Skip to content

Commit ea9409c

Browse files
committed
feat: add mocked timer detection and try to workaround them
1 parent 92fa0db commit ea9409c

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

src/browser.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ import Hookable from 'hable'
22
import onExit from 'signal-exit'
33
import BrowserError from './utils/error'
44
import Xvfb from './utils/commands/xvfb'
5-
import { abstractGuard, loadDependency, getBrowserConfigFromString, getBrowserImportFromConfig } from './utils'
65
import { browsers } from './browsers'
6+
import {
7+
abstractGuard,
8+
loadDependency,
9+
isMockedFunction,
10+
disableTimers,
11+
enableTimers,
12+
getBrowserConfigFromString,
13+
getBrowserImportFromConfig
14+
} from './utils'
715

816
export default class Browser extends Hookable {
917
constructor(config = {}) {
@@ -58,6 +66,16 @@ export default class Browser extends Hookable {
5866
if (this.config.xvfb !== false) {
5967
Xvfb.load(this)
6068
}
69+
70+
if (isMockedFunction(setTimeout, 'setTimeout')) {
71+
// eslint-disable-next-line no-console
72+
console.warn(`Mocked timers detected
73+
74+
The browser probably won't ever start with globally mocked timers. Will try to automatically use real timers on start and set to use fake timers after start. If the browser still hangs and doesn't start, make sure to only mock the global timers after the browser has started `)
75+
76+
this.hook('start:before', () => enableTimers())
77+
this.hook('start:after', () => disableTimers())
78+
}
6179
}
6280

6381
static async get(browserString = '', config = {}) {

src/utils/index.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,23 @@ export function abstractGuard(className, { name } = {}) {
1010
}
1111
}
1212

13+
export function isMockedFunction(fn, fnName) {
14+
return fn.name !== fnName
15+
}
16+
1317
// TODO: add more test framework checks like sinon?
18+
export function disableTimers() {
19+
// find Jest fingerprint
20+
if (process.env.JEST_WORKER_ID) {
21+
try {
22+
jest.useFakeTimers()
23+
} catch (e) {
24+
/* istanbul ignore next */
25+
throw new BrowserError(`Enabling fake timers failed: ${e.message}`)
26+
}
27+
}
28+
}
29+
1430
export function enableTimers() {
1531
// find Jest fingerprint
1632
if (process.env.JEST_WORKER_ID) {
@@ -86,9 +102,9 @@ export function getDefaultHtmlCompiler() {
86102
return html => compile(html).ast
87103
}
88104

89-
export async function loadDependency(dependency) {
105+
export function loadDependency(dependency) {
90106
try {
91-
return await import(dependency).then(m => m.default || m)
107+
return import(dependency).then(m => m.default || m)
92108
} catch (e) {
93109
throw new BrowserError(`Could not import the required dependency '${dependency}'
94110
(error: ${e.message})

0 commit comments

Comments
 (0)