feat: flush intervals by 50 ms default

ts
Jason Staten 5 years ago
parent 1706665619
commit d7c50a87d1

@ -1,56 +1,74 @@
import React from 'react'
import {render, fireEvent} from '../'
import angular from 'angular'
import 'angular-mocks'
import {render, fireEvent, wait} from '../'
class StopWatch {
lapse = 0
running = false
constructor($interval) {
this.$interval = $interval
}
class StopWatch extends React.Component {
state = {lapse: 0, running: false}
handleRunClick = () => {
this.setState(state => {
if (state.running) {
clearInterval(this.timer)
} else {
const startTime = Date.now() - this.state.lapse
this.timer = setInterval(() => {
this.setState({lapse: Date.now() - startTime})
})
}
return {running: !state.running}
})
if (this.running) {
clearInterval(this.timer)
} else {
const startTime = Date.now() - this.lapse
this.timer = this.$interval(() => {
this.lapse = Date.now() - startTime
})
}
this.running = !this.running
}
handleClearClick = () => {
clearInterval(this.timer)
this.setState({lapse: 0, running: false})
this.$interval.cancel(this.timer)
this.lapse = 0
this.running = false
}
componentWillUnmount() {
clearInterval(this.timer)
}
render() {
const {lapse, running} = this.state
return (
<div>
<span>{lapse}ms</span>
<button onClick={this.handleRunClick}>
{running ? 'Stop' : 'Start'}
</button>
<button onClick={this.handleClearClick}>Clear</button>
</div>
)
$onDestroy() {
this.$interval.cancel(this.timer)
}
}
const wait = time => new Promise(resolve => setTimeout(resolve, time))
const template = `
<div>
<span data-testid="elapsed">{{$ctrl.lapse}}ms</span>
<button ng-click="$ctrl.handleRunClick()">
{{$ctrl.running ? 'Stop' : 'Start'}}
</button>
<button ng-click="$ctrl.handleClearClick()">Clear</button>
</div>
`
beforeEach(() => {
angular.module('atl', [])
angular.mock.module('atl')
angular.module('atl').component('atlStopwatch', {
template,
controller: StopWatch,
})
})
test('unmounts a component', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {})
const {unmount, getByText, container} = render(<StopWatch />)
const {$scope, unmount, getByText, getByTestId} = render(
`<atl-stopwatch></atl-stopwatch>`,
)
const elapsedTime = getByTestId('elapsed')
expect(elapsedTime).toHaveTextContent('0ms')
fireEvent.click(getByText('Start'))
// Ensure it starts
getByText('Stop')
await wait()
expect(elapsedTime.textContent).not.toEqual('0ms')
unmount()
// hey there reader! You don't need to have an assertion like this one
// this is just me making sure that the unmount function works.
// You don't need to do this in your apps. Just rely on the fact that this works.
expect(container.innerHTML).toBe('')
// just wait to see if the interval is cleared or not
// if it's not, then we'll call setState on an unmounted component
// and get an error.
// eslint-disable-next-line no-console
await wait(() => expect(console.error).not.toHaveBeenCalled())
expect($scope.$$destroyed).toBe(true)
})

@ -59,6 +59,9 @@ function render(ui, {container, baseElement = container, queries, scope} = {}) {
return template.content
},
$scope,
unmount: () => {
$scope.$destroy()
},
...getQueriesForElement(baseElement, queries),
}
}
@ -79,6 +82,7 @@ function cleanupAtContainer(container) {
function cleanupScope(scope) {
scope.$destroy()
mountedScopes.delete(scope)
}
function getAngularService(name) {
@ -112,16 +116,18 @@ Object.keys(dtlFireEvent).forEach(key => {
fireEvent.mouseEnter = fireEvent.mouseOver
fireEvent.mouseLeave = fireEvent.mouseOut
function flush() {
function flush(millis = 50) {
const $browser = getAngularService('$browser')
if ($browser.deferredFns.length) {
$browser.defer.flush()
}
const $rootScope = getAngularService('$rootScope')
const $interval = getAngularService('$interval')
$interval.flush(millis)
$browser.defer.flush(millis)
$rootScope.$digest()
}
function wait(callback, options) {
dtlWait(() => {
flush()
function wait(callback, options = {}) {
return dtlWait(() => {
flush(options.interval)
if (callback) {
callback()
}

Loading…
Cancel
Save