Unit testing a Polymer web app
A project should contain a number of automated tests that can be run after every code change to ensure that the previous functionality still works. Dart's unittest
framework is the best tool for the job, and the Dart website has some excellent articles to get you started. However, testing Polymer web applications is a lot trickier because of the way Polymer works, as it hides HTML in shadow DOM and also because it works in an asynchronous fashion, independent of the testing code.
Getting ready
We will create some tests in the ClickCounter example (the standard web application template using the polymer
library). You can find the code in the polymer1
app. We include the unittest
library in the pubspec.yaml
file, and create a test
folder.
How to do it...
In the test
folder, we create a test_polymer1.html
page; a web page that loads the Polymer component required to test this functionality. The following is the minimum content required for the component:
<head> <title>test_polymer1</title> <link rel="import" href="../web/polymer1.html"> <script type="application/dart" src="test_polymer1.dart"></script> </head> test_polymer1.dart contains the test script: import 'package:unittest/unittest.dart'; import 'dart:html'; import 'package:polymer/polymer.dart'; import '../web/clickcounter.dart'; main() { initPolymer();
var _el;
setUp((){
_el = createElement('<click-counter>Click counter test</click-counter>');
document.body.append(_el); }); tearDown((){ _el.remove(); }); // tests: test('shadowroot elements are created', (){ expect(querySelector('click-counter').children, isNotNull); expect(querySelector('click-counter').shadowRoot.text, isNotNull); }); test('initial text ok', (){ expect(querySelector('click-counter').shadowRoot.text.contains('click count: 0'), isTrue); }); // test button with text Transaction: test('button with id click exists', (){ var button = querySelector('click-counter').shadowRoot.querySelector('#click'); expect(button, isNotNull); }); test('button click() increments counter', (){ ButtonElement button = querySelector('click-counter').shadowRoot.querySelector('#click'); button.click(); button.click(); button.click(); // get counter value: ClickCounter cc = querySelector('click-counter'); expect(cc.count, 3); // after 3 clicks }); } createElement(String html) => new Element.html(html, treeSanitizer: new NullTreeSanitizer()); class NullTreeSanitizer implements NodeTreeSanitizer { void sanitizeTree(node) {} }
When the script is run, the following output appears:
unittest-suite-wait-for-done
PASS: shadowroot elements are created
PASS: initial text ok
PASS: button with id click exists
PASS: button click() increments counter
All 4 tests passed.
unittest-suite-success
How it works...
The test web page loads the Polymer component, and the test script loads the unittest
and polymer
packages and component classes (clickcounter.dart
). In main()
, we load the polymer
package with initPolymer()
; in setup()
, we use a helper method createElement()
, with an HTML string containing the polymer
tag <clickcounter>
as argument to instantiate the Polymer component and add it to the page. This was done in order to avoid the default HTML sanitization createElement()
, which uses a null sanitizer instead of the built-in sanitizer (refer to Chapter 5, Handling Web Applications, for more information on this topic). Then, we start testing, for example:
expect(querySelector('click-counter').children, isNotNull);
so that the Polymer component tree is createdvar button = querySelector('click-counter').shadowRoot.querySelector('#click'); expect(button, isNotNull);
so that the button with the ID'click'
is createdexpect(querySelector('click-counter').shadowRoot.text.contains('click count: 0'), isTrue);
so that the text initially displayed is'click count: 0'
.
Notice how we have to dig into shadowRoot
of the Polymer component to get this information as follows:
- Verify that after clicking the button three times invoked by
button.click()
, our count property has the value 3:ClickCounter cc = querySelector('click-counter'); expect(cc.count, 3);
See also
- To discover more information about the Dart
unittest
library, refer to the book Learning Dart, Ivo Balbaert, Dzenan Ridjanovic, Packt Publishing, or the excellent articles at background knowledge and information on how to extend the use of Dart Unittest in your own work.