diff --git a/__tests__/App.test.jsx b/__tests__/App.test.jsx index 29f0f21fa0..663cf231a8 100644 --- a/__tests__/App.test.jsx +++ b/__tests__/App.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import { mountWithContexts } from './enzymeHelpers'; +import { mountWithContexts, waitForElement } from './enzymeHelpers'; import { asyncFlush } from '../jest.setup'; @@ -66,11 +66,9 @@ describe('', () => { expect(wrapper.find(aboutModalContent)).toHaveLength(0); wrapper.find(aboutDropdown).simulate('click'); wrapper.find(aboutButton).simulate('click'); - wrapper.update(); // check about modal content - const content = wrapper.find(aboutModalContent); - expect(content).toHaveLength(1); + const content = await waitForElement(wrapper, aboutModalContent); expect(content.find('dd').text()).toContain(ansible_version); expect(content.find('pre').text()).toContain(`< Tower ${version} >`); diff --git a/__tests__/enzymeHelpers.jsx b/__tests__/enzymeHelpers.jsx index aa04ca5c26..d8a5de7e4e 100644 --- a/__tests__/enzymeHelpers.jsx +++ b/__tests__/enzymeHelpers.jsx @@ -158,3 +158,26 @@ export function mountWithContexts (node, options = {}) { }; return mount(wrapContexts(node, context), { context, childContextTypes }); } + +/** + * Wait for element to exist. + * + * @param[wrapper] - A ReactWrapper instance + * @param[selector] - The selector of the element to wait for. + */ +export function waitForElement (wrapper, selector) { + const interval = 100; + return new Promise((resolve, reject) => { + let attempts = 30; + (function pollElement () { + wrapper.update(); + if (wrapper.exists(selector)) { + return resolve(wrapper.find(selector)); + } + if (--attempts <= 0) { + return reject(new Error(`Element not found using ${selector}`)); + } + return setTimeout(pollElement, interval); + }()); + }); +} diff --git a/__tests__/enzymeHelpers.test.jsx b/__tests__/enzymeHelpers.test.jsx index 5ee423800a..8a92fe0ab9 100644 --- a/__tests__/enzymeHelpers.test.jsx +++ b/__tests__/enzymeHelpers.test.jsx @@ -1,8 +1,8 @@ -import React from 'react'; +import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { mountWithContexts } from './enzymeHelpers'; +import { mountWithContexts, waitForElement } from './enzymeHelpers'; import { Config } from '../src/contexts/Config'; import { withNetwork } from '../src/contexts/Network'; import { withRootDialog } from '../src/contexts/RootDialog'; @@ -185,12 +185,12 @@ describe('mountWithContexts', () => { }); it('should set props on wrapped component', () => { - function Component ({ text }) { + function TestComponent ({ text }) { return (
{text}
); } const wrapper = mountWithContexts( - + ); expect(wrapper.find('div').text()).toEqual('foo'); wrapper.setProps({ @@ -199,3 +199,56 @@ describe('mountWithContexts', () => { expect(wrapper.find('div').text()).toEqual('bar'); }); }); + +/** + * This is a fixture for testing async components. It renders a div + * after a short amount of time. + */ +class TestAsyncComponent extends Component { + constructor (props) { + super(props); + this.state = { displayElement: false }; + } + + componentDidMount () { + setTimeout(() => { + this.setState({ displayElement: true }); + }, 1000); + } + + render () { + const { displayElement } = this.state; + if (displayElement) { + return (
); + } + return null; + } +} + +describe('waitForElement', () => { + it('waits for the element and returns it', async (done) => { + const selector = '#test-async-component'; + const wrapper = mountWithContexts(); + expect(wrapper.exists(selector)).toEqual(false); + + const elem = await waitForElement(wrapper, selector); + expect(elem.props().id).toEqual('test-async-component'); + expect(wrapper.exists(selector)).toEqual(true); + done(); + }); + + it('eventually throws an error for elements that don\'t exist', async (done) => { + const selector = '#does-not-exist'; + const wrapper = mountWithContexts(
); + + let error; + try { + await waitForElement(wrapper, selector); + } catch (err) { + error = err; + } finally { + expect(error).toEqual(new Error(`Element not found using ${selector}`)); + done(); + } + }); +});