Skip to content

Commit

Permalink
feat: add mocked timer detection and try to workaround them
Browse files Browse the repository at this point in the history
  • Loading branch information
pimlie committed Mar 21, 2019
1 parent 92fa0db commit ea9409c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
20 changes: 19 additions & 1 deletion src/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ import Hookable from 'hable'
import onExit from 'signal-exit'
import BrowserError from './utils/error'
import Xvfb from './utils/commands/xvfb'
import { abstractGuard, loadDependency, getBrowserConfigFromString, getBrowserImportFromConfig } from './utils'
import { browsers } from './browsers'
import {
abstractGuard,
loadDependency,
isMockedFunction,
disableTimers,
enableTimers,
getBrowserConfigFromString,
getBrowserImportFromConfig
} from './utils'

export default class Browser extends Hookable {
constructor(config = {}) {
Expand Down Expand Up @@ -58,6 +66,16 @@ export default class Browser extends Hookable {
if (this.config.xvfb !== false) {
Xvfb.load(this)
}

if (isMockedFunction(setTimeout, 'setTimeout')) {
// eslint-disable-next-line no-console
console.warn(`Mocked timers detected
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 `)

this.hook('start:before', () => enableTimers())
this.hook('start:after', () => disableTimers())
}
}

static async get(browserString = '', config = {}) {
Expand Down
20 changes: 18 additions & 2 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,23 @@ export function abstractGuard(className, { name } = {}) {
}
}

export function isMockedFunction(fn, fnName) {
return fn.name !== fnName
}

// TODO: add more test framework checks like sinon?
export function disableTimers() {
// find Jest fingerprint
if (process.env.JEST_WORKER_ID) {
try {
jest.useFakeTimers()
} catch (e) {
/* istanbul ignore next */
throw new BrowserError(`Enabling fake timers failed: ${e.message}`)
}
}
}

export function enableTimers() {
// find Jest fingerprint
if (process.env.JEST_WORKER_ID) {
Expand Down Expand Up @@ -86,9 +102,9 @@ export function getDefaultHtmlCompiler() {
return html => compile(html).ast
}

export async function loadDependency(dependency) {
export function loadDependency(dependency) {
try {
return await import(dependency).then(m => m.default || m)
return import(dependency).then(m => m.default || m)
} catch (e) {
throw new BrowserError(`Could not import the required dependency '${dependency}'
(error: ${e.message})
Expand Down

0 comments on commit ea9409c

Please sign in to comment.