Search code examples
nuxt.jsnuxt3.jsvitest

Test a component with Vitest using useNuxtApp with Nuxt 3


I want to test a component using the useNuxtApp composable. This is the component(MyComponent.vue):

<template>
  <div class="flex justify-between">
    <span>{{ $fmt(12) }}</span>
  </div>
</template>

<script lang="ts" setup>
const { $fmt } = useNuxtApp()
</script>

$fmt is a plugin in plugins folder.

The problem is when I try to test MyComponent.vue with vitest, the test is not started and this error appears:

ReferenceError: useNuxtApp is not defined

I don't know how to mock the useNuxtApp composable


Solution

  • The solution is to import useNuxtApp in your component:

    <template>
      <div class="flex justify-between">
        <span>{{ $fmt(12) }}</span>
      </div>
    </template>
    
    <script lang="ts" setup>
    import { useNuxtApp } from '#app'
    const { $fmt } = useNuxtApp()
    </script>
    

    add the #app and #head aliases in vitest.config.js to import useNuxtApp in your test file also:

    import path from 'path'
    import vue from '@vitejs/plugin-vue'
    
    export default {
      plugins: [vue()],
      test: {
        globals: true,
        environment: 'jsdom',
        setupFiles: './tests/unit/setup/index.ts',
      },
      resolve: {
        alias: {
          '@': path.resolve(__dirname, '.'),
          '#app': path.resolve(
            __dirname,
            './node_modules/nuxt/dist/app/index.d.ts'
          ),
          '#head': path.resolve(
            __dirname,
            './node_modules/nuxt/dist/app/index.d.ts'
          ),
        },
      },
    }
    

    And finally you can mock useNuxtApp in your test file:

    import { vi } from 'vitest'
    import * as nuxt from '#app'
    import { currency } from '@/plugins/utils/fmt-util'
    
    // @ts-ignore
    vi.spyOn(nuxt, 'useNuxtApp').mockImplementation(() => ({
      $fmt: { currency },
    }))