The Polymer library is in maintenance mode. For new development, we recommend Lit.

This guide shows you the basics of using Polymer CLI to run unit tests, and how to accomplish various tasks and scenarios using the Web Component Tester library (the underlying library that powers Polymer CLI's testing tools).

Update your tools for 3.0. For testing with 3.0, make sure you have the next version of the Polymer CLI (npm install -g polymer-cli).

Polymer CLI is an all-in-one command-line interface that covers the vast majority of Polymer development tasks, including unit testing. The underlying library that powers Polymer CLI's unit testing tools is called Web Component Tester.

Web Component Tester is an end-to-end testing environment built by the Polymer team. It enables you to test your elements locally, against all of your installed browsers, or remotely, via Sauce Labs. It is built on top of popular third-party tools, including:

  • Mocha for a test framework, complete with support for BDD and TDD.
  • Chai for more assertion types that can be used with your Mocha tests.
  • Sinon for spies, stubs, and mocks.
  • Selenium for running tests against multiple browsers.
  • Accessibility Developer Tools for accessibility audits.

For demonstration purposes, this guide shows you how to install Polymer CLI and initialize an element project. You'll then use this project to learn how to add and run unit tests.

  1. Install Polymer CLI. Follow the directions in Install Polymer CLI to get started.

  2. Create an element project. This guide assumes that your element project directory and your element are both named my-el.

  3. cd to the base directory of your project.

  4. Run ls.

    You'll see that your element project contains a directory called test. This is where all of your unit tests should be stored.

    When you run polymer test, Web Component Tester automatically searches for a test directory and runs any tests it finds in there. If you use another directory name, you'll need to specify it when you run polymer test.

  5. Open test/my-el_test.html to see an example of a basic unit test.

  6. Run the test.

    polymer test

    Web Component Tester automatically finds all of the browsers on your system and runs your tests against each one. To run your tests against a single browser, use the -l (or --local) argument:

    polymer test -l chrome

If you receive errors about testing on Safari, see Set up testing on Safari.

You can also run your tests in the browser. This allows you to use the browser's DevTools to inspect or debug your unit tests.

For example, using Polymer CLI and the example element project created in Quick start above, start your server:

polymer serve

Then, to run the basic my-el_test.html unit test, open a web browser and go to the following URL:


Now that you've got the basics down of using Polymer CLI to run tests, it's time to start creating them.

This section of the doc shows you how to accomplish various tasks or scenarios while implementing your unit tests.

To create an asynchronous test, pass done as an argument to the test function and then call done() when the test is complete. The done argument is a signal to Mocha that the test is asynchronous. When Mocha runs the test, it waits until the test code invokes the done() callback. If the done() callback isn't invoked, the test eventually times out and Mocha reports the test as a failure.


class MyEl extends PolymerElement {
  fireEvent() {
    this.dispatchEvent(new CustomEvent('test-event', {detail: 'tested!'}));


test('fires an event', function(done) {
  myEl.addEventListener('test-event', function(event) {
    assert.equal(event.detail, 'tested!');

Test fixtures enable you to define a template of content and copy a clean, new instance of that content into each test suite. Use test fixtures to minimize the amount of shared state between test suites.

To use a test fixture:

  • Define the test fixture template and give it an ID.
  • Define a variable in your test script to reference the template.
  • Instantiate a new instance of the fixture in your setup() method.


<test-fixture id="my-el-fixture">
    <my-el prop1="test value">

  suite('<my-el>', function() {
    var myEl;
    setup(function() {
      myEl = fixture('my-el-fixture');
    test('sets the "prop1" property from markup', function() {
      assert.equal(myEl.prop1, 'test value');

Stubs enable you to replace default implementations with custom methods. This is useful for catching side effects.


setup(function() {
  stub('paper-button', {
    click: function() {
      console.log(' called');

You don't have to use stubs directly on individual elements. You can override the implementation for all elements of a given type.

Use stub elements to test elements in isolation. For example, if one of your tests depends on another element to return data, rather than importing the other (possibly unstable) element into your tests, you can implement a stub of the other element that always returns consistent data.

Use replace() to create stub elements.


setup(function() {

For example, using the sample replace() above and the element below:


// import statements go here

class MyEl extends PolymerElement {
  static get template() {
    return html`<paper-button id="pb">button</paper-button>`;

customElements.define('my-el', MyEl);

At test runtime, the content template would be stamped out as:

<fake-paper-button id="pb">button</fake-paper-button>

The attributes and content of the element are preserved, but the tag is replaced with the specified stub tag.

Because the method is called within setup(), all of the changes are reverted at the end of each test.

Web Component Tester includes Sinon, which enables you to mock XHR requests and create fake servers.

Below is an example of a simple XHR unit test suite for <iron-ajax>. Check out Sinon's documentation for more in-depth examples.

<!-- create test fixture template -->
<test-fixture id="simple-get">
    <iron-ajax url="/responds_to_get_with_json"></iron-ajax>
  suite('<iron-ajax>', function() {
    var ajax;
    var request;
    var server;
    var responseHeaders = {
      json: { 'Content-Type': 'application/json' }
    setup(function() {
      server = sinon.fakeServer.create();
        /\/responds_to_get_with_json.*/, [
    teardown(function() {
    suite('when making simple GET requests for JSON', function() {
      setup(function() {
        // get fresh instance of iron-ajax before every test
        ajax = fixture('simple-get');
      test('has sane defaults that love you', function() {
        request = ajax.generateRequest();
      test('has the correct xhr method', function() {
        request = ajax.generateRequest();

Note: The example above uses Chai's expect assertion style.

To run a set of test suites:

  1. Create an HTML file with a script that calls the loadSuites method. loadSuites takes as an argument an array of strings, where each string is a relative URL for a test suite:


    <!doctype html>
        <meta charset="utf-8">
        <script src="../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
        <script src="../node_modules/web-component-tester/browser.js"></script>

    You can configure your tests using query strings in the URLs. See Test shadow DOM for an example.

  2. Run Web Component Tester, specifying the path to the HTML file as the first argument. For example:

    wct test/my-test-set.html

Always wrap your test in flush if your element template contains a template repeater (dom-repeat) or conditional template (dom-if), or if your test involves shadow DOM mutation. The shady DOM polyfill lazily performs these operations in some cases for performance. flush ensures that asynchronous changes have taken place. The test function should take one argument, done, to indicate that it is asynchronous, and it should call done() at the end of flush.

suite('my-list tests', function() {
  var list, listItems;
  setup(function() {
    list = fixture('basic');
  test('Item lengths should be equal', function(done) {
    list.items = [
      'Responsive Web App boilerplate',
      'Unit testing with Web Component Tester',
      'Offline support with the Platinum Service Worker Elements'
    // Data bindings will stamp out new DOM asynchronously
    // so wait to check for updates
    flush(function() {
      listItems = list.shadowRoot.querySelectorAll('li');
      assert.equal(list.items.length, listItems.length);

To run your tests with polyfills, create a test set. When you call loadSuites, add parameters to the URL of your test suite to enable one or more polyfills. For example:



The sample above runs basic-test.html twice, once using native APIs (where the browser supports them), and once using using all of the polyfills.

It's important to get a good testing setup in place for your project as early as possible. Using services like Travis for continuous integration, and Sauce Labs for cross-browser testing means you can be confident that changes you push to your project will work well on different platforms and devices. For guidance on setting up these tools check out the Polycast below.

Safari 10 and 11 have built-in support for testing, but it must be manually enabled.

To enable testing on Safari 10 and 11:

  1. If you don't see the Develop menu in the Safari menu bar, enable it:

    1. Select Safari > Preferences, then click the Advanced tab.
    2. Check the Show Develop menu checkbox.
  2. From the Develop menu, select Allow Remote Automation.

  3. You may need to authorize safaridriver to launch the webdriverd service which hosts the local web server:

    /usr/bin/safaridriver --enable

    Complete the authentication prompt.

More information: WebDriver support in Safari 10

Polymer Summit 2015 video on testing:

The Web Component Tester README has more in-depth information about Web Component Tester usage.