framework icon indicating copy to clipboard operation
framework copied to clipboard

support for unit testing in a nuxt environment

Open aseidma opened this issue 3 years ago • 17 comments

Describe the feature

Unit testing (e.g. [parts of ]composables or server functions) doesn't require a full built of nuxt.

Originally posted by @pi0 in https://github.com/vitest-dev/vitest/issues/2044#issuecomment-1251939691

We plan to support also unit testing with nuxi test but properly in a Nuxt environment. Exposing vite config only is not enough for doing that and in past similar approach made lots of headaches for testing in Nuxt 2. However, probably will expose as a @nuxt/kit utility anyway as an alternative to current usage that needs replicating vite config for aliases.

Related: https://github.com/nuxt/framework/issues/2465 (auto-import issues when testing components)

issue description from https://github.com/nuxt/framework/issues/7672 - @tobiasdiez

aseidma avatar Dec 20 '21 15:12 aseidma

How do you not use auto-import functionality to import defineComponent? I can't find any module to import it from. 🤔

aseidma avatar Dec 20 '21 19:12 aseidma

You can import it from vue or #imports - neither of which would work in a unit test out-of-the-box. You can see what they correspond to by inspecting the paths in .nuxt/tsconfig.json, and it would be possible to set up your jest environment with moduleNameMapper to respect these values. But I think we can do better.

danielroe avatar Dec 20 '21 23:12 danielroe

I've managed to import the methods from #app, however mapping it to node_modules/@nuxt/bridge/dist/runtime/index as defined in ./.nuxt/tsconfig.json does not work for tests. They fail with a message saying that the path could not be resolved. I've also tried adjusting the path by removing node_modules/, adding <rootDir> and turning it into a relative import with ./, none of the paths resolve when running tests.

There is also no #imports defined in .nuxt/tsconfig.json - perhaps the issue lies here?

Any idea why the paths resolve when running on the dev/production server but don't when running tests? Here is my jest.config.js for context:

module.exports = {
    moduleNameMapper: {
        "^@/(.*)$": "<rootDir>/$1",
        "^~/(.*)$": "<rootDir>/$1",
        "^vue$": "vue/dist/vue.common.js",
        "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
            "<rootDir>/__mocks__/fileMock.js",
        "\\.(css|less|scss|sass)$": "identity-obj-proxy",
        "^#app": "node_modules/@nuxt/bridge/dist/runtime/index",
    },
    watchman: true,
    moduleFileExtensions: ["ts", "js", "vue", "json"],
    transform: {
        "^.+\\.ts?$": "ts-jest",
        "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
        ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest",
    },
    snapshotSerializers: ["<rootDir>/node_modules/jest-serializer-vue"],
    collectCoverage: false,
    collectCoverageFrom: [
        "<rootDir>/components/**/*.vue",
        "<rootDir>/pages/**/*.vue",
    ],
    setupFiles: ["<rootDir>/tests/setup.ts"],
}

aseidma avatar Dec 21 '21 14:12 aseidma

Hi @aseidma, this config has worked for me:

File jest.config.js:

module.exports = {
  setupFiles: ['<rootDir>/jest.setup.js'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '^vue$': 'vue/dist/vue.common.js',
    '^utils/(.*)$': '<rootDir>/utils/$1',
    '#app': '@nuxt/bridge/dist/runtime/index',
  },
  moduleFileExtensions: ['ts', 'js', 'vue', 'json', 'mjs'],
  transform: {
    '^.+\\.ts?$': 'ts-jest',
    '^.+\\.ts$': 'ts-jest',
    '^.+\\.js$': 'babel-jest',
    '.*\\.(vue)$': 'vue-jest',
    '.*\\.(mjs)$': 'babel-jest',
  },
  transformIgnorePatterns: [
    'node_modules/(?!@nuxt)/',
  ],
  collectCoverage: true,
  collectCoverageFrom: [
    '<rootDir>/components/**/*.vue',
    '<rootDir>/pages/**/*.vue',
    '<rootDir>/utils/**/*.ts',
  ],
  testEnvironment: 'jsdom',
};

File jest.setup.js:

import Vue from 'vue';
import VueCompositionAPI from '@vue/composition-api';

Vue.use(VueCompositionAPI)

File babel.config.js (You will need to remove .babelrc file):

module.exports = {
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": true
        }
      }
    ]
  ]
};

However, I am unable to test functions as useNuxtApp or useRuntimeConfig. The following error is displayed: nuxt app instance unavailable

Thank you!

ClaudiaPascualGea avatar Jan 26 '22 11:01 ClaudiaPascualGea

You can import it from vue or #imports - neither of which would work in a unit test out-of-the-box. You can see what they correspond to by inspecting the paths in .nuxt/tsconfig.json, and it would be possible to set up your jest environment with moduleNameMapper to respect these values. But I think we can do better.

I was able to map the #imports module via moduleNameMapper:

// jest.config.js
moduleNameMapper: {
        "^@/(.*)": "<rootDir>/$1",
        "#app": "<rootDir>/node_modules/nuxt3/dist/app/index.mjs",
        "#imports": "<rootDir>/node_modules/nuxt3/dist/pages/runtime/composables.mjs",
},

But to make this work I need to include an import statement in my Vue file so jest has a reference to the module.

import { useRouter } from "#imports" // This needs to be used in my setup script

This works, but now I've lost the convenience of auto-importing if I want Jest to have a reference to the #imports module.

If anyone has any updates or progress on supporting auto-imports in a test env, I'm all ears.

calebwaldner avatar Feb 07 '22 16:02 calebwaldner

What works for auto-imports is to add methods to global in setupfilesafterenv. For example,

global.useRuntimeConfig = () => constructConfig()

It would be nice if nuxt would provide helper utils to make this easier.

tobiasdiez avatar Apr 26 '22 19:04 tobiasdiez

Just wanting to add that this is quite a crucial feature to have, because right now we can't run component tests in nuxt3.

Vitest also doesn't know about the magic auto-imports, so I think it would be nice if Nuxt3 exposed a method that we can call in vitest for this.

Edit: I've found that the unplugin-auto-import plugin works well with providing its own vite config to vitest.

TheDutchCoder avatar Aug 24 '22 12:08 TheDutchCoder

Would like to add that, l also get the same problem with storybook on Nuxt 3

ReferenceError: ref is not defined

It also feels like this auto import feature breaks the benefit of composition api to see where imports are from. (Just thinking out loud)

Didza avatar Sep 04 '22 22:09 Didza

For vitest, using unplugin-auto-import helps mapped auto-imported dirs such as composables and components. However, for nuxt's built in global composables such as useState etc, still can't figure it out.

I found a clue that you could set similar config to what you'd set in jest using moduleNameMapper, with resolve.alias. But so far I tried mimicking the above jest config to no avail.

@TheDutchCoder would you share your config here, if you could get it to work? Thx

marssantoso avatar Sep 27 '22 04:09 marssantoso

For vitest, using unplugin-auto-import helps mapped auto-imported dirs such as composables and components. However, for nuxt's built in global composables such as useState etc, still can't figure it out.

I found a clue that you could set similar config to what you'd set in jest using moduleNameMapper, with resolve.alias. But so far I tried mimicking the above jest config to no avail.

@TheDutchCoder would you share your config here, if you could get it to work? Thx

Any update for this issue?

ekasuweantara avatar Oct 11 '22 04:10 ekasuweantara

For vitest, using unplugin-auto-import helps mapped auto-imported dirs such as composables and components. However, for nuxt's built in global composables such as useState etc, still can't figure it out. ...

I have a similar issue trying to test useStorage. Here is a reproduction. storage.test.ts includes what I'm trying to do, the other tests are attempts to find a workaround but all tests fail.

janfrl avatar Oct 11 '22 07:10 janfrl

Am I correct in saying that Jest testing isn't supported yet in Nuxt 3?

The installation document seems a little thin on the ground. https://v3.nuxtjs.org/getting-started/testing

ckhatton avatar Oct 17 '22 09:10 ckhatton

There are both jest + vitest drivers for Nuxt e2e testing.

danielroe avatar Oct 17 '22 09:10 danielroe

I followed the guide, but I get the error SyntaxError: Cannot use import statement outside a module when running a test. This suggests I will need to setup Babel, but the guide does not mention this.

The test spec is in the directory /tests.

ckhatton avatar Oct 17 '22 09:10 ckhatton

Ah, yes. Jest does struggle with ESM. That's not an issue with Nuxt, per se, but it's a tricky one. There are various guides online.

danielroe avatar Oct 17 '22 09:10 danielroe