question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Jest + Axios + flushPromises is not enough to wait for Mirage response

See original GitHub issue

This might not be Mirage related, in that case I’m sorry.

In a Nuxt (Vue) app, I have a component test like this:

wrapper = render(MyForm);
fillIn(wrapper.find('input').element, 'valid@gmail.com');
wrapper.find('button').trigger('submit');
await flushPromises();
expect(onSuccess).toHaveBeenCalled();

That test was fine until I moved from axios mocking towards using Mirage. It seems like await flushPromises(); is not enough anymore and the expect(onSuccess).toHaveBeenCalled(); gets called too early.

In some scenarios I could introduce different waiting strategy. I could wait for error or success message rendering in the DOM (await waitForElement(() => {}); But in this case, there’s the prop callback being called and that’s it.

I can see that the route handler is reached before the test ends - even before the assertion (🙏 ) so all I need is a tiny bit of extra waiting, so it would be awesome if I could do something like

await server.idle()

There’s one reliable solution and that’s

await waitFor(() => expect(onRegister).toHaveBeenCalled());

But it seems its significiantly slower (up to extra 50 - 100ms from my measurements, which makes sense, given it loops in 50ms intervals). With the waitFor(() => {}). This test takes up to 200ms which seems like it’s more than it should. But I could be wrong here and it’s normal:)

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
mcoqblin-hiptestcommented, Sep 6, 2020

Hello,

I am bumping this issue because I ran into the same problem earlier this year when trying to setup Mirage in a test environment. I found the source of the problem and the solution, which involves no delays in tests 😄.

tl;dr Setting server.timing to false (not 0) after the server creation will allow you to simply use await flushPromises / await act / await waitFor without any delay.

Reason

Mirage uses Pretender to handle routes, and includes the timing property.

To introduce that delay, Pretender uses setTimeout. This is why awaiting for promises has no effect here.

It is also not possible to use fake timers to instantly execute setTimeout calls, since for various feature reasons Pretender actually performs 50ms long setTimeout calls, and checks the actual elapsed time. It also does that using recursive calls, so attempting to fake setTimeout will result in a good old stack overflow.

Solution

As a documented feature, the timing parameter can also be a boolean. If set to false, it will make the request synchronous. After checking, I can confirm it skips every setTimeout calls.

Right now Mirage does not support having a false timing option when creating a server. Probably part of a bug by the way, as the line this.timing = this.timing || config.timing || 400 can never result in this.timing being set to 0 in a development environment.

However it is possible to force it after the server creation, using server.timing = false. I suppose this is officially supported as the documentation mentions being able to force a timing for a specific test this way.

I can confirm it works wonderfully my test suite in a React environment using testing-library. For instance:

button = render(<Button>)

await act(async () => {
  fireEvent.click(button.container)
})

expect(onSuccess).toHaveBeenCalled()

It also works well with waitFor or flushPromises, and will not have any delay.

Updating Mirage

I would suggest that instead of forcing timing to 0 for tests, it is forced to false instead. I don’t think this would break existing tests, unless some nasty workaround has been done like waiting for setTimeout to be called.

For safety though, I also suggest either allowing timing to be 0 in config, and/or adding a boolean async option to be able to have more control over that behavior.

I am currently trying the changes on my side and will create a pull request when it is done.

0reactions
ryantocommented, May 20, 2020

@dv297 To get your application tests working the best approach is to not wait a specific amount of time, but to wait for an element to be in the document. Check out the guides on appearance and disappearance.

This should be enough to get your tests passing.

+ import { render, fireEvent, waitFor } from "@testing-library/vue";

// ...

  it("shows list elements from api", async () => {
    const { findByText, getByText, queryByText } = render(List);

    const retrieveButton = getByText("Retrieve List");
    await fireEvent.click(retrieveButton);

+    await waitFor(() => {
      expect(queryByText("ABC")).toBeInTheDocument();
      expect(queryByText("DEF")).toBeInTheDocument();
+    })
  });

I think this also has the benefit of making your tests more robust since your no longer relying on implementation details like time or currently resolved promises.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Vue jest not waiting for axios Post - Stack Overflow
I don't see you flushing the promises. Can you try using the flush promise library? npm i --save-dev flush-promises. and then.
Read more >
Cannot reliably flush promises when using delayResponse
I'm using await flushPromises() (from flush-promises package) to wait for promises to be resolved in the test. However, the test skips over ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found