Thursday, April 2, 2015

Organizing web-component-tester Test Suites


I like web-component-tester. I just don't know if I like like it.

Actually, I probably do, but I am unsure if I like it enough to go back and rewrite testing chapters in Patterns in Polymer. Certainly I would prefer the option with less work, but not at the expense of an inferior solution. So tonight, I press on in my investigation.

Having gotten my Grunt watcher configuration just right, tonight I experiment a little with the test organization options that are supported by web-component-tester (WCT). I start by simply copying my existing test into separate JS files. The existing test is contained in my project's test/index.html page:
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <script src="../bower_components/webcomponentsjs/webcomponents.min.js"></script>
  <script src="../../web-component-tester/browser.js"></script>
  <link rel="import" href="../elements/x-pizza.html">
</head>
<body>
  <x-pizza id="fixture"></x-pizza>
  <script>
    suite('<x-pizza>', function() {
      test('starts with no toppings', function() {
        assert.equal(
          document.getElementById('fixture').pizzaState,
          '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":[]}'
        );
      });
    });
  </script>
</body>
</html>
To load tests, I replace the test suite above with the WCT.loadSuites() method:
<body>
  <x-pizza id="fixture"></x-pizza>
  <script>
    WCT.loadSuites([
      'simple_tests_01.js',
      'simple_tests_02.js',
    ]);
  </script>
</body>
Here, I load two suites which, as the names imply, are very simple. I also retain the <x-pizza> fixture in place in this test/index.html entry point (this may be a mistake, but I leave it for now). The simple tests copy the original test which verifies the initial state of the element:
suite('<x-pizza>', function() {
  test('starts with no toppings', function() {
    assert.equal(
      document.getElementById('fixture').pizzaState,
      '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":[]}'
    );
  });
});
With that, my WCT tests still pass. Thanks to my duplicated test, I now have two passing tests in each of the browsers for which WCT is configured:
Running "wct-test:local" (wct-test) task
Starting Selenium server for local browsers
Selenium server running on port 48572
Web server running on port 48270 and serving from /home/chris/repos/polymer-book/play/web-component-tester
chrome 41                Beginning tests via http://localhost:48270/js/test/index.html?cli_browser_id=0
chrome 41                Tests passed
firefox 37               Beginning tests via http://localhost:48270/js/test/index.html?cli_browser_id=1
firefox 37               Tests passed
Test run ended with great success

chrome 41 (2/0/0)                       firefox 37 (2/0/0)                    

Done, without errors.
I am unsure of the best practice for fixture elements. I have the feeling that once a test alters the state, subsequent test suites will see the change instead of the initial, default state. To test that theory, I add a new test that adds a topping to the <x-pizza> element:
<body>
  <x-pizza id="fixture"></x-pizza>
  <script>
    WCT.loadSuites([
      'simple_tests_01.js',
      'adding_toppings.js',
      'simple_tests_02.js',
    ]);
  </script>
</body>
The test itself looks something like:
suite('<x-pizza>', function() {
  var el;

  setup(function(done){
    el = document.getElementById('fixture');
    // Crazy JS to select an item from a drop-down and trigger a
    // change here...

    el.async(done);
  });

  test('can add toppings to the whole pizza', function() {
    assert.equal(
      el.pizzaState,
      '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":["pepperoni"]}'
    );
  });
});
The craziness that updates the element is best left for another day. For now, please take it on faith that the elided code makes a change to the <x-pizza> element. And indeed it does since this test passes. Unfortunately, as I feared, it changes the <x-pizza> element for later tests because the last simple test is now failing due to the presence of pepperoni:
...
firefox 37               ✖ index.html » <x-pizza> » starts with no toppings

  expected '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":["pepperoni"]}' to equal '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":[]}'

firefox 37               Tests failed: 1 failed tests
Test run ended in failure: 1 failed tests

chrome 41 (2/0/1)                       firefox 37 (2/0/1)      
So, to isolate fixtures, it seems that external test suites need to be HTML suites. I switch simple_test_02.js to simple_test_02.html in the test/index.html entry point:
<body>
  <x-pizza id="fixture"></x-pizza>
  <script>
    WCT.loadSuites([
      'simple_tests_01.js',
      'adding_toppings.js',
      'simple_tests_02.html',
    ]);
  </script>
</body>
And in that HTML suite, I start a completely new WCT test context for my <x-pizza> element. I load WCT, Polymer and import the element itself. Finally I write the test:
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <script src="../bower_components/webcomponentsjs/webcomponents.min.js"></script>
  <script src="../../web-component-tester/browser.js"></script>
  <link rel="import" href="../elements/x-pizza.html">
</head>
<body>
<x-pizza id="fixture"></x-pizza>
<script>
suite('<x-pizza>', function() {
  test('starts with no toppings', function() {
    assert.equal(
      document.getElementById('fixture').pizzaState,
      '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":[]}'
    );
  });
});
</script>
</body>
</html>
With that, I have all of my tests passing again:
>> File "test/simple_tests_02.html" changed.
Running "notify_hooks" task

Running "wct-test:local" (wct-test) task
Starting Selenium server for local browsers
Selenium server running on port 34160
Web server running on port 54777 and serving from /home/chris/repos/polymer-book/play/web-component-tester
chrome 41                Beginning tests via http://localhost:54777/js/test/index.html?cli_browser_id=0
chrome 41                Tests passed
firefox 37               Beginning tests via http://localhost:54777/js/test/index.html?cli_browser_id=1
firefox 37               Tests passed
Test run ended with great success

chrome 41 (3/0/0)                       firefox 37 (3/0/0)                    

Done, without errors.
It seems safe to say that, if tests rely on fixture data like this, then HTML suites are the way to go. This is perfectly reasonable and not entirely unexpected. Still, it might improve maintainability if WCT can come up with a way to not duplicate the <head> section of each HTML suite. That minor quibble aside, test organization in WCT seems quite easy.


Day #17

No comments:

Post a Comment