Running your tests using Jest & Playwright
npm install -D jest jest-playwright-preset playwright
Also you can use jest-playwright-preset
with specific playwright packages:
playwright-webkit
, playwright-chromium
and playwright-firefox
npm install -D jest jest-playwright-preset playwright-firefox
- Node.js >= 10.15.0
- Playwright >=0.12.1
Update your Jest configuration, either:
with package.json
:
"jest": {
"preset": "jest-playwright-preset"
}
or with jest.config.js
:
module.exports = {
preset: 'jest-playwright-preset',
}
And add the Jest command as in the script section of your package.json
:
{
"scripts": {
"test": "jest"
}
}
Now you can use Playwright in your tests:
beforeAll(async () => {
await page.goto('https://whatismybrowser.com/')
})
test('should display "google" text on page', async () => {
const browser = await page.$eval('.string-major', (el) => el.innerHTML)
expect(browser).toContain('Chrome')
})
It's recommend to use a separate Jest configuration jest.e2e.config.js
for jest-playwright
to gain speed improvments and by that to only use Playwright in the end-to-end tests. For that you have to use the -c
flag when calling Jest and use the testMatch
or testRegex
in your Jest config to split them.
Be sure to remove any existing testEnvironment
option from your Jest configuration. The jest-playwright-preset
preset needs to manage that option itself.
You can specify a jest-playwright.config.js
at the root of the project or define a custom path using the JEST_PLAYWRIGHT_CONFIG
environment variable. It should export a config object.
launchOptions
<[object]>. All Playwright launch options can be specified in config. Since it is JavaScript, you can use all stuff you need, including environment.launchType
<LAUNCH | PERSISTENT | SERVER>. Method to launch browser instance.jest-playwright
attaches Playwright to an existing browser instance by default.connectOptions
<[object]>. All Playwright connect options can be specified in config.contextOptions
<[object]>. All Playwright context options can be specified in config.browsers
<[string[]]>. Define browsers to run tests in.chromium
Each test runs Chromium (default).firefox
Each test runs Firefox.webkit
Each test runs Webkit.
devices
<[(string | object)[] | RegExp]>. Define a devices to run tests in. Actual list of devices can be found here.exitOnPageError
<[boolean]>. Exits process on any page error. Defaults totrue
.collectCoverage
<[boolean]>. Enables the coverage collection of thesaveCoverage(page)
calls to the.nyc_output/coverage.json
file.serverOptions
<[object]>. Alljest-process-manager
options.selectors
<[array]>. Define selectors. Each selector must be an object with name and script properties.
There are different ways to define browsers in your tests:
- You can use array of device names:
module.exports = {
devices: ["iPhone 6", "Pixel 2"],
...
}
- You can use RegExp:
module.exports = {
devices: /iPhone 8/,
...
}
- Also you can define custom device:
{
// Name of device
name: string
// Page width and height
viewport: {
width: number
height: number
}
// user agent
userAgent: string
// device scale factor
deviceScaleFactor: number
// is device is mobile
isMobile: boolean
// support of touch events
hasTouch: boolean
}
Usage with query-selector-shadow-dom in jest-playwright.config.js
:
const {
selectorEngine,
} = require('query-selector-shadow-dom/plugins/playwright');
module.exports = {
selectors: [
{name: 'shadow', script: selectorEngine}
],
...
}
You can also specify browser with the BROWSER
environment variable. You should do it only if you are using the whole playwright package.
You can specify device with DEVICE
environment variable.
browserName
<[string]> - name of the current browser (chromium, firefox or webkit)deviceName
<[string]> - name of the current devicebrowser
<[Browser]> - Playwright browser instancecontext
<[Context]> - a new Playwright context instance for each new test filepage
<[Page]> - Playwright page instance (since a new context for every test file also a new page for it)
All of them are available globally in each Jest test. If you are using ESLint and JavaScript, its recommend to use it in combination with the eslint-plugin-jest-playwright.
Debugging tests can be hard sometimes and it is very useful to be able to pause tests in order to inspect the browser. Jest Playwright exposes a method jestPlaywright.debug()
that suspends test execution and gives you opportunity to see what's going on in the browser.
await jestPlaywright.debug()
beforeEach(async () => {
await jestPlaywright.resetPage()
})
To create a new page for each test, you can use this snippet to have a new page object for each individual test.
beforeEach(async () => {
await jestPlaywright.resetContext()
})
To create a new context for each test, you can use this snippet to have a new context object for each individual test.
beforeEach(async () => {
await jestPlaywright.resetBrowser()
})
You can use this snippet to reset current browser for each individual test. It will reset browser, context and page.
It's possible to track the coverage of the end-to-end tests with the babel-plugin-istanbul Babel plugin configured. It needs to be included in the web application which you are gonna test otherwise it won't work. To use it, you have to set collectCoverage
in the jest-playwright.config.js
to true
. Per default the test coverage will be automatically saved after each navigation change (beforeunload
event). If a certain code path is not covered, you can manually call and add the corresponding saveCoverage(page)
call to your tests like that:
await jestPlaywright.saveCoverage(page)
By using coverage collection, it will write the coverage data to the .nyc_output/coverage.json
file which can be transformed using nyc
to the lcov format:
npx nyc report --reporter=lcovonly
or to HTML:
npx nyc report --reporter=html
which will create a HTML website in the coverage
directory.
It's possible to skip tests for browsers or combination of browsers and devices
it.jestPlaywrightSkip(
{ browsers: ['chromium'] },
'should skip this one',
async () => {
const title = await page.title()
expect(title).toBe('Google')
},
)
Jest Playwright integrates a functionality to start a server when running your test suite, like jest-puppeteer. It automatically closes the server when tests are done.
To use it, specify a server section in your jest-playwright.config.js
.
// jest-playwright.config.js
module.exports = {
serverOptions: {
command: 'node server.js',
port: 4444,
},
}
Other options are documented in jest-process-manager.
The default jest-playwright environment is node, but you can use a browser-like environment through jest-playwright-jsdom
There is a utility package expect-playwright which simplifies the expect statements in combination with Playwright to make e.g. shorter text comparisons.
There is an ESLint plugin available eslint-plugin-jest-playwright available which includes the globals for using jest-playwright.
You can run tests for multiple browsers and devices:
- You must have installed the playwright package
- You must define browsers to test with your
jest-playwright.config.js
:
module.exports = {
browsers: ["chromium", "webkit"],
devices: ["iPhone 6", "Pixel 2"],
...
}
It will run your tests for:
- Chromium browser and iPhone 6 device;
- Chromium browser and Pixel 2 device;
- Webkit browser and iPhone 6 device;
- Webkit browser and Pixel 2 device;
If there is no defined browsers in config it will run tests for chromium browser.
Usage with jest-circus
You can use jest-playwright with the jest-circus runner for taking screenshots during test failures for example:
jest.config.json
"testRunner": "jest-circus/runner",
"testEnvironment": "./CustomEnvironment.js"
CustomEnvironment.js
const PlaywrightEnvironment = require('jest-playwright-preset/lib/PlaywrightEnvironment')
.default
class CustomEnvironment extends PlaywrightEnvironment {
async setup() {
await super.setup()
// Your setup
}
async teardown() {
// Your teardown
await super.teardown()
}
async handleTestEvent(event) {
if (event.name === 'test_done' && event.test.errors.length > 0) {
const parentName = event.test.parent.name.replace(/\W/g, '-')
const specName = event.test.name.replace(/\W/g, '-')
await this.global.page.screenshot({
path: `screenshots/${parentName}_${specName}.png`,
})
}
}
}
module.exports = CustomEnvironment
Example Jest configuration in combination with ts-jest:
module.exports = {
preset: 'jest-playwright-preset',
transform: {
'^.+\\.ts$': 'ts-jest',
},
}
Types are also available, which you can either use via directly in your test:
/// <reference types="jest-playwright-preset" />
/// <reference types="expect-playwright" />
or at your central tsconfig.json
either via files
:
{
"files": [
"./global.d.ts",
"node_modules/jest-playwright-preset/types/global.d.ts",
"node_modules/expect-playwright/global.d.ts"
]
}
or via types
:
{
"compilerOptions": {
"types": ["jest-playwright-preset", "expect-playwright"]
}
}
It's important to not change the testEnvironment
to node
. Otherwise it won't work.
If you face into error messages like UnhandledPromiseRejectionWarning: Error: Protocol error (Runtime.callFunctionOn): Target closed.
or
Timeout - Async callback was not invoked within the 20000ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 20000ms timeout specified by jest.setTimeout.Error:
and your Jest error reporting will only show that an entire test (it()
function) has failed, then you need to increase the Jest timeout because the Playwright timeout is greater than the Jest timeout. So Jest in the end will simply stop the execution and no verbose (which exact line) error reporting can be generated.
To fix this behavior simply call
jest.setTimeout(35 * 1000)
in your tests at the top. (30 seconds is the default Playwright timeout for waiting for an specific element.)
If for your individual tests a new entire browser instance spins up each time and it won't be reused, then you probably run them in parallel. If you run them in a synchronous way with the --runInBand
CLI option for Jest, then the same browser instance will be re-used and this should fix the issue.
Demonstration the usage of jest-playwright
for various test cases can be found in playwright-jest-examples
Thanks to Smooth Code for the great jest-puppeteer.
MIT