WebdriverIO Testing Library
webdriverio-testing-library
allows the use of dom-testing-library
queries in WebdriverIO for end-to-end web testing.
Install
Be sure to follow the WebdriverIO install & config instructions first
then just
- npm
- Yarn
npm install --save-dev @testing-library/webdriverio
yarn add --dev @testing-library/webdriverio
API
setupBrowser
Accepts a WebdriverIO browser object
and returns dom-testing-library queries modifed to return
WebdriverIO elements like normal
selectors. All queries are async and
are bound to document.body
by default.
import {setupBrowser} from '@testing-library/webdriverio'
it('can click button', async () => {
const {getByText} = setupBrowser(browser)
const button = await getByText('Button Text')
await button.click()
expect(await button.getText()).toEqual('Button Clicked')
})
setupBrowser
also adds queries as commands to the browser and to all
WebdriverIO elements. The browser commands are scoped to document.body
. The
element commands are scoped to the element in the same way as if it was passed
to within
.
it('adds queries as browser commands', async () => {
setupBrowser(browser)
expect(await browser.getByText('Page Heading')).toBeDefined()
})
it('adds queries as element commands scoped to element', async () => {
setupBrowser(browser)
const nested = await browser.$('*[data-testid="nested"]')
const button = await nested.getByText('Button Text')
await button.click()
expect(await button.getText()).toEqual('Button Clicked')
})
When using sync mode these commands are also synchronous:
it('adds queries as browser commands', async () => {
setupBrowser(browser)
expect(browser.getByText('Page Heading')).toBeDefined()
})
it('adds queries as element commands scoped to element', async () => {
setupBrowser(browser)
const nested = browser.$('*[data-testid="nested"]')
const button = nested.getByText('Button Text')
button.click()
expect(button.getText()).toEqual('Button Clicked')
})
When using v7.19 or higher of WebdriverIO you can also use chainable queries.
Chainable queries are added to the browser and element as commands with the
format {query}$
.
it('can chain browser getBy queries', async () => {
setupBrowser(browser)
await browser.getByTestId$('nested').getByText$('Button Text').click()
const buttonText = await browser
.getByTestId$('nested')
.getByText$('Button Text')
.getText()
expect(buttonText).toEqual('Button Clicked')
})
it('can chain element getBy queries', async () => {
const {getByTestId} = setupBrowser(browser)
const nested = await getByTestId('nested')
await nested.getByText$('Button Text').click()
const buttonText = await browser.getByText$('Button Clicked').getText()
expect(buttonText).toEqual('Button Clicked')
})
it('can chain getAllBy queries', async () => {
setupBrowser(browser)
await browser.getByTestId$('nested').getAllByText$('Button Text')[0].click()
expect(await browser.getAllByText('Button Clicked')).toHaveLength(1)
})
within
Accepts a WebdriverIO element and returns queries scoped to that element
import {within} from '@testing-library/webdriverio'
it('within scopes queries to element', async () => {
const nested = await browser.$('*[data-testid="nested"]')
const button = await within(nested).getByText('Button Text')
await button.click()
expect(await button.getText()).toEqual('Button Clicked')
})
configure
Lets you configure dom-testing-library
import {configure} from '@testing-library/webdriverio'
beforeEach(() => {
configure({testIdAttribute: 'data-automation-id'})
})
afterEach(() => {
configure(null)
})
it('lets you configure queries', async () => {
const {getByTestId} = setupBrowser(browser)
expect(await getByTestId('testid-in-data-automation-id-attr')).toBeDefined()
})
TypeScript
This library comes with full typescript definitions. To use the commands added
by setupBrowser
the Browser
and Element
interfaces in the
global WebdriverIO
namespace need to be extended. Add the following to a
typescript module:
import {WebdriverIOQueries} from '@testing-library/webdriverio'
declare global {
namespace WebdriverIO {
interface Browser extends WebdriverIOQueries {}
interface Element extends WebdriverIOQueries {}
}
}
If you are using the @wdio/sync
package you will need to use the
WebdriverIOQueriesSync
type to extend the interfaces:
import {WebdriverIOQueriesSync} from '@testing-library/webdriverio'
declare global {
namespace WebdriverIO {
interface Browser extends WebdriverIOQueriesSync {}
interface Element extends WebdriverIOQueriesSync {}
}
}
To add chainable query types you need to extend the above interfaces as well as
ChainablePromiseElement
with WebdriverIOQueriesChainable
:
import {WebdriverIOQueriesChainable, WebdriverIOQueries} from '../../src'
declare global {
namespace WebdriverIO {
interface Browser
extends WebdriverIOQueries,
WebdriverIOQueriesChainable<Browser> {}
interface Element
extends WebdriverIOQueries,
WebdriverIOQueriesChainable<Element> {}
}
}
declare module 'webdriverio' {
interface ChainablePromiseElement<T extends WebdriverIO.Element | undefined>
extends WebdriverIOQueriesChainable<T> {}
}
If you are finding an error similar to this:
browser.getByRole('navigation')
// "Argument of type '"navigation"' is not assignable to parameter of type 'ByRoleOptions | undefined'."
you need to include "DOM" in the lib option of your tsconfig. See here for more information.
Additional information about using typescript with WebdriverIO can be found here