Skip to content
This repository was archived by the owner on Mar 5, 2022. It is now read-only.

Commit 788d592

Browse files
authored
fix: add delay to let hooks run (#201)
1 parent 37c1ab6 commit 788d592

File tree

5 files changed

+61
-14
lines changed

5 files changed

+61
-14
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
example from https://reactjs.org/docs/testing-recipes.html#timers
2+
3+
Your code might use timer-based functions like setTimeout to schedule more work in the future. In this example, a multiple choice panel waits for a selection and advances, timing out if a selection isn’t made in 5 seconds.

cypress/component/advanced/timers/card-spec.js

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,51 @@ import Card from './card.jsx'
33
import React from 'react'
44
import { mount } from 'cypress-react-unit-test'
55

6-
// NOTE: seems our clock control does not work with effect hooks
7-
it.skip('should select null after timing out', () => {
6+
// looking at the clock control from component's hook
7+
// https://github.com/bahmutov/cypress-react-unit-test/issues/200
8+
it('should select null after timing out (fast)', () => {
89
const onSelect = cy.stub()
10+
// https://on.cypress.io/clock
911
cy.clock()
12+
1013
mount(<Card onSelect={onSelect} />)
14+
cy.get('button').should('have.length', 4)
15+
16+
// component calls "onSelect" stub after 5 seconds of inactivity
1117
cy.tick(100).then(() => {
18+
// not yet
19+
expect(onSelect).to.not.have.been.called
20+
})
21+
cy.tick(1000).then(() => {
22+
// not yet
1223
expect(onSelect).to.not.have.been.called
1324
})
14-
cy.tick(5000).then(() => {
25+
cy.tick(1000).then(() => {
26+
// not yet
27+
expect(onSelect).to.not.have.been.called
28+
})
29+
cy.tick(1000).then(() => {
30+
// not yet
31+
expect(onSelect).to.not.have.been.called
32+
})
33+
cy.tick(1000).then(() => {
34+
// not yet
35+
expect(onSelect).to.not.have.been.called
36+
})
37+
cy.log('5 seconds passed')
38+
cy.tick(1000).then(() => {
39+
// NOW
1540
expect(onSelect).to.have.been.calledWith(null)
1641
})
1742
})
1843

44+
it('should select null after timing out (slow)', () => {
45+
// without synthetic clock we must wait for the real delay
46+
const onSelect = cy.stub().as('selected')
47+
mount(<Card onSelect={onSelect} />)
48+
cy.get('@selected', { timeout: 5100 }).should('have.been.calledWith', null)
49+
})
50+
1951
it('should accept selections', () => {
2052
const onSelect = cy.stub()
2153
mount(<Card onSelect={onSelect} />)

cypress/component/advanced/timers/card-without-effect-spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import { unmountComponentAtNode } from 'react-dom'
66

77
it('should select null after timing out', () => {
88
const onSelect = cy.stub()
9+
// https://on.cypress.io/clock
910
cy.clock()
1011
mount(<Card onSelect={onSelect} />)
12+
1113
cy.tick(100).then(() => {
1214
expect(onSelect).to.not.have.been.called
1315
})

cypress/component/advanced/timers/card.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import React, { useEffect } from 'react'
33
export default function Card(props) {
44
useEffect(() => {
55
const timeoutID = setTimeout(() => {
6+
console.log('after timeout')
67
props.onSelect(null)
78
}, 5000)
9+
810
return () => {
11+
console.log('clearing timeout')
912
clearTimeout(timeoutID)
1013
}
1114
}, [props.onSelect])
1215

16+
console.log('inside Card')
1317
return [1, 2, 3, 4].map(choice => (
1418
<button
1519
key={choice}

lib/index.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,24 @@ export const mount = (jsx: React.ReactElement, options: MountOptions = {}) => {
100100
}
101101
}
102102

103-
return cy
104-
.wrap(CypressTestComponent, { log: false })
105-
.as(options.alias || displayName)
106-
.then(() => {
107-
if (logInstance) {
108-
logInstance.snapshot('mounted')
109-
logInstance.end()
110-
}
111-
112-
return undefined
113-
})
103+
return (
104+
cy
105+
.wrap(CypressTestComponent, { log: false })
106+
.as(options.alias || displayName)
107+
// by waiting, we give the component's hook a chance to run
108+
// https://github.com/bahmutov/cypress-react-unit-test/issues/200
109+
.wait(1, { log: false })
110+
.then(() => {
111+
if (logInstance) {
112+
logInstance.snapshot('mounted')
113+
logInstance.end()
114+
}
115+
116+
// by returning undefined we keep the previous subject
117+
// which is the mounted component
118+
return undefined
119+
})
120+
)
114121
})
115122
}
116123

0 commit comments

Comments
 (0)