diff --git a/.eslintrc.js b/.eslintrc.js index b57f63f4..ff456f51 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,7 +14,7 @@ module.exports = { globals: { page: true, browser: true, - expectPage: true, + jestPuppeteer: true, }, rules: { 'class-methods-use-this': 'off', diff --git a/README.md b/README.md index be453b5b..b7a0acd1 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,14 @@ await expect(page).toFillForm('form[name="myForm"]', { }) ``` +### Put in debug mode + +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. + +```js +await jestPuppeteer.debug() +``` + ### Start a server Jest Puppeteer integrates a functionality to start a server when running your test suite. It automatically closes the server when tests are done. @@ -116,6 +124,7 @@ module.exports = { globals: { page: true, browser: true, + jestPuppeteer: true, }, } ``` @@ -230,6 +239,19 @@ await expect(page).toMatch('A text in the page') // ... ``` +### `global.jestPuppeteer.debug()` + +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 + +```js +it('should put test in debug mode', async () => { + await jestPuppeteer.debug() +}) +``` + ### `jest-puppeteer.config.js` 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. diff --git a/package.json b/package.json index 7cd4581a..b7063a14 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "build": "lerna run build", "ci": "yarn build && yarn lint && yarn test --ci", + "dev": "lerna run build --parallel -- --watch", "format": "prettier --write \"packages/**/*.{js,json,md}\" \"*.{js,json,md}\"", "lint": "eslint .", "release": "lerna publish --conventional-commits && conventional-github-releaser --preset angular", @@ -26,5 +27,6 @@ "lerna": "^2.11.0", "prettier": "^1.13.5", "puppeteer": "^1.5.0" - } + }, + "dependencies": {} } diff --git a/packages/jest-environment-puppeteer/README.md b/packages/jest-environment-puppeteer/README.md index 70124b56..c3dfff8a 100644 --- a/packages/jest-environment-puppeteer/README.md +++ b/packages/jest-environment-puppeteer/README.md @@ -60,6 +60,19 @@ it('should fill an input', async () => { }) ``` +### `global.jestPuppeteer.debug()` + +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 + +```js +it('should put test in debug mode', async () => { + await jestPuppeteer.debug() +}) +``` + ### `jest-puppeteer.config.js` 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. diff --git a/packages/jest-environment-puppeteer/src/PuppeteerEnvironment.js b/packages/jest-environment-puppeteer/src/PuppeteerEnvironment.js index 8c5d9810..0fe023d9 100644 --- a/packages/jest-environment-puppeteer/src/PuppeteerEnvironment.js +++ b/packages/jest-environment-puppeteer/src/PuppeteerEnvironment.js @@ -2,6 +2,7 @@ import fs from 'fs' // eslint-disable-next-line import NodeEnvironment from 'jest-environment-node' import puppeteer from 'puppeteer' +import chalk from 'chalk' import readConfig from './readConfig' import { WS_ENDPOINT_PATH } from './constants' @@ -10,6 +11,17 @@ const handleError = error => { } class PuppeteerEnvironment extends NodeEnvironment { + // Jest is not available here, so we have to reverse engineer + // the setTimeout function, see https://github.com/facebook/jest/blob/v23.1.0/packages/jest-runtime/src/index.js#L823 + setTimeout(timeout) { + if (this.global.jasmine) { + // eslint-disable-next-line no-underscore-dangle + this.global.jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout + } else { + this.global[Symbol.for('TEST_TIMEOUT_SYMBOL')] = timeout + } + } + async setup() { const config = await readConfig() this.global.puppeteerConfig = config @@ -33,6 +45,42 @@ class PuppeteerEnvironment extends NodeEnvironment { if (config && config.exitOnPageError) { this.global.page.addListener('pageerror', handleError) } + + this.global.jestPuppeteer = { + debug: async () => { + // eslint-disable-next-line no-eval + // Set timeout to 4 days + this.setTimeout(345600) + // Run a debugger (in case Puppeteer has been launched with `{ devtools: true }`) + await this.global.page.evaluate(() => { + // eslint-disable-next-line no-debugger + debugger + }) + console.log( + chalk.blue('\n\n🕵️‍ Code is paused, press enter to resume'), + ) + // Run an infinite promise + return new Promise(resolve => { + const { stdin } = process + const onKeyPress = key => { + if (key === '\r') { + stdin.removeListener('data', onKeyPress) + if (!listening) { + stdin.pause() + } + resolve() + } + } + const listening = stdin.listenerCount('data') > 0 + if (!listening) { + stdin.setRawMode(true) + stdin.resume() + stdin.setEncoding('utf8') + } + stdin.on('data', onKeyPress) + }) + }, + } } async teardown() {