I continue my experiments using Protractor to test Polymer elements. I do not expect to get this working completely. Instead I am trying to understand what end-to-end testing of a Polymer element might look like. I also hope to understand where the gaps still exist between current WebDriver tools and real end-to-end testing.
Mostly, I am just having fun.
Tonight's fun takes the form of trying to convert last night's unit test into a real e2e Polymer test. The test that I wound up with is almost pretty:
it('updates value when internal state changes', function() {
var selector = 'x-pizza';
browser.executeScript(
'var el = document.querySelector("' + selector + '"); ' +
'el.model.firstHalfToppings.push("pepperoni"); '
);
expect($(selector).getAttribute('value')).
toMatch('pepperoni');
});
A beforeEach()
block loads the page containing the element to be tested: the <x-pizza>
pizza building Polymer element. This test then adds pepperoni to the first half and then expects that the element's value
property is updated to include pepperoni in it.This is not a real unit test, in that it does not test a single method of the Polymer element. It is also not a true e2e test because of the
executeScript()
call that manipulates the innards of the Polymer element. This is something in between. It is a functional test (it tests functionality across concerns), but it still lies closer to unit test than e2e, which is what Protractor wants to do.The version of the
<x-pizza>
element being tested here looks like:(I switched to a Material Design later)
If those drop downs were not part of
<x-pizza>
, I might tell protractor to interact with them by replacing the executeScript()
work-under-the-covers with something like:
// browser.executeScript(
// 'var el = document.querySelector("' + selector + '"); ' +
// 'el.model.firstHalfToppings.push("pepperoni"); '
// );
$('#firstHalf options').
then(function(options){
options[1].click();
});
$('#firstHalf button').
then(function(button){
button.click();
});
But, since WebDriver (and hence Protractor) does not support the shadow DOM, I get an error like: 1) <x-pizza> updates value when internal state changes
Message:
NoSuchElementError: No element found using locator: By.cssSelector("#firstHalf options")
So what is a fellow to do? Well, hopefully recreate this with executeScript: browser.executeScript(
'var el = document.querySelector("' + selector + '"); ' +
'var options = el.shadowRoot.querySelectorAll("#firstHalf option"); ' +
'options[1].selected = true; ' +
'button = el.shadowRoot.querySelector("#firstHalf button"); ' +
'button.click(); '
);
Ick. This code still finds the <x-pizza>
element, but now is selects the second option (pepperoni) and clicks the “Add Topping” button.I suppose that is not too horrible, but I sure hate all that coding inside JavaScript strings. Especially since it does not even work:
1) <x-pizza> updates value when internal state changes
Message:
Expected '
' to match 'pepperoni'.
If I add a browser.wait(30*1000)
(waiting 30 seconds is my preferred debugging methodology in Protractor), I can see that this code would seem to do what I expect. The pepperoni option is selected. The first half topping button is clicked. But I still get a failure. More importantly, I get a code failure in the JavaScript console of the waiting browser. The problem occurs in the code that adds unknown toppings. I will fix that another day (my tests found a bug!). For now, I need to figure out why this is trying to add an unknown topping when I clearly added pepperoni. Thankfully, I have already solved this. Polymer needs a change event to be triggered before it will update its bound values:
browser.executeScript(
'var el = document.querySelector("' + selector + '"); ' +
'var options = el.shadowRoot.querySelectorAll("#firstHalf option"); ' +
'options[1].selected = true; ' +
'' +
'var e = document.createEvent("Event"); ' +
'e.initEvent("change", true, true); ' +
'options[1].dispatchEvent(e); ' +
'' +
'button = el.shadowRoot.querySelector("#firstHalf button"); ' +
'button.click(); '
);
That actually gets my test working:$ protractor conf.js Using the selenium server at http://localhost:4444/wd/hub [launcher] Running 1 instances of WebDriver ... Finished in 1.363 seconds 3 tests, 6 assertions, 0 failuresThat is a good stopping point for tonight. I have learned that it is possible to write actual end-to-end tests for Polymer. I also learned that it is pretty ugly doing so inside Protractor
browser.executeScript()
blocks. Not only is it ugly, but there is definite gap between Protractor/WebDriver and a Polymer e2e testing tool. The lack of access to the shadow DOM is one problem, but now I see that Polymer events are also tricky. Those problems aside, I also see definite advantages to e2e testing of Polymer elements—the most obvious being the bug that I found tonight by interacting with my Polymer element like a user would. And yes, I am still having fun.
Day #28
No comments:
Post a Comment