jest-puppeteer-vuetify v0.1.5
jest-puppeteer-vuetify
This is a utility which both makes it easier to use XPaths with jest and puppeteer, and generates XPaths to locate Vuetify components.
Installation
jest-puppeteer-vuetify is written in Typescript, and so must be built:
yarn
yarn run buildTesting
A Vuetify application, jest-puppeteer-vuetify-test, is included which serves various Vuetify components for testing purposes.
It must be running before tests can be run:
cd jest-puppeteer-vuetify-test
yarn
yarn serveOnce jest-puppeteer-vuetify-test is running, tests can be run:
# Headless mode
yarn run test
# Browser popup, extended jest test timeout
yarn run test-debugjest-xpaths
Puppeteer and expect-puppeteer prefer using CSS selectors whenever possible.
They do have some support for XPath locators, but they cannot be used for everything that CSS selectors can be used for.
Sadly, many elements generated by Vuetify cannot practically be identified with CSS selectors, so sometimes XPaths are required.
To help remedy this, the jest-xpaths module registers several new methods on the Jest expect object.
For instance:
await expect(page).toFillXPath('//input[@id="username"]', 'DandiDan');
await expect(page).toClickXPath('//input[@id="submit"]');This module is still a work in progress. If you think it should be capable of something that it doesn't do yet, feel free to augment it.
vuetify-xpaths
Despite XPaths sometimes being the only option for locating Vuetify elements, they can still be painful to write and maintain.
To help with this, we have the vuetify-xpaths helper which generates XPaths (element locators) for common Vuetify elements.
For example, to fill a text field labelled Username and click a button labelled Submit, you can do this:
await expect(page).toFillXPath(vTextField('Username'), 'DandiDan');
await expect(page).toClickXPath(vBtn('Submit'));Usage
The canonical argument to any vElement is a destructured object.
The arguments are unique to each element, but generally will have a content argument and a cssClass argument.
If the argument is not an object, it is assumed to be content.
- If
contentis falsy or absent, likevFoo()orvFoo({content: null}), the XPath will match anyv-foo. - If
contentis a string, likevFoo('Hello')orvFoo({content: 'World'}), the XPath will match anyv-foowhich contains the string. - If
contentis a valid XPath, likevFoo(vBar()), the XPath will match anyv-foowhich contains av-bar. Note thatvBaris not necessarily an immediate child ofvFoo;vFoo(vBar())will also match<v-foo><div><v-bar /></div></v-foo>. - If
contentis an array, every element in the array is treated as a separatecontent.vFoo(['Hello', vBar()])will match anyv-foowhich contains both av-barelement and the textHello.
The same assumptions are generally made for different arguments. Here are some examples selectors and DOM elements they will locate:
vFoo({ contents: vBar('Hello World!'), cssClass: ['world', 'hello'] })
<v-foo class='hello world'>
<v-bar>
Hello World!
</v-bar>
</v-foo>The second argument will generally be an object whose options will vary based on the element.
Most elements have a cssClass option which will only match elements with the given class.
- If
cssClassis falsy, nothing will be done. - If
cssClassis a string, likevFoo(null, 'text-center'), it will match allv-foowhich have the classtext-center. This is roughly equivalent to the CSS selector.v-foo.text-center. - If
cssClassis an array, likevFoo(null, ['text-center', 'text--blue']), it will match allv-foowhich have both classestext-centerandtext--blue. This is roughly equivalent to the CSS selector.v-foo.text-center.text--blue.
Other secondary options will generally behave like contents or like cssClass, depending on whether they identify DOM properties or CSS classes.
Because generated XPaths are strings, generally speaking they can be composed with string concatenation.
vFoo() + vBar() will match any v-bar which is contained in a v-foo.
This module is still a work in progress. It relies on the internal behavior of Vuetify and is liable to break with any Vuetify update. If existing methods don't work in your use case or there is a missing method, feel free to fix it.