Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/__tests__/fake-timers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {render} from './helpers/test-utils'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've moved all the fake timers tests to this file. The only reason we're using fake timers is for testing timeouts and we don't want this test to take forever.


// Because we're using fake timers here and I don't want these tests to run
// for the actual length of the test (because it's waiting for a timeout error)
// we'll mock the setTimeout, clearTimeout, and setImmediate to be the ones
// that jest will mock for us.
jest.mock('../helpers', () => {
const actualHelpers = jest.requireActual('../helpers')
return {
...actualHelpers,
setTimeout,
clearTimeout,
setImmediate,
}
})

jest.useFakeTimers()

// Because of the way jest mocking works here's the order of things (and no, the order of the code above doesn't make a difference):
// 1. Just mocks '../helpers' and setTimeout/clearTimeout/setImmediate are set to their "correct" values
// 2. We tell Jest to use fake timers
// 3. We reset the modules and we mock '../helpers' again so now setTimeout/clearTimeout/setImmediate are set to their mocked values
// We're only doing this because want to mock those values so this test doesn't take 4501ms to run.
jest.resetModules()

const {
waitForElement,
waitForDomChange,
waitForElementToBeRemoved,
} = require('../')

test('waitForElementToBeRemoved: times out after 4500ms by default', () => {
const {container} = render(`<div></div>`)
const promise = expect(
waitForElementToBeRemoved(() => container),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Timed out in waitForElementToBeRemoved."`,
)
jest.advanceTimersByTime(4501)
return promise
})

test('waitForElement: can time out', async () => {
const promise = waitForElement(() => {})
jest.advanceTimersByTime(4600)
await expect(promise).rejects.toThrow(/timed out/i)
})

test('waitForElement: can specify our own timeout time', async () => {
const promise = waitForElement(() => {}, {timeout: 4700})
const handler = jest.fn()
promise.then(handler, handler)
// advance beyond the default
jest.advanceTimersByTime(4600)
// promise was neither rejected nor resolved
expect(handler).toHaveBeenCalledTimes(0)

// advance beyond our specified timeout
jest.advanceTimersByTime(150)

// timed out
await expect(promise).rejects.toThrow(/timed out/i)
})

test('waitForDomChange: can time out', async () => {
const promise = waitForDomChange()
jest.advanceTimersByTime(4600)
await expect(promise).rejects.toThrow(/timed out/i)
})

test('waitForDomChange: can specify our own timeout time', async () => {
const promise = waitForDomChange({timeout: 4700})
const handler = jest.fn()
promise.then(handler, handler)
// advance beyond the default
jest.advanceTimersByTime(4600)
// promise was neither rejected nor resolved
expect(handler).toHaveBeenCalledTimes(0)

// advance beyond our specified timeout
jest.advanceTimersByTime(150)

// timed out
await expect(promise).rejects.toThrow(/timed out/i)
})
26 changes: 0 additions & 26 deletions src/__tests__/wait-for-dom-change.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,29 +50,3 @@ Array [
]
`)
})

test('can time out', async () => {
jest.useFakeTimers()
const promise = waitForDomChange()
jest.advanceTimersByTime(4600)
await expect(promise).rejects.toThrow(/timed out/i)
jest.useRealTimers()
})

test('can specify our own timeout time', async () => {
jest.useFakeTimers()
const promise = waitForDomChange({timeout: 4700})
const handler = jest.fn()
promise.then(handler, handler)
// advance beyond the default
jest.advanceTimersByTime(4600)
// promise was neither rejected nor resolved
expect(handler).toHaveBeenCalledTimes(0)

// advance beyond our specified timeout
jest.advanceTimersByTime(150)

// timed out
await expect(promise).rejects.toThrow(/timed out/i)
jest.useRealTimers()
})
39 changes: 0 additions & 39 deletions src/__tests__/wait-for-element-to-be-removed.fake-timers.js

This file was deleted.

24 changes: 24 additions & 0 deletions src/__tests__/wait-for-element-to-be-removed.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,27 @@ test('resolves on mutation if callback throws an error', async () => {
})
await waitForElementToBeRemoved(() => getByTestId('div'), {timeout: 100})
})

test('requires a function as the first parameter', () => {
return expect(
waitForElementToBeRemoved(),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"waitForElementToBeRemoved requires a function as the first parameter"`,
)
})

test('requires an element to exist first', () => {
return expect(
waitForElementToBeRemoved(() => null),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist before waiting for removal."`,
)
})

test('requires an unempty array of elements to exist first', () => {
return expect(
waitForElementToBeRemoved(() => []),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist before waiting for removal."`,
)
})
26 changes: 0 additions & 26 deletions src/__tests__/wait-for-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,6 @@ test('waits for element to appear in a specified container', async () => {
expect(element).toBeTruthy()
})

test('can time out', async () => {
jest.useFakeTimers()
const promise = waitForElement(() => {})
jest.advanceTimersByTime(4600)
await expect(promise).rejects.toThrow(/timed out/i)
jest.useRealTimers()
})

test('can specify our own timeout time', async () => {
jest.useFakeTimers()
const promise = waitForElement(() => {}, {timeout: 4700})
const handler = jest.fn()
promise.then(handler, handler)
// advance beyond the default
jest.advanceTimersByTime(4600)
// promise was neither rejected nor resolved
expect(handler).toHaveBeenCalledTimes(0)

// advance beyond our specified timeout
jest.advanceTimersByTime(150)

// timed out
await expect(promise).rejects.toThrow(/timed out/i)
jest.useRealTimers()
})

test('throws last thrown error', async () => {
const {rerender, container} = render('<div />')
let error
Expand Down
37 changes: 21 additions & 16 deletions src/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import MutationObserver from '@sheerun/mutationobserver-shim'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplifying this quite a bit by not using getters and instead just creating variables. Similar to how wait-for-expect does it.


const globalObj = typeof window === 'undefined' ? global : window

// we only run our tests in node, and setImmediate is supported in node.
// istanbul ignore next
function setImmediatePolyfill(fn) {
return globalObj.setTimeout(fn, 0)
}

// istanbul ignore next
const {
setTimeout,
clearTimeout,
setImmediate = setImmediatePolyfill,
} = globalObj

function newMutationObserver(onMutation) {
const MutationObserverConstructor =
typeof window !== 'undefined' &&
Expand All @@ -18,20 +33,10 @@ function getDocument() {
return window.document
}

/*
* There are browsers for which `setImmediate` is not available. This
* serves as a polyfill of sorts, adopting `setTimeout` as the closest
* equivalent
*/
function getSetImmediate() {
/* istanbul ignore else */
if (typeof setImmediate === 'function') {
return setImmediate
} else {
return function setImmediate(fn) {
return setTimeout(fn, 0)
}
}
export {
getDocument,
newMutationObserver,
setImmediate,
setTimeout,
clearTimeout,
}

export {getDocument, newMutationObserver, getSetImmediate}
9 changes: 7 additions & 2 deletions src/wait-for-dom-change.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import {newMutationObserver, getDocument, getSetImmediate} from './helpers'
import {
newMutationObserver,
getDocument,
setImmediate,
setTimeout,
clearTimeout,
} from './helpers'
import {getConfig} from './config'

function waitForDomChange({
Expand All @@ -12,7 +18,6 @@ function waitForDomChange({
},
} = {}) {
return new Promise((resolve, reject) => {
const setImmediate = getSetImmediate()
const timer = setTimeout(onTimeout, timeout)
const observer = newMutationObserver(onMutation)
observer.observe(container, mutationObserverOptions)
Expand Down
9 changes: 7 additions & 2 deletions src/wait-for-element-to-be-removed.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import {getDocument, getSetImmediate, newMutationObserver} from './helpers'
import {
getDocument,
newMutationObserver,
setImmediate,
setTimeout,
clearTimeout,
} from './helpers'
import {getConfig} from './config'

function waitForElementToBeRemoved(
Expand Down Expand Up @@ -44,7 +50,6 @@ function waitForElementToBeRemoved(
}

function onDone(error, result) {
const setImmediate = getSetImmediate()
clearTimeout(timer)
setImmediate(() => observer.disconnect())
if (error) {
Expand Down
10 changes: 8 additions & 2 deletions src/wait-for-element.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import {newMutationObserver, getDocument, getSetImmediate} from './helpers'
import {
newMutationObserver,
getDocument,
setImmediate,
setTimeout,
clearTimeout,
} from './helpers'
import {getConfig} from './config'

function waitForElement(
Expand All @@ -23,10 +29,10 @@ function waitForElement(
}
let lastError
const timer = setTimeout(onTimeout, timeout)

const observer = newMutationObserver(onMutation)
observer.observe(container, mutationObserverOptions)
function onDone(error, result) {
const setImmediate = getSetImmediate()
clearTimeout(timer)
setImmediate(() => observer.disconnect())
if (error) {
Expand Down
1 change: 0 additions & 1 deletion tests/jest.config.node.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const baseConfig = require('kcd-scripts/jest')
module.exports = {
...baseConfig,
rootDir: path.join(__dirname, '..'),
setupFilesAfterEnv: undefined,
displayName: 'node',
testEnvironment: 'jest-environment-node',
testMatch: ['**/__node_tests__/**.js'],
Expand Down