M src/__tests__/end-to-end.js => src/__tests__/end-to-end.js +47 -26
@@ 1,39 1,60 @@
-import React from 'react'
+import angular from 'angular'
+import 'angular-mocks'
import {render, wait} from '../'
-const fetchAMessage = () =>
- new Promise(resolve => {
- // we are using random timeout here to simulate a real-time example
- // of an async operation calling a callback at a non-deterministic time
- const randomTimeout = Math.floor(Math.random() * 100)
- setTimeout(() => {
- resolve({returnedMessage: 'Hello World'})
- }, randomTimeout)
- })
+class controller {
+ loading = true
+ data = null
+
+ constructor($q, $timeout) {
+ this.$q = $q
+ this.$timeout = $timeout
+ }
-class ComponentWithLoader extends React.Component {
- state = {loading: true}
- async componentDidMount() {
- const data = await fetchAMessage()
- this.setState({data, loading: false}) // eslint-disable-line
+ load() {
+ return this.$q(resolve => {
+ // we are using random timeout here to simulate a real-time example
+ // of an async operation calling a callback at a non-deterministic time
+ const randomTimeout = Math.floor(Math.random() * 100)
+ this.$timeout(() => {
+ resolve({returnedMessage: 'Hello World'})
+ }, randomTimeout)
+ })
}
- render() {
- if (this.state.loading) {
- return <div>Loading...</div>
- }
- return (
- <div data-testid="message">
- Loaded this message: {this.state.data.returnedMessage}!
- </div>
- )
+
+ $onInit() {
+ this.load().then(response => {
+ this.loading = false
+ this.data = response
+ })
}
}
+const template = `
+ <div ng-if="$ctrl.loading">Loading...</div>
+ <div
+ ng-if="!$ctrl.loading"
+ data-testid="message"
+ >
+ Loaded this message: {{$ctrl.data.returnedMessage}}!
+ </div>
+`
+
+beforeEach(() => {
+ angular.module('atl', [])
+ angular.mock.module('atl')
+ angular.module('atl').component('atlEnd', {
+ template,
+ controller,
+ })
+})
+
test('it waits for the data to be loaded', async () => {
- const {queryByText, queryByTestId} = render(<ComponentWithLoader />)
+ const {queryByText, findByTestId} = render(`<atl-end></atl-end>`)
expect(queryByText('Loading...')).toBeTruthy()
await wait(() => expect(queryByText('Loading...')).toBeNull())
- expect(queryByTestId('message').textContent).toMatch(/Hello World/)
+ const message = await findByTestId('message')
+ expect(message.textContent).toMatch(/Hello World/)
})
D src/flush-microtasks.js => src/flush-microtasks.js +0 -47
@@ 1,47 0,0 @@
-/* istanbul ignore file */
-// the part of this file that we need tested is definitely being run
-// and the part that is not cannot easily have useful tests written
-// anyway. So we're just going to ignore coverage for this file
-/**
- * copied from React's enqueueTask.js
- */
-
-let didWarnAboutMessageChannel = false
-let enqueueTask
-try {
- // read require off the module object to get around the bundlers.
- // we don't want them to detect a require and bundle a Node polyfill.
- const requireString = `require${Math.random()}`.slice(0, 7)
- const nodeRequire = module && module[requireString]
- // assuming we're in node, let's try to get node's
- // version of setImmediate, bypassing fake timers if any.
- enqueueTask = nodeRequire('timers').setImmediate
-} catch (_err) {
- // we're in a browser
- // we can't use regular timers because they may still be faked
- // so we try MessageChannel+postMessage instead
- enqueueTask = callback => {
- if (didWarnAboutMessageChannel === false) {
- didWarnAboutMessageChannel = true
- // eslint-disable-next-line no-console
- console.error(
- typeof MessageChannel !== 'undefined',
- 'This browser does not have a MessageChannel implementation, ' +
- 'so enqueuing tasks via await act(async () => ...) will fail. ' +
- 'Please file an issue at https://github.com/facebook/react/issues ' +
- 'if you encounter this warning.',
- )
- }
- const channel = new MessageChannel()
- channel.port1.onmessage = callback
- channel.port2.postMessage(undefined)
- }
-}
-
-export default function flushMicroTasks() {
- return {
- then(resolve) {
- enqueueTask(resolve)
- },
- }
-}
M src/index.js => src/index.js +3 -4
@@ 1,5 1,4 @@
-import flush from './flush-microtasks'
-import {cleanup} from './pure'
+import {flush, cleanup} from './pure'
// if we're running in a test runner that supports afterEach
// then we'll automatically run cleanup afterEach test
@@ 7,8 6,8 @@ import {cleanup} from './pure'
// if you don't like this then either import the `pure` module
// or set the ATL_SKIP_AUTO_CLEANUP env variable to 'true'.
if (typeof afterEach === 'function' && !process.env.ATL_SKIP_AUTO_CLEANUP) {
- afterEach(async () => {
- await flush()
+ afterEach(() => {
+ flush()
cleanup()
})
}
M src/pure.js => src/pure.js +35 -22
@@ 4,6 4,7 @@ import {
getQueriesForElement,
prettyDOM,
fireEvent as dtlFireEvent,
+ wait as dtlWait,
} from '@testing-library/dom'
const mountedContainers = new Set()
@@ 24,21 25,17 @@ function render(ui, {container, baseElement = container, queries, scope} = {}) {
// they're passing us a custom container or not.
mountedContainers.add(container)
- let $scope
- angular.mock.inject([
- '$compile',
- '$rootScope',
- ($compile, $rootScope) => {
- $scope = $rootScope.$new()
- mountedScopes.add($scope)
- Object.assign($scope, scope)
+ const $rootScope = getAngularService('$rootScope')
+ const $compile = getAngularService('$compile')
+ const $scope = $rootScope.$new()
+ Object.assign($scope, scope)
- const element = $compile(ui)($scope)[0]
- container.appendChild(element)
+ mountedScopes.add($scope)
- $scope.$digest()
- },
- ])
+ const element = $compile(ui)($scope)[0]
+ container.appendChild(element)
+
+ $scope.$digest()
return {
container,
@@ 84,19 81,19 @@ function cleanupScope(scope) {
scope.$destroy()
}
-function getRootScope() {
- let $rootScope
+function getAngularService(name) {
+ let service
angular.mock.inject([
- '$rootScope',
- rootScope => {
- $rootScope = rootScope
+ name,
+ injected => {
+ service = injected
},
])
- return $rootScope
+ return service
}
function fireEvent(...args) {
- const $rootScope = getRootScope()
+ const $rootScope = getAngularService('$rootScope')
const result = dtlFireEvent(...args)
$rootScope.$digest()
return result
@@ 104,7 101,7 @@ function fireEvent(...args) {
Object.keys(dtlFireEvent).forEach(key => {
fireEvent[key] = (...args) => {
- const $rootScope = getRootScope()
+ const $rootScope = getAngularService('$rootScope')
const result = dtlFireEvent[key](...args)
$rootScope.$digest()
return result
@@ 115,5 112,21 @@ Object.keys(dtlFireEvent).forEach(key => {
fireEvent.mouseEnter = fireEvent.mouseOver
fireEvent.mouseLeave = fireEvent.mouseOut
+function flush() {
+ const $browser = getAngularService('$browser')
+ if ($browser.deferredFns.length) {
+ $browser.defer.flush()
+ }
+}
+
+function wait(callback, options) {
+ dtlWait(() => {
+ flush()
+ if (callback) {
+ callback()
+ }
+ }, options)
+}
+
export * from '@testing-library/dom'
-export {render, cleanup, fireEvent}
+export {render, cleanup, fireEvent, wait, flush}