 Hey, guys. How's it going? So this is Testing with Polymer, featuring Web Component Tester and friends. We're going to talk about testing how the Polymer team tests what we're going to talk about how the Polymer team tests the web platform features of the future. By way of introduction, I'm Chris Joel. I'm a software engineer and contributor to the catalog of Polymer elements. You can also find me on GitHub at RoboDynamo, sorry, on Twitter at RoboDynamo and on GitHub at Cdata. So test-driven development and behavior-driven development, these things are really important when it comes to testing. We're not going to be covering these in detail today. We have a baseline expectation that you guys are familiar with this stuff. Expectation frameworks, assertion frameworks, very important. I'm going to assume that you have at least a passing familiarity. Mox stubs and spies, these are kind of an advanced testing topic, but I'm also going to gloss over them and assume that you've seen them before. And we're definitely not going to talk about why testing is important. We all know the superhero who thinks that he doesn't need to test his code. We all know better. Don't be that person. So how many of you guys think testing is hard, or maybe it could be easier, like could stand to be improved because I see a show of hands? Yeah, I've heard a little bit of FUD that Web Components in particular are kind of tricky to test, not easy to reason about. I'm happy to be the one to assure you that not only are they easy to test, Web Components can make testing the whole experience of testing just much better. And the Polymer team has built some great tools to make the whole experience even better than that. So we're going to talk a ton about testing Web Components. I want to set some baseline ground rules. There are a lot of details that go into really good test suites, and in particular, I want to talk about three qualities that I value in my test suites. These aren't the only things I like, but they're pretty high on the list. A good test suite should be order independent. If desired, I should be able to run my tests in random order. And in fact, as some of you probably know, most test suites out there support this feature. You can just run your tests in random order. Test suites should be repeatable with consistent results. If I run a test once and it passes, it should pass if I run it again immediately afterwards. Of course, there's no avoiding the occasional hyzen bug, but for the most part, you want your tests to be consistently repeatable. And third, you really want your tests to be dry. Don't repeat yourself. Test suites can grow in unexpected ways, so we need to keep repetition to a minimum. Every time you copy and paste something while filling out your test suite, it should be considered a code smell. So I mentioned that the Polymer team has built some useful tools for making testing even more delightful. The tool at the center of our testing world is Web Component Tester. You guys have probably seen this if you've gone through some of the code labs. We call it WCT for short on the Polymer team. WCT is a batteries included solution for rapidly building out robust test suites for web components. What do I mean by batteries included? Mocha provides a baseline for BDD and TDD styles. Chai is included. This provides expectations and assertions. Also, Synon.js is on board, enabling easy mocks, stubs, and spies. Do you want to run your test suite in multiple browsers at once? Of course you do, you're web developers. Selenium is built right into Web Component Tester. WCT can drive multiple browsers with just one command. We have general Selenium support built in, so we also added support for Sauce Labs. Sauce Labs is basically Selenium in the cloud. So you can run your local tests in virtually every browser configuration. Just configure WCT with your Sauce Labs API and you're good to go. Some of WCT's own features are built using a published plugin API. So you can teach WCT a new trick if you want. What does testing web components really look like with WCT? Well, writing tests for WCT is as simple as creating an HTML document. First, include the WCT runtime in your head and import the element you want to test. For this talk, I'm going to be testing a Polymer element called PaperButton. You guys are probably familiar with this one. As you can see, I've imported PaperButton.html in my head. We want to test the element in its natural habitat, the HTML document. So, next, I add PaperButton into the body of the document to use as a test fixture for my test. And below the button, I begin a script tag where I start a Mocha TDD-style test suite. Here, my test suite is just going to be called PaperButton. Then, I fill out the suite and add a test to kick things off. This test isn't very robust. It's really just pulling the button out of the document and testing that it's OK. But it's a good start. Putting it all together, we have a nice example of a basic test in WCT. Note that we didn't have to do any extra work to get TDD or expectations. It's all included. And if the syntax looks familiar to you, it's because we're using the tools that you probably already use. So now that we have our test suite, I want to try it out. At first, I'm going to spin up an HTTP server and open the test HTML in my browser. Just copy past the URL. It's looking good. Since web components are just HTML, it should be really easy to run the test in a web browser. And it is. In the real world, PaperButton needs to work in as many browsers as I can throw at it. This is where WCT really starts to shine. Watch what happens when I run my test right through WCT. WCT finds all of the browsers on my system and runs the test suite against them. So far, Chrome Stable, Canary, Safari, Firefox, they're all looking good. Here's our button test suite again. There aren't many useful tests in here yet. I want to add some tests that test real features in PaperButton. First, I need a feature to add tests for. Every PaperButton can be given a toggles attribute. This attribute makes PaperButton toggle between on and off each time you click it. Here's the normal button. And here's the toggle button. Every time I click it, it toggles between on and off. This causes a property on the button, called active, to be set to true or false. OK, so I know what feature I want to test in the button. First, I write out my test. The toggle button activates when clicked. Now, I select my PaperButton from the document and assign it to a local variable. Here, I'm just using query selector to pull the button out of the document. After I run this code, button will be assigned to the button in my document. And here's the meat of the test. I set toggle's property to true, which makes this button a toggle button. Then I click the button and activate it. And finally, I checked that the button is activated by expecting the active property to be true. Here, I'm just saying expect button.active to be equal to true. Let's put it all together. Pull the button out of the document, make the effects on the button, and then set my expectations. This looks like a pretty solid test. But what about the normal non-toggle button? We should probably test that a normal button behaves correctly as well. This turns out to be a super easy test to write. The test is very similar to the one we just wrote. The main differences are that we don't set the button to toggle, and we expect that the active property is false. So before we go any further, I have to point out that a new problem has come up. Now, you may already know this, but at Google, engineers have a tradition called testing on the toilet. So trust me when I say this, we're experts on leaky state. State leak is a common accident in test suites, and we just had that accident. Let's look at the new tests all together. I know this is a lot of code to look at in one slide, but can you find the leaky state here? I'll give you a second to check it out. Raise your hand if you find it. The value of toggles is set in the first test. It doesn't get unset before the second test. This means our second test will fail if it runs after the first one. These tests are not order independent. The order in which state leaks makes a big difference. The tests are not runnable in isolation either. They depend on leaky state, and will often fail without it. Leaky state can change across our test runs. If I did run these tests in random order, I might get a failure, or I might get a success. Who knows? The worst part about all of this is that we did something that seemed right, but it didn't work right. After all, test fixtures in HTML represent global state in our test suite, and the internal state of each element is difficult to reset hygienically. Well, thankfully, there's an element for that. Web components are here to help. As it turns out, there is a custom element that enables us to address this problem. For testing polymer elements, we created the test fixture element. This element packages a sane approach to declarative HTML fixtures. In order to use it, first, I create a test fixture element and give it an appropriate ID. I'm just going to call this one paper button, because I'm testing paper button. Next, I'm going to add a template to my test fixture element. The contents of the template are going to be the HTML I want to test, so I'm just going to put a paper button in here. Bringing it all together, I have a template that gives context to my paper button test fixture. Using the test fixture couldn't be easier. I'm going to create a setup function for my test suite to help keep things dry. In setup, I call a new Mocha helper called Fixture. The fixture named paper button then stamps its template into the DOM and returns the contents. After this code is run, button will be assigned to a newly created paper button. Here it is with the rest of the test suite. Our test fixture will handle creating a new button at the beginning of each test. Then, after each test, the test fixture will automatically tear down the HTML by removing it from the DOM. As our test suite grows, we can add as many new test fixtures as we want. Here, I've added a new test fixture for our toggle button. This is great because it means when I want to test toggle button features, I can just stamp the toggle button test fixture. Different test fixtures can be created for all kinds of scenarios. And the best part is, since you control when the test fixture is stamped, you can wrap side effects like network requests or timers. So far, so good. We've covered some very useful tools. But there's still some other nice toys that we've been working on to help make testing Polymer an even more delightful experience. I want to cover some of those with you briefly so you guys can stay on the horizon of testing Polymer. I already told you about the new Fixture Mocha helper. We've also created another Mocha helper called stub. This helper enables the tester to replace partial element implementation with custom methods. Here, I'm replacing the click method on paper button with a custom implementation. The new implementation logs to the console instead of the default behavior. This is great because now I can capture side effects from click being called on the button. For the duration of any test that uses this setup, the custom implementation will replace the original implementation. You don't even have to use this directly on a button reference. You can just say, for all paper buttons, I'm going to stub this implementation. And the best part is, the implementation is automatically reset after each test. This uses synon under the hood. And so those of you who are familiar with synon will be nodding your heads. Stub methods are just synon spies, which means during my test, I can run expectations on things that happen to these methods. Here, I'm checking things like how many times was click called or what arguments were passed to click or what order were different methods that I've stubbed called in. We've also introduced a replace Mocha helper. This helper replaces matching element children in all other elements for the duration of the test. So that's a little bit to swallow. So let me walk you through what that means. It's very easy to use. First, I call replace with a tag name that you wish to replace. And then I also tell it what alternative tag name I want to use. How is this useful? Here I have two representations of an element I'm working on called xCustomElement. The first is the actual template of the element. It has a paper button inside. So every time an xCustomElement gets created, paper button will be created as well. What I want is to remove paper button from the experience so that I don't get any side effects. So I've replaced paper button with fake paper button. The effective template when this element gets created is going to be the one below where a fake paper button is created. It still gets the same attributes and the same content, but it's effectively a fully stubbed out element. And just like stub and just like fixture, all of the changes are reverted at the end of each test. Last but not least, we have a topic that I am particularly excited about. Polymer element authors consider accessibility issues to be top priority bugs. Testing elements for accessibility reflections has become a major area of exploration for us. Alice Boxhall and Laura Palermo will be giving a great talk on accessibility later today so definitely check it out. Alice in particular has done a tremendous amount of work on a Chrome extension called accessibility developer tools. You should also check that out if you haven't seen it. Everybody should have this installed. Some of you may have heard of it. Here's a screenshot of what it looks like in action. For those of you that haven't, one of its major features is that it'll allow you to do an accessibility audit on any arbitrary page of your site. Here I have done an audit of a major American news outlet. It looks like they have some room for improvement. Wouldn't it be great if they could just add this to their web component test suite? Now they can. Dan Friedman has done a great job and integrated this directly into web component tester. You can use Accessibility Suite against any test fixture in your suite. It'll cause a suite of 26 audits to be run against your fixtured DOM. Accessibility Suite will automatically filter out audits that are not relevant to your DOM, and failed audits will cause your test suite to fail. Accessibility testing is a very tricky thing to automate correctly, and the accessibility developer tools are certainly not exhaustive. We're exploring more strategies in this area, and there's definitely more to come. So today I showed you that web components are not, the web components testing is not hard. In fact, web components can make the whole testing experience much easier and bring new advantages to your test suite. And you learned about a bunch of exciting tools that the Polymer team is working on to make testing web components and Polymer elements even better. Thanks for coming to the summit today and for taking some time to learn a little bit more about testing Polymer and web components.