msw: `flushPromises` from `vue-test-utils` must be called multiple times
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");.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 21 (6 by maintainers)
Summary, if I may, for anyone stumbling upon this in the future:
vue-test-utilsimplementsflushPromisesas a dead simple way to “wait for external promises to resolve”flushPromisesmakes a fairly important assumption about the external promisesmswdoes notmswimplementation, precisely 2 calls are needed.mswdev will not change their implementation to conform (possibly justified if it will cause unexpected breaking changes)vue-test-utilsdevs will add documentation update with a warning aboutvue-test-utils+mswFeel free to edit this comment if any of this is incorrect.
For a race condition, it has been extraordinarily consistent, across multiple OS’s, new/old devices, and 100+ runs.
I asked the
vue-test-utilsfolks about this. See https://github.com/vuejs/test-utils/issues/137 I also looked intomsw’s compiled code, and it seems like every request is behind asetTimeout(func, 0)promise (or more, if using thedelay()feature), which is basically like one instance offlushPromises. As such, their explanation for why you need twoflushPromisesmakes more sense to me.Again yes,
axios-mock-adapter. Perhaps that library is mocking things synchronously somehow, leading to the difference.Ultimately it seems to come down to this. I’m begging for
mswandvue-test-utilsto 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 forvue-cliprojects (equivalent to the ubiquitouscreate-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 usingvue-test-utilswithmsw.I’ve just written a new Vue + MSW integration example and I highly recommend anybody reading this to use
wait-for-expectto handle asynchronous code. You shouldn’t rely on third-party packages to flush promises for you. That brings too much implementation details to your tests and you start focusing on the wrong thing.