Monday, December 22, 2014

Fixing Polymer Bugs with Protractor


Today, I hope to get a feel for fixing bugs in Polymer elements by driving the fixes with Protractor.

A while back, I noticed a problem in my <x-pizza> pizza building element:



The problem occurs when adding non-standard toppings, which results in a JavaScript error. I actually noticed the problem while writing Protractor tests, so if I can fix it with another Protractor test, it would make for nice symmetry.

My Protractor test for adding valid toppings looks like:
describe('<x-pizza>', function(){
  beforeEach(function(){
    browser.get('http://localhost:8000');
  });
  it('updates value when internal state changes', function() {
    new XPizzaComponent().
      addFirstHalfTopping('pepperoni');

    expect($('x-pizza').getAttribute('value')).
      toMatch('pepperoni');
  });
});
That is nice and compact thanks to the Page Objects pattern—the XPizzaComponent in this case.

The page object makes it easy to write a new test that breaks things:
  it('adds "unknown" topping when invalid item selected', function() {
    new XPizzaComponent().
      addFirstHalfTopping('');

    expect($('x-pizza').getAttribute('value')).
      toMatch('unknown');
  });
Instead of choosing an option from the list, this should select the first item on the drop down list, which is blank. When I run the Protractor test, I get a failure, but not an error:
  1) <x-pizza> adds "unknown" topping when invalid item selected
   Message:
     Expected '

' to match 'unknown'.
   Stacktrace:
     Error: Failed expectation
    at [object Object].<anonymous> (/home/chris/repos/polymer-book/play/protractor/tests/XPizzaSpec.js:31:7)
If I add a browser.pause():
  it('adds "unknown" topping when invalid item selected', function() {
    new XPizzaComponent().
      addFirstHalfTopping('');

    browser.pause();

    expect($('x-pizza').getAttribute('value')).
      toMatch('unknown');
  });
Then I can see the error in the WebDriver console:



I find that I can also use this very verbose code to print out the console:
  it('adds "unknown" topping when invalid item selected', function() {
    new XPizzaComponent().
      addFirstHalfTopping('');

    browser.manage().logs().get('browser').then(function(browserLog) {
      console.log('log: ' + require('util').inspect(browserLog));
    });

    expect($('x-pizza').getAttribute('value')).
      toMatch('unknown');
  });
Regardless of how I find the error, it is fairly easy to fix it. The console in both cases reports the error to be at:
ReferenceError: _svgUnknown is not defined
    at x-pizza.Polymer._toppingMaker (http://localhost:8000/elements/x_pizza.js:94:12)
Looking at the _toppingMaker() method, I see right away that, unlike the SVG makers for know elements, I am trying to call _svgUnknown() as a function instead of a method:
  _toppingMaker: function(topping) {
    if (topping == 'pepperoni') return this._svgPepperoni;
    if (topping == 'sausage') return this._svgSausage;
    if (topping == 'green peppers') return this._svgGreenPepper;
    return _svgUnknown;
  },
And, indeed, converting that to a method resolves the bug:
  _toppingMaker: function(topping) {
    if (topping == 'pepperoni') return this._svgPepperoni;
    if (topping == 'sausage') return this._svgSausage;
    if (topping == 'green peppers') return this._svgGreenPepper;
    return this._svgUnknown;
  },
Just as importantly, I know have an e2e test that exercises this code, ensuring that I do not make a dumb mistake again:
<x-pizza>
  has a shadow DOM - pass
  updates value when internal state changes - pass
  syncs <input> values - pass
  adds "unknown" topping when invalid item selected - pass


Finished in 1.938 seconds
4 tests, 4 assertions, 0 failures
This might seem like a small thing for all that test code, but if I made that mistake once, I can make it again. Unless I have a test.


Day #32


No comments:

Post a Comment