I had a couple of gaps in my tests (I wasn’t testing the ConnectedPost) and I ran into the issue again where the HTML was not updated after an asynchronous call to the server. I did a a little research to figure out why.
When you make a call with await in a function, like this:
async componentDidMount() { const post = await fetch(this.props.id) this.setState({post}) }
Javascript returns a promise which gets resolved later. The React framework takes care of that eventually but, when you render your component in a test, you need to make sure all the promises are resolved before you check the resulting HTML.
Jest gives us a function to make that happen and I am going to add a helper to my React helper file to make it easy to use.
// ReactHelper.jsx export const resolveAllPromises = () => new Promise(setImmediate)
Whenever I test a component that makes asynchronous calls, I have to remember to call resolveAllPromises() and make the test function async, like this:
// posts/Post.test.jsx test('fetches a post from the server', async () => { server.send.mockReturnValue(post) const component = display(<ConnectedPost id={1}/>) await resolveAllPromises() component.update() assert_select(component, '.post .title', 'The title') expect(server.send).toBeCalledWith('/posts/1.json') })
But wait! Why should I have to remember do call that every time? I can add it to the helper like this:
// ReactHelper.jsx export async function displayConnected(component) { const connected = mount(component) await resolveAllPromises() connected.update() return connected }
And now the test becomes much simpler:
test('fetches a post from the server', async () => { server.send.mockReturnValue(post) const component = await displayConnected(<ConnectedPost id={1}/>) assert_select(component, '.post .title', 'The title') expect(server.send).toBeCalledWith('/posts/1.json') })
I’m glad that’s straightened out. Back to the storyline.