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.

`flushPromises` from `vue-test-utils` must be called multiple times

See original GitHub issue

Discussed in https://github.com/mswjs/msw/discussions/988

Please read discussion first for full details.

<div type='discussions-op-text'>

Originally posted by vincerubinetti November 17, 2021 I have a Vue and vue-test-utils project that I’m trying to use MSW with. I have unit tests for components that call api functions when mounted. Vue exports a function called flushPromises, which is intended to be a simple function you can await to make sure the api calls have returned and the component has finished rendering before continuing with the test.

import { flushPromises, mount } from "@vue/test-utils";

mount(someComponent, mountOptions);

await flushPromises();
await flushPromises(); // <-- need this extra call for MSW to work properly, but not axios-mock-adapter

// some assertions

The component that I’m testing looks like this:

export default defineComponent({
  data() {
    return {
      status: null
    };
  },
  async mounted() {
    this.status = "loading";
    try {
      this.blah = await axios.get(...blah...);
      this.status = null;
    } catch (error) {
      this.status = "error";
    }
  },
});

For some reason, with MSW, I need two flushPromises calls for my tests to pass. The odd thing is, I was using axios-mock-adapter before trying out MSW, and it was working with just one call. Can anyone think of any reason why MSW might be different?

Another funny thing is that MSW is working in my e2e tests in Cypress (setupWorker), but the problem I describe above is happening in my unit tests in Jest (setupServer), which is setup like this:

const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
</div>

Minimum reproducible example

Here is a barebones Vue CLI project with jest unit tests and cypress e2e tests set up: https://github.com/vincerubinetti/msw-test (archived for posterity)

You can run the unit tests with yarn test:unit and the e2e (with gui) tests with yarn test:e2e. This demonstrates the behavior that msw needs two calls to flushPromises whereas axios-mock-adapter only needs one.

You can verify that msw and axios-mock-adapter are both correctly mocking the call by adding expect(wrapper.text()).toMatch("foo"); expect(wrapper.text()).toMatch("bar");.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:16 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
vincerubinetticommented, Mar 15, 2022

Summary, if I may, for anyone stumbling upon this in the future:

  • vue-test-utils implements flushPromises as a dead simple way to “wait for external promises to resolve”
  • but flushPromises makes a fairly important assumption about the external promises
  • most api mocking libraries happen to conform to this assumption, but msw does not
  • it is not a race condition. given the current msw implementation, precisely 2 calls are needed.
  • msw dev will not change their implementation to conform (possibly justified if it will cause unexpected breaking changes)
  • vue-test-utils devs will add documentation update with a warning about vue-test-utils + msw

Feel free to edit this comment if any of this is incorrect.

1reaction
vincerubinetticommented, Mar 15, 2022

and simply prematurely solves an actual race condition

For a race condition, it has been extraordinarily consistent, across multiple OS’s, new/old devices, and 100+ runs.

I asked the vue-test-utils folks about this. See https://github.com/vuejs/test-utils/issues/137 I also looked into msw’s compiled code, and it seems like every request is behind a setTimeout(func, 0) promise (or more, if using the delay() feature), which is basically like one instance of flushPromises. As such, their explanation for why you need two flushPromises makes more sense to me.

I assume when you say “without MSW” you imply you’re using another API mocking library.

Again yes, axios-mock-adapter. Perhaps that library is mocking things synchronously somehow, leading to the difference.


It may be that the way msw is implemented is inherently incompatible with flushing promises in this way, and if that’s the case it should be noted somewhere.

Ultimately it seems to come down to this. I’m begging for msw and vue-test-utils to just add a simple note somewhere. One sentence could’ve saved me hours and hours of discussion, investigating, making min-reproductions, etc.

I can see that you disagree with vue-test-utils’s approach, but it is the default testing library for vue-cli projects (equivalent to the ubiquitous create-react-app). In other words, a ton of people use it. I would really appreciate it if you could just add a simple warning about using vue-test-utils with msw.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Vue-test-utils: using $nextTick multiple times in a single test
I figured out that the $touch() method is called asynchronously, so I need to use $nextTick() for the expect() . The problem appears...
Read more >
Testing Asynchronous Behavior - Vue Test Utils
Another solution is to use an async function and a package like flush-promises . flush-promises flushes all pending resolved promise handlers. You can...
Read more >
Testing Vue 3 Apps — Mock HTTP Requests - Dev Genius
We can do this with unit tests, and then we don't have to test everything by hand. In this article, we'll look at...
Read more >
Vue-test-utils: using $nextTick multiple times in a single test ...
Another approach is to use flushPromises. import flushPromises from 'flush-promises'; ... test('some async test', async () => { const wrapper ...
Read more >
Testing Caveats | VeeValidate
The following examples will use vue-test-utils API to conduct the tests. After triggering an event like an input event, make sure to call...
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