Skip to content
This repository was archived by the owner on Sep 11, 2025. It is now read-only.

Commit d41ca51

Browse files
authored
Support different jest environments (#116)
* Support different jest environments * Fix utils test * Clear some unnecessary close functions
1 parent a55e114 commit d41ca51

File tree

7 files changed

+188
-184
lines changed

7 files changed

+188
-184
lines changed

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module.exports = require('./lib/PlaywrightEnvironment').default
2+
module.exports.getPlaywrightEnv = require('./lib/PlaywrightEnvironment').getPlaywrightEnv
23
module.exports.globalSetup = require('./lib/global').setup
34
module.exports.globalTeardown = require('./lib/global').teardown

src/PlaywrightEnvironment.ts

Lines changed: 138 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
/* eslint-disable no-console */
22
/* eslint-disable @typescript-eslint/ban-ts-ignore */
3-
import NodeEnvironment from 'jest-environment-node'
4-
import { Config as JestConfig } from '@jest/types'
5-
import { Event, State } from 'jest-circus'
3+
import type { Config as JestConfig } from '@jest/types'
4+
import type { Event, State } from 'jest-circus'
5+
import type { Browser } from 'playwright-core'
6+
import playwright from 'playwright-core'
7+
import type { Config, GenericBrowser, BrowserType } from './types'
8+
import { CHROMIUM, IMPORT_KIND_PLAYWRIGHT } from './constants'
69
import {
710
getBrowserType,
811
getDeviceType,
912
getPlaywrightInstance,
1013
readConfig,
1114
readPackage,
1215
} from './utils'
13-
import {
14-
Config,
15-
CHROMIUM,
16-
GenericBrowser,
17-
IMPORT_KIND_PLAYWRIGHT,
18-
BrowserType,
19-
} from './constants'
20-
import playwright, { Browser } from 'playwright-core'
2116

2217
const handleError = (error: Error): void => {
2318
process.emit('uncaughtException', error)
@@ -64,154 +59,156 @@ const getBrowserPerProcess = async (
6459
}
6560
}
6661

67-
class PlaywrightEnvironment extends NodeEnvironment {
68-
private _config: JestConfig.ProjectConfig
69-
constructor(config: JestConfig.ProjectConfig) {
70-
super(config)
71-
this._config = config
72-
}
62+
export const getPlaywrightEnv = (basicEnv = 'node') => {
63+
// eslint-disable-next-line @typescript-eslint/no-var-requires
64+
const RootEnv = require(basicEnv === 'node'
65+
? 'jest-environment-node'
66+
: 'jest-environment-jsdom')
7367

74-
async setup(): Promise<void> {
75-
const config = await readConfig(this._config.rootDir)
76-
//@ts-ignore
77-
const browserType = getBrowserType(this._config.browserName)
78-
const { context, exitOnPageError, server, selectors } = config
79-
const playwrightPackage = await readPackage()
80-
if (playwrightPackage === IMPORT_KIND_PLAYWRIGHT) {
81-
// eslint-disable-next-line @typescript-eslint/no-var-requires
82-
const playwright = require('playwright')
83-
if (selectors) {
84-
await Promise.all(
85-
selectors.map(({ name, script }) => {
86-
return playwright.selectors.register(name, script)
87-
}),
88-
)
89-
}
68+
return class PlaywrightEnvironment extends RootEnv {
69+
private _config: JestConfig.ProjectConfig
70+
71+
constructor(config: JestConfig.ProjectConfig) {
72+
super(config)
73+
this._config = config
9074
}
91-
//@ts-ignore
92-
const device = getDeviceType(this._config.device)
93-
const playwrightInstance = await getPlaywrightInstance(
94-
playwrightPackage,
95-
browserType,
96-
)
97-
let contextOptions = context
98-
99-
if (server) {
100-
// eslint-disable-next-line @typescript-eslint/no-var-requires
101-
const devServer = require('jest-dev-server')
102-
const { setup, ERROR_TIMEOUT, ERROR_NO_COMMAND } = devServer
103-
teardownServer = devServer.teardown
104-
try {
105-
await setup(server)
106-
} catch (error) {
107-
if (error.code === ERROR_TIMEOUT) {
108-
logMessage({
109-
message: error.message,
110-
action: 'can set "server.launchTimeout"',
111-
})
75+
76+
async setup(): Promise<void> {
77+
const config = await readConfig(this._config.rootDir)
78+
//@ts-ignore
79+
const browserType = getBrowserType(this._config.browserName)
80+
const { context, exitOnPageError, server, selectors } = config
81+
const playwrightPackage = await readPackage()
82+
if (playwrightPackage === IMPORT_KIND_PLAYWRIGHT) {
83+
// eslint-disable-next-line @typescript-eslint/no-var-requires
84+
const playwright = require('playwright')
85+
if (selectors) {
86+
await Promise.all(
87+
selectors.map(({ name, script }) => {
88+
return playwright.selectors.register(name, script)
89+
}),
90+
)
11291
}
113-
if (error.code === ERROR_NO_COMMAND) {
114-
logMessage({
115-
message: error.message,
116-
action: 'must set "server.command"',
117-
})
92+
}
93+
//@ts-ignore
94+
const device = getDeviceType(this._config.device)
95+
const playwrightInstance = await getPlaywrightInstance(
96+
playwrightPackage,
97+
browserType,
98+
)
99+
let contextOptions = context
100+
101+
if (server) {
102+
// eslint-disable-next-line @typescript-eslint/no-var-requires
103+
const devServer = require('jest-dev-server')
104+
const { setup, ERROR_TIMEOUT, ERROR_NO_COMMAND } = devServer
105+
teardownServer = devServer.teardown
106+
try {
107+
await setup(server)
108+
} catch (error) {
109+
if (error.code === ERROR_TIMEOUT) {
110+
logMessage({
111+
message: error.message,
112+
action: 'can set "server.launchTimeout"',
113+
})
114+
}
115+
if (error.code === ERROR_NO_COMMAND) {
116+
logMessage({
117+
message: error.message,
118+
action: 'must set "server.command"',
119+
})
120+
}
121+
throw error
118122
}
119-
throw error
120123
}
121-
}
122124

123-
if (device) {
124-
const { viewport, userAgent } = playwright.devices[device]
125-
contextOptions = { viewport, userAgent, ...contextOptions }
126-
}
127-
this.global.browserName = browserType
128-
this.global.deviceName = device
129-
this.global.browser = await getBrowserPerProcess(
130-
playwrightInstance,
131-
browserType,
132-
config,
133-
)
134-
this.global.context = await this.global.browser.newContext(contextOptions)
135-
this.global.page = await this.global.context.newPage()
136-
if (exitOnPageError) {
137-
this.global.page.on('pageerror', handleError)
138-
}
139-
this.global.jestPlaywright = {
140-
debug: async (): Promise<void> => {
141-
// Run a debugger (in case Playwright has been launched with `{ devtools: true }`)
142-
await this.global.page.evaluate(() => {
143-
// eslint-disable-next-line no-debugger
144-
debugger
145-
})
146-
// eslint-disable-next-line no-console
147-
console.log('\n\n🕵️‍ Code is paused, press enter to resume')
148-
// Run an infinite promise
149-
return new Promise((resolve) => {
150-
const { stdin } = process
151-
const listening = stdin.listenerCount('data') > 0
152-
const onKeyPress = (key: string): void => {
153-
if (
154-
key === KEYS.CONTROL_C ||
155-
key === KEYS.CONTROL_D ||
156-
key === KEYS.ENTER
157-
) {
158-
stdin.removeListener('data', onKeyPress)
159-
if (!listening) {
160-
if (stdin.isTTY) {
161-
stdin.setRawMode(false)
125+
if (device) {
126+
const { viewport, userAgent } = playwright.devices[device]
127+
contextOptions = { viewport, userAgent, ...contextOptions }
128+
}
129+
this.global.browserName = browserType
130+
this.global.deviceName = device
131+
this.global.browser = await getBrowserPerProcess(
132+
playwrightInstance,
133+
browserType,
134+
config,
135+
)
136+
this.global.context = await this.global.browser.newContext(contextOptions)
137+
this.global.page = await this.global.context.newPage()
138+
if (exitOnPageError) {
139+
this.global.page.on('pageerror', handleError)
140+
}
141+
this.global.jestPlaywright = {
142+
debug: async (): Promise<void> => {
143+
// Run a debugger (in case Playwright has been launched with `{ devtools: true }`)
144+
await this.global.page.evaluate(() => {
145+
// eslint-disable-next-line no-debugger
146+
debugger
147+
})
148+
// eslint-disable-next-line no-console
149+
console.log('\n\n🕵️‍ Code is paused, press enter to resume')
150+
// Run an infinite promise
151+
return new Promise((resolve) => {
152+
const { stdin } = process
153+
const listening = stdin.listenerCount('data') > 0
154+
const onKeyPress = (key: string): void => {
155+
if (
156+
key === KEYS.CONTROL_C ||
157+
key === KEYS.CONTROL_D ||
158+
key === KEYS.ENTER
159+
) {
160+
stdin.removeListener('data', onKeyPress)
161+
if (!listening) {
162+
if (stdin.isTTY) {
163+
stdin.setRawMode(false)
164+
}
165+
stdin.pause()
162166
}
163-
stdin.pause()
167+
resolve()
164168
}
165-
resolve()
166169
}
167-
}
168-
if (!listening) {
169-
if (stdin.isTTY) {
170-
stdin.setRawMode(true)
170+
if (!listening) {
171+
if (stdin.isTTY) {
172+
stdin.setRawMode(true)
173+
}
174+
stdin.resume()
175+
stdin.setEncoding('utf8')
171176
}
172-
stdin.resume()
173-
stdin.setEncoding('utf8')
174-
}
175-
stdin.on('data', onKeyPress)
176-
})
177-
},
177+
stdin.on('data', onKeyPress)
178+
})
179+
},
180+
}
178181
}
179-
}
180182

181-
async handleTestEvent(event: Event, state: State): Promise<void> {
182-
// Hack to set testTimeout for jestPlaywright debugging
183-
if (
184-
event.name === 'add_test' &&
185-
event.fn &&
186-
event.fn.toString().includes('jestPlaywright.debug()')
187-
) {
188-
// Set timeout to 4 days
189-
state.testTimeout = 4 * 24 * 60 * 60 * 1000
183+
async handleTestEvent(event: Event, state: State): Promise<void> {
184+
// Hack to set testTimeout for jestPlaywright debugging
185+
if (
186+
event.name === 'add_test' &&
187+
event.fn &&
188+
event.fn.toString().includes('jestPlaywright.debug()')
189+
) {
190+
// Set timeout to 4 days
191+
state.testTimeout = 4 * 24 * 60 * 60 * 1000
192+
}
190193
}
191-
}
192194

193-
async teardown(jestConfig: JestConfig.InitialOptions = {}): Promise<void> {
194-
const { page, context, browser } = this.global
195-
if (page) {
196-
page.removeListener('pageerror', handleError)
197-
}
198-
if (context) {
199-
await context.close()
200-
}
201-
if (page) {
202-
await page.close()
203-
}
195+
async teardown(jestConfig: JestConfig.InitialOptions = {}): Promise<void> {
196+
const { page, browser } = this.global
197+
if (page) {
198+
page.removeListener('pageerror', handleError)
199+
}
204200

205-
if (browser) {
206-
await browser.close()
207-
}
201+
if (browser) {
202+
await browser.close()
203+
}
208204

209-
await super.teardown()
205+
await super.teardown()
210206

211-
if (!jestConfig.watch && !jestConfig.watchAll && teardownServer) {
212-
await teardownServer()
207+
if (!jestConfig.watch && !jestConfig.watchAll && teardownServer) {
208+
await teardownServer()
209+
}
213210
}
214211
}
215212
}
216213

217-
export default PlaywrightEnvironment
214+
export default getPlaywrightEnv()

src/PlaywrightRunner.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// @ts-nocheck
2-
import JestRunner, {
2+
import JestRunner from 'jest-runner'
3+
import playwright from 'playwright-core'
4+
import type {
35
Test,
46
TestRunnerContext,
57
TestWatcher,
@@ -8,9 +10,8 @@ import JestRunner, {
810
OnTestFailure,
911
TestRunnerOptions,
1012
} from 'jest-runner'
11-
import playwright from 'playwright-core'
12-
import { Config as JestConfig } from '@jest/types'
13-
import { BrowserType } from './constants'
13+
import type { Config as JestConfig } from '@jest/types'
14+
import type { BrowserType } from './types'
1415
import {
1516
checkBrowserEnv,
1617
checkDeviceEnv,

src/constants.ts

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,11 @@
1-
import {
2-
BrowserTypeLaunchOptions,
3-
BrowserNewContextOptions,
4-
WebKitBrowser,
5-
ChromiumBrowser,
6-
FirefoxBrowser,
7-
BrowserType as PlaywrightBrowserType,
8-
BrowserTypeConnectOptions,
9-
} from 'playwright-core'
10-
import { JestDevServerOptions } from 'jest-dev-server'
1+
import { Config } from './types'
112

123
export const IMPORT_KIND_PLAYWRIGHT = 'playwright'
134

145
export const CHROMIUM = 'chromium'
156
export const FIREFOX = 'firefox'
167
export const WEBKIT = 'webkit'
178

18-
export type BrowserType = typeof CHROMIUM | typeof FIREFOX | typeof WEBKIT
19-
20-
export type GenericBrowser = PlaywrightBrowserType<
21-
WebKitBrowser | ChromiumBrowser | FirefoxBrowser
22-
>
23-
24-
export type SelectorType = {
25-
script: string | Function | { path?: string; content?: string }
26-
name: string
27-
}
28-
29-
export type PlaywrightRequireType = BrowserType | typeof IMPORT_KIND_PLAYWRIGHT
30-
31-
export interface Config {
32-
launchBrowserApp?: BrowserTypeLaunchOptions
33-
context?: BrowserNewContextOptions
34-
exitOnPageError: boolean
35-
browsers?: BrowserType[]
36-
devices?: string[]
37-
server?: JestDevServerOptions
38-
selectors?: SelectorType[]
39-
connectBrowserApp?: BrowserTypeConnectOptions
40-
}
41-
429
export const DEFAULT_CONFIG: Config = {
4310
launchBrowserApp: {},
4411
context: {},

0 commit comments

Comments
 (0)