vitest: vue: dynamic component imports are not resolved

Describe the bug

With Vue, you can define async components with a dynamic import like the following:

<template>
  <button @click="showHello = true">Show Hello</button>
  <div v-if="showHello">
    <div>Async component</div>
    <Hello :count="1"></Hello>
  </div>
</template>

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue';

const Hello = defineAsyncComponent(() => import('./Hello.vue'));
const showHello = ref(false);
</script>

Hello.vue is then loaded only when the user clicks on the button Show Hello

But a unit test checking this behavior fails with Vitest:

import { mount, flushPromises } from '@vue/test-utils';
import AsyncComp from '../components/AsyncComp.vue';

test('mount component', async () => {
  const wrapper = mount(AsyncComp);

  expect(wrapper.text()).toContain('Show Hello');

  await wrapper.get('button').trigger('click');
  expect(wrapper.vm.showHello).toBe(true);
  await flushPromises();
  // I suppose this should work but does not
  expect(wrapper.text()).toContain('1 x 2');
});

Maybe I’m missing something obvious in the test setup, but it looks like the promise is never resolved.

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-bmfn8b

System Info

System:
    OS: macOS 12.3.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 16.90 GB / 64.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.15.0 - ~/.volta/tools/image/node/16.15.0/bin/node
    Yarn: 1.22.17 - ~/.volta/tools/image/yarn/1.22.17/bin/yarn
    npm: 6.14.17 - ~/.volta/tools/image/npm/6.14.17/bin/npm
  Browsers:
    Chrome: 101.0.4951.64
    Firefox: 100.0
    Safari: 15.4
  npmPackages:
    @vitejs/plugin-vue: 2.3.3 => 2.3.3
    vite: 2.9.9 => 2.9.9
    vitest: 0.12.6 => 0.12.6

Used Package Manager

yarn

Validations

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 15 (9 by maintainers)

Most upvoted comments

I’m having troubles when trying to load nested async components (first async components loads another async component). When using just one, it works fine. See the example. Any idea what am I doing wrong or the dynamicImportSettled doesn’t wait for the nested import?

Yeah, I think we can either offer a wrapper in VTU, or at least document how to build it once a utility is available 👍

Now that dynamicImportSettled is released, we can close this issue. Thanks @sheremet-va !

I found a way to load it, using Vitest internals:

  await flushPromises() // this is needed for vue to start importing
  const worker = globalThis.__vitest_worker__
  const promises = [...worker.moduleCache.values()]
    .filter(m => !m.exports && m.promise)
    .map(m => m.promise)
  await Promise.all(promises) // this is needed for us to wait until module is loaded
  await flushPromises() // this is needed for vue to rerender component

To break it down,

  1. We clicked “Show Hello”
  2. Vue initiated loading, but haven’t called loader yet
  3. We are waiting until the end of the even loop, because Vitest haven’t started importing yet
  4. When Vitest imports modules it puts it inside moduleCache, so we can use it to guarantee that module is loaded
  5. We need to wait until the end of the event loop for Vue to rerender component

I found a bug that Vitest stores some modules twice, but it is out of scope of this issue. I am not sure what else I can do to help you, @cexbrayat