Run your tests using Jest & Puppeteer πͺβ¨
npm install --save-dev jest-puppeteer puppeteer jest
Requires Jest v22+ TypeScript users should additionally install
@types/puppeteer
,@types/jest-environment-puppeteer
and@types/expect-puppeteer
Update your Jest configuration:
{
"preset": "jest-puppeteer"
}
Use Puppeteer in your tests:
describe('Google', () => {
beforeAll(async () => {
await page.goto('https://google.com')
})
it('should display "google" text on page', async () => {
await expect(page).toMatch('google')
})
})
Writing integration test can be done using Puppeteer API but it can be complicated and hard because API is not designed for testing.
To make it simpler, expect-puppeteer API add some specific matchers if you make expectation on a Puppeteer Page.
Some examples:
// Assert that current page contains 'Text in the page'
await expect(page).toMatch('Text in the page')
// Assert that a button containing text "Home" will be clicked
await expect(page).toClick('button', { text: 'Home' })
// Assert that a form will be filled
await expect(page).toFillForm('form[name="myForm"]', {
firstName: 'James',
lastName: 'Bond',
})
Debugging tests can be hard sometimes and it is very useful to be able to pause tests in order to inspect the browser. Jest Puppeteer exposes a method jestPuppeteer.debug()
that suspends test execution and gives you opportunity to see what's going on in the browser.
await jestPuppeteer.debug()
Jest Puppeteer integrates a functionality to start a server when running your test suite. It automatically closes the server when tests are done.
To use it, specify a server section in your jest-puppeteer.config.js
.
// jest-puppeteer.config.js
module.exports = {
server: {
command: 'node server.js',
port: 4444,
},
}
Other options are documented in jest-dev-server.
Jest Puppeteer automatically detect the best config to start Puppeteer but sometimes you may need to specify custom options. All Puppeteer launch or connect options can be specified in jest-puppeteer.config.js
at the root of the project. Since it is JavaScript, you can use all stuff you need, including environment.
// jest-puppeteer.config.js
module.exports = {
launch: {
dumpio: true,
headless: process.env.HEADLESS !== 'false',
},
}
Jest Puppeteer exposes two new globals: browser
, page
. If you want to avoid errors, you can add them to your .eslintrc.js
:
// .eslintrc.js
module.exports = {
env: {
jest: true,
},
globals: {
page: true,
browser: true,
jestPuppeteer: true,
},
}
Sometimes you want to use your own environment, to do that you can extend PuppeteerEnvironment
.
First, create your own js file for custom environment.
// custom-environment.js
const PuppeteerEnvironment = require('jest-environment-puppeteer')
class CustomEnvironment extends PuppeteerEnvironment {
async setup() {
await super.setup()
// Your setup
}
async teardown() {
// Your teardown
await super.teardown()
}
}
module.exports = CustomEnvironment
Then, assigning your js file path to the testEnvironment
property in your Jest configuration.
{
// ...
"testEnvironment": "./custom-environment.js"
}
Now your custom setup
and teardown
will be triggered before and after each test suites.
It is possible to create your own globalSetup
and globalTeardown
.
For this use case, jest-environment-puppeteer
exposes two methods: setup
and teardown
, so that you can wrap them with your own global setup and global teardown methods as the following example:
// global-setup.js
const { setup: setupPuppeteer } = require('jest-environment-puppeteer')
module.exports = async function globalSetup() {
await setupPuppeteer()
// Your global setup
}
// global-teardown.js
const { teardown: teardownPuppeteer } = require('jest-environment-puppeteer')
module.exports = async function globalTeardown() {
// Your global teardown
await teardownPuppeteer()
}
Then assigning your js file paths to the globalSetup
and globalTeardown
property in your Jest configuration.
{
// ...
"globalSetup": "./global-setup.js",
"globalTeardown": "./global-teardown.js"
}
Now your custom globalSetup
and globalTeardown
will be triggered once before and after all test suites.
You can find an example of create-react-app setup in this repository.
Give access to the Puppeteer Browser.
it('should open a new page', async () => {
const page = await browser.newPage()
await page.goto('https://google.com')
})
Give access to a Puppeteer Page opened at start (you will use it most of time).
it('should fill an input', async () => {
await page.type('#myinput', 'Hello')
})
Helper to make Puppeteer assertions, see documentation.
await expect(page).toMatch('A text in the page')
// ...
Put test in debug mode.
- Jest is suspended (no timeout)
- A
debugger
instruction to Chromium, if Puppeteer has been launched with{ devtools: true }
it will stop
it('should put test in debug mode', async () => {
await jestPuppeteer.debug()
})
You can specify a jest-puppeteer.config.js
at the root of the project or define a custom path using JEST_PUPPETEER_CONFIG
environment variable.
launch
<object> All Puppeteer launch options can be specified in config. Since it is JavaScript, you can use all stuff you need, including environment.connect
<object> All Puppeteer connect options can be specified in config. This is an alternative tolaunch
config, allowing you to connect to an already running instance of Chrome.server
<Object> Server options allowed by jest-dev-server
// jest-puppeteer.config.js
module.exports = {
launch: {
dumpio: true,
headless: process.env.HEADLESS !== 'false',
},
server: {
command: 'node server.js',
port: 4444,
},
}
This example uses an already running instance of Chrome by passing the active web socket endpoint to connect
. This is useful, for example, when you want to connect to Chrome running in the cloud.
// jest-puppeteer.config.js
const wsEndpoint = fs.readFileSync(endpointPath, 'utf8')
module.exports = {
connect: {
browserWSEndpoint: wsEndpoint,
},
server: {
command: 'node server.js',
port: 4444,
},
}
Thanks to Fumihiro Xue for his great Jest example.
MIT