This is a utility which both makes it easier to use XPaths with jest and puppeteer, and generates XPaths to locate Vuetify components.
jest-puppeteer-vuetify
is written in Typescript, and so must be built:
yarn
yarn run build
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 serve
Once jest-puppeteer-vuetify-test
is running, tests can be run:
# Headless mode
yarn run test
# Browser popup, extended jest test timeout
yarn run test-debug
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.
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'));
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
content
is falsy or absent, likevFoo()
orvFoo({content: null})
, the XPath will match anyv-foo
. - If
content
is a string, likevFoo('Hello')
orvFoo({content: 'World'})
, the XPath will match anyv-foo
which contains the string. - If
content
is a valid XPath, likevFoo(vBar())
, the XPath will match anyv-foo
which contains av-bar
. Note thatvBar
is not necessarily an immediate child ofvFoo
;vFoo(vBar())
will also match<v-foo><div><v-bar /></div></v-foo>
. - If
content
is an array, every element in the array is treated as a separatecontent
.vFoo(['Hello', vBar()])
will match anyv-foo
which contains both av-bar
element 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
cssClass
is falsy, nothing will be done. - If
cssClass
is a string, likevFoo(null, 'text-center')
, it will match allv-foo
which have the classtext-center
. This is roughly equivalent to the CSS selector.v-foo.text-center
. - If
cssClass
is an array, likevFoo(null, ['text-center', 'text--blue'])
, it will match allv-foo
which have both classestext-center
andtext--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.