Use Cypress Daywalker to test your web components (Polymer, lit-html, ...) app.
Please star this repo if you use this plugin. This helps me to understand how many people it is useful for and motivates me to continue improving it.
This plugin does not randomly query through trees of nodes but rather creates an index of all registered custom elements.
Add the plugin to your devDependencies
npm install -D cypress-daywalker
At the top of cypress/support/commands.js
:
import 'cypress-daywalker/commands'
You need to inject cypress-daywalker.js
into your application's entrypoint. This can happen by manually or dynamically adding a script tag to your entrypoint file. (If you test a built app, don't forget to add 'node_modules/cypress-daywalker/cypress-daywalker.js' as an extra dependency.)
This is the easiest way: At the top of your entrypoint file e.g. index.html
add the following script tag.
<!-- Eventually adjust the path to your node modules -->
<script src="./node_modules/cypress-daywalker/cypress-daywalker.js"></script>
You might want to avoid that the script tag ends up in a production environment. Therefore, you can inject the script tag into your document before any other javascript gets executed by listening to the window:before:load
event.
context('Default', () => {
before(() => {
// INJECT THE SCRIPT LIKE THIS:
cy.on('window:before:load', (w) => {
const script = w.document.createElement('script');
// Eventually adjust the path to your node modules
script.src = '/node_modules/cypress-daywalker/cypress-daywalker.js';
// // If you cannot reach your node_modules folder easily (e.g. in a Java application), try to load it via a cdn.
// script.src = 'https://cdn.jsdelivr.net/gh/jaysunsyn/[email protected]/cypress-daywalker.js';
w.document.querySelector('head').appendChild(script);
});
cy.visit('http://localhost:3000/');
});
it('input gets filled', () => {
// Test stuff
});
});
Find an example here.
Not all CSS selectors are supported yet, so do not use it as you would use jQuery or the usual querySelector command. Please create issues of use cases where you would like better querying functionalities. For the apps this plugin was developed for, the current functionalities worked pretty well.
By default, cy.dwGet
returns the first found node. If you want it to return any other one, there are two options:
nth
cy.dwGet('my-element', {nth: 2})
cy.dwGet(paper-input:nth(3) input')
If you want to retrieve all results, add the all
flag like this cy.dwGet('my-element', {all: true})
.
This works very well.
cy.dwGet('paper-button')
This works very well.
cy.dwGet('#submit')
cy.dwGet('paper-button#submit')
Find custom elements everywhere in the app or native elements at root level.
cy.dwGet('.foo')
cy.dwGet('.foo.moo')
<div class="find-me">
<paper-button></paper-button>
</div>
<paper-button></paper-button>
cy.dwGet('.find-me > paper-button')
Starting from the root level:
cy.dwGet('div my-element paper-input#important')
or starting from any custom element:
cy.dwGet('my-element div#jay')
Starting a path with a native element which is inside a shadow root is not supported.
If you lazy load some components, you can, for example, add a .wait(500)
to your .visit()
command to wait for them to get available.
Not all cypress commands can be used yet. For some, there are replacements below.
Instead of .click()
use:
cy.dwGet('paper-button').dwDispatch('click') // Results in Event('click')
cy.dwGet('paper-button').dwDispatch(new MouseEvent('click')) // Or pass in any other event
Instead of .type('Hello world')
use:
cy.dwGet('paper-input').dwSetProp('moto moto') // Results in the value property gets set
cy.dwGet('paper-input').dwSetProp('Question', 'label') // Or specify the property name
Instead of .invoke()
use:
cy.dwGet('my-el').dwCall('close')
Before using .should()
you need to attach the node.
When a node gets attached, it gets cloned and appended to the body. When detatching, this clone gets removed.
Be aware that after attaching, you interact with a cloned node and not with the original one.
cy.dwGet('div > paper-button span').dwAttach().should('have.text', 'Click').dwDetach();
See the latest tests of the example https://travis-ci.com/JaySunSyn/cypress-daywalker/builds/