-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
34a9ccf
commit e9d4561
Showing
2 changed files
with
83 additions
and
0 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
06-test-react-components-with-jest-and-react-testing-library/__tests__/countdown.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import 'react-testing-library/cleanup-after-each'; | ||
|
||
import React from 'react'; | ||
import {render} from 'react-testing-library'; | ||
|
||
import {Countdown} from '../src/countdown'; | ||
|
||
// because the component we're testing is using setInterval, we need mock the | ||
// timer out using Jest, otherwise our tests may be subject to the timers, | ||
// slowing our tests down | ||
jest.useFakeTimers(); | ||
|
||
beforeEach(() => { | ||
jest.spyOn(console, 'error').mockImplementation(() => {}); | ||
}); | ||
|
||
afterEach(() => { | ||
console.error.mockRestore(); | ||
}); | ||
|
||
describe('Countdown', () => { | ||
// my naive first implementation. This does, however, work, but it's only | ||
// ensuring that the component clears the interval | ||
// We don't explicitly know that setState will not be called after the | ||
// component has unmounted | ||
test('clears interval when unmounting', () => { | ||
jest.spyOn(global, 'clearInterval'); | ||
const {unmount} = render(<Countdown />); | ||
|
||
unmount(); | ||
|
||
expect(global.clearInterval).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
// to assert that set state is not called after the component unmounts, we can | ||
// assert on console.error, since we know that React will throw an error if | ||
// state is set on an unmounted component | ||
test('does not set state after interval is cleared', () => { | ||
const {unmount} = render(<Countdown />); | ||
|
||
unmount(); | ||
|
||
// we need to ensure that before any assertions are made that there are no | ||
// more pending timers to run, otherwise we may be running assertions before | ||
// our component has done all of its work | ||
jest.runOnlyPendingTimers(); | ||
|
||
// if console.error was not called by the time there are no timers to run, | ||
// we know that setState didn't result in an error being thrown. | ||
expect(console.error).not.toHaveBeenCalled(); | ||
}); | ||
}); |
31 changes: 31 additions & 0 deletions
31
06-test-react-components-with-jest-and-react-testing-library/src/countdown.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from 'react'; | ||
|
||
class Countdown extends React.Component { | ||
state = {remainingTime: 10000}; | ||
|
||
componentDidMount() { | ||
const end = Date.now() + this.state.remainingTime; | ||
|
||
this.interval = setInterval(() => { | ||
const remainingTime = end - Date.now(); | ||
|
||
if (remainingTime <= 0) { | ||
clearInterval(this.interval); | ||
|
||
this.setState({remainingTime: 0}); | ||
} else { | ||
this.setState({remainingTime}); | ||
} | ||
}); | ||
} | ||
|
||
componentWillUnmount() { | ||
clearInterval(this.interval); | ||
} | ||
|
||
render() { | ||
return this.state.remainingTime; | ||
} | ||
} | ||
|
||
export {Countdown}; |