Sunday, April 5, 2015

The Debugger and Breakpoints with web-component-tester


At this point, I am just looking for an excuse not to use web-component-tester. And so far, I have not found one. The web-component-tester (WCT) testing library for Polymer elements seems quite solid. It eliminates a lot of the overhead required for Polymer testing without sacrificing much in the way of configurability or extendability.

But, thanks to a question from Jim Simon in response to last night's post, I might just have the excuse for which I have been looking.

OK, in reality, I am not looking for a reason to dislike WCT. I am simply casting a very critical eye at it before I switch testing solutions in Patterns in Polymer to use it. Until Jim's question, I had yet to find a reasonable objection. Until Jim's question...

So here it is, how do you debug tests in WCT? With Karma, which is the current Patterns in Polymer recommendation for JavaScript, you click the Debug button on the page. Setting breakpoints and using debugger statements work as expected.

I would be satisfied that debugging was solid in WCT if I could simply get a debugger statement to work. So I add one to my Page Objects test from a couple of nights ago:
  describe('adding a whole topping', function(){
    beforeEach(function(done){
      xPizza.addWholeTopping('green peppers', done);
    });

    it('updates the pizza state accordingly', function(){
      var with_toppings = JSON.stringify({
        firstHalfToppings: [],
        secondHalfToppings: [],
        wholeToppings: ['green peppers']
      });

      debugger

      assert.equal(
        xPizza.currentPizzaStateDisplay(),
        with_toppings
      );
    });
  });
This seems a useful point to set a debugger statement. The element would have been established by virtue of a fixture and WCT's baked-in wait for Polymer.onReady. In this case, I use the page object's addWholeTopping() method to interact with the element, wait for changes to be done, then wait for the debugger statement to kick-in.

This will not work with my file-watcher setup because debugger statements, like breakpoints, only work if the JavaScript console is open in Chrome. Without that, my tests merrily continue to pass:
Running "wct-test:local" (wct-test) task
Starting Selenium server for local browsers
Selenium server running on port 52328
Web server running on port 40424 and serving from /home/chris/repos/polymer-book/play/web-component-tester
chrome 41                Beginning tests via http://localhost:40424/js/test/index.html?cli_browser_id=0
chrome 41                ✓ index.html »  » can add toppings to the whole pizza
chrome 41                ✓ index.html »  » defaults » has no toppings anywhere
chrome 41                ✓ index.html »  » adding a whole topping » updates the pizza state accordingly
chrome 41                ✓ simple_tests_01.html »  (1) » starts with no toppings
chrome 41                ✓ simple_tests_02.html »  (2) » starts with no toppings
chrome 41                Tests passed
Test run ended with great success

chrome 41 (5/0/0)                     

Done, without errors.
My first thought at this point is that I need to make use of WCT's persistent option:
$ wct --help

Usage: wct [options]

Options:
   -p, --persistent        Keep browsers active (refresh to rerun tests).
   --root                  The root directory to serve tests from.
   --plugin NAME           Plugins that should be loaded.
   --skip-plugin NAME      Configured plugins that should _not_ be loaded.
   --expanded              Log a status line for each test run
...
I give that a try:
$ wct -p
Starting Selenium server for local browsers
Selenium server running on port 43088
Web server running on port 56994 and serving from /home/chris/repos/polymer-book/play/web-component-tester
chrome 41                Beginning tests via http://localhost:56994/js/test/index.html?cli_browser_id=0
chrome 41                ✓ index.html » <x-pizza> » can add toppings to the whole pizza
chrome 41                ✓ index.html » <x-pizza> » defaults » has no toppings anywhere
chrome 41                ✓ index.html » <x-pizza> » adding a whole topping » updates the pizza state accordingly
chrome 41                ✓ simple_tests_01.html » <x-pizza> (1) » starts with no toppings
chrome 41                ✓ simple_tests_02.html » <x-pizza> (2) » starts with no toppings
...
The tests continue to pass (and not break for debugging). But the test browser remains. I open the JavaScript console:



Then I reload the page, and... the dang page closes the JavaScript console before re-running the tests. My guess is that WCT is doing this because this browser session is still attached to the backend WCT session. When I reload the browser, the WCT session again reports:
...
chrome 41                Beginning tests via http://localhost:56994/js/test/index.html?cli_browser_id=0
chrome 41                ✓ index.html » <x-pizza> » can add toppings to the whole pizza
chrome 41                ✓ index.html » <x-pizza> » defaults » has no toppings anywhere
chrome 41                ✓ index.html » <x-pizza> » adding a whole topping » updates the pizza state accordingly
chrome 41                ✓ simple_tests_01.html » <x-pizza> (1) » starts with no toppings
chrome 41                ✓ simple_tests_02.html » <x-pizza> (2) » starts with no toppings
But what would happen if I start a new window at the same URL, but without that cli_browser_id query string parameter?

There is an easy way to find the answer to that. I open a new Chrome window, open its JavaScript console, and point it to my current WCT server (currently for me at http://localhost:56994/js/test/index.html). With that, I see:



Yay! Debugging.

I can do anything that I normally would in there: look at local variables, check the call stack, step through execution, even interact with objects in the console:



This works just as well with debugger statements in the actual Polymer code and with breakpoints set in the Sources tab. This seems exactly what I need (and hopefully what Jim needs as well).

I think that I will continue to run a file watcher WCT instance during the course of normal development. When things go really wrong, I will stop the WCT instance and bring up a --persistent instance of WCT and a completely separate Chrome window in which I can do the debugging thing. Once I resolve the problem, I can close the persistent WCT session and browser windows, then return to my regularly scheduled file watcher session.

I am rapidly running out of reasons to dislike WCT. But there is always hope for tomorrow.


Day #20

2 comments:

  1. Glad you found a solution! I didnt elaborate much last night, but my team and I have been using debugger statements as well. We also run the tests in persistent mode, wait for the first run to finish, and then open up the debugger. We found that clicking on the specific test that failed to rerun it (instead of refreshing the page) will keep the dev tools window open and stop correctly on the debugger. I was just hoping that maybe you'd found a better solution :-p. One thing I haven't tried is using Webstorm's client side debugging capabilities and setting breakpoints in there. Maybe I'll give that a try tomorrow at work. Thanks for the post and mention though!

    ReplyDelete
  2. Hey, is there a better way to do this now?

    ReplyDelete