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 angular from 'angular'
import {render, fireEvent} from '../' 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 = () => { handleRunClick = () => {
this.setState(state => { if (this.running) {
if (state.running) {
clearInterval(this.timer) clearInterval(this.timer)
} else { } else {
const startTime = Date.now() - this.state.lapse const startTime = Date.now() - this.lapse
this.timer = setInterval(() => { this.timer = this.$interval(() => {
this.setState({lapse: Date.now() - startTime}) this.lapse = Date.now() - startTime
}) })
} }
return {running: !state.running} this.running = !this.running
})
} }
handleClearClick = () => { handleClearClick = () => {
clearInterval(this.timer) this.$interval.cancel(this.timer)
this.setState({lapse: 0, running: false}) this.lapse = 0
this.running = false
}
$onDestroy() {
this.$interval.cancel(this.timer)
} }
componentWillUnmount() {
clearInterval(this.timer)
} }
render() {
const {lapse, running} = this.state const template = `
return (
<div> <div>
<span>{lapse}ms</span> <span data-testid="elapsed">{{$ctrl.lapse}}ms</span>
<button onClick={this.handleRunClick}> <button ng-click="$ctrl.handleRunClick()">
{running ? 'Stop' : 'Start'} {{$ctrl.running ? 'Stop' : 'Start'}}
</button> </button>
<button onClick={this.handleClearClick}>Clear</button> <button ng-click="$ctrl.handleClearClick()">Clear</button>
</div> </div>
) `
}
}
const wait = time => new Promise(resolve => setTimeout(resolve, time)) beforeEach(() => {
angular.module('atl', [])
angular.mock.module('atl')
angular.module('atl').component('atlStopwatch', {
template,
controller: StopWatch,
})
})
test('unmounts a component', async () => { test('unmounts a component', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {}) const {$scope, unmount, getByText, getByTestId} = render(
const {unmount, getByText, container} = render(<StopWatch />) `<atl-stopwatch></atl-stopwatch>`,
)
const elapsedTime = getByTestId('elapsed')
expect(elapsedTime).toHaveTextContent('0ms')
fireEvent.click(getByText('Start')) fireEvent.click(getByText('Start'))
// Ensure it starts
getByText('Stop')
await wait()
expect(elapsedTime.textContent).not.toEqual('0ms')
unmount() 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. expect($scope.$$destroyed).toBe(true)
// 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())
}) })

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

Loading…
Cancel
Save