Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for unit testing in a nuxt environment #349

Closed
3 tasks done
aseidma opened this issue Dec 20, 2021 · 38 comments
Closed
3 tasks done

support for unit testing in a nuxt environment #349

aseidma opened this issue Dec 20, 2021 · 38 comments
Assignees
Labels
enhancement New feature or request

Comments

@aseidma
Copy link

aseidma commented Dec 20, 2021

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 vitest-dev/vitest#2044 (comment)

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.

Tasks

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

issue description from nuxt/nuxt#14972 - @tobiasdiez

@danielroe danielroe added the enhancement New feature or request label Dec 20, 2021
@danielroe danielroe changed the title @vue/test-utils not working with setup syntax support for unit testing components that use auto-import functionality Dec 20, 2021
@aseidma
Copy link
Author

aseidma commented Dec 20, 2021

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

@danielroe
Copy link
Member

danielroe commented Dec 20, 2021

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.

@aseidma
Copy link
Author

aseidma commented Dec 21, 2021

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"],
}

@ClaudiaPascualGea
Copy link

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!

@calebwaldner
Copy link

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.

@tobiasdiez
Copy link

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.

@TheDutchCoder
Copy link

TheDutchCoder commented Aug 24, 2022

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.

@Didza
Copy link

Didza commented Sep 4, 2022

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)

@danielroe danielroe changed the title support for unit testing components that use auto-import functionality support for unit testing in a nuxt environment Sep 21, 2022
@marssantoso
Copy link

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

@ekasuweantara
Copy link

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?

@zanfee
Copy link

zanfee commented Oct 11, 2022

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.

@ckhatton
Copy link

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

Copy link
Member

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

@ckhatton
Copy link

ckhatton commented Oct 17, 2022

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.

Copy link
Member

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.

@dsvgl
Copy link

dsvgl commented Nov 9, 2022

Is it planned to tackle this for the final release? There are numerous discussions on how to get unit tests working with auto-imports: https://github.com/nuxt/framework/discussions?discussions_q=test+imports
I tried all of the mentioned solution like using unplugin-auto-import, reading paths from tsconfig, etc. It works to a certain degree. But when it comes to things like useNuxtApp there is no automated/easy way to get it working.

The only thing I found working (for vitest) is stubbing everything manually via vi.stubGlobal like so (inside a setup-file or on top of test-files):

vi.stubGlobal('useNuxtApp', () => ({
  $colors: {
    'super-color': 'blue',
  },
}));

Or am I missing something?

@silencerspirit
Copy link

silencerspirit commented Nov 17, 2022

Got same error:
image

vitest.config.ts
image

@yassilah
Copy link
Contributor

In case that might be useful, here's my solution: https://github.com/nuxt/framework/discussions/5379#discussioncomment-4224823

@MrKoopie
Copy link

What is the status of this issue? Is any attempt made to add support for this? Nuxt seems to be a wonderful solution, but lacking the ability of unit testing seems to be a

I have tried adding aliases and made several other attempts to get this to work (including manual mapping), however, even with fixing the #import issue, I get the same issue like @silencerspirit has.

@cavias
Copy link

cavias commented Nov 30, 2022

Hello! We are running into the same issue as described here, but we can't seem to get any of the aforementioned workarounds working.

Could we perhaps have any update on the status of this issue? Testing is, imo, very much an important part of modern software design, so I feel this is a lacking feature.

@Nugscree

This comment was marked as duplicate.

@danielroe
Copy link
Member

For those who can't see the status, I'm working on this issue at the moment - which I think is pretty important. Here's a spoiler: https://twitter.com/danielcroe/status/1590490011501142017.

@silverbackdan
Copy link

silverbackdan commented Dec 6, 2022

Hi @danielroe - thanks for working on this. I think it's pretty important too.
I did have things working with @nuxt/test-utils-edge and vite-plugin-nuxt-test which created a working vite config that looked like this:

import { defineConfig } from 'vitest/config'
import NuxtVitest from 'vite-plugin-nuxt-test'

export default defineConfig({
  plugins: [NuxtVitest()],
  test: {
    deps: {
      inline: ['@nuxt/test-utils-next']
    }
  }
})

It now doesn't seem to work with the error

Error: [vite-node] Failed to load /.nuxt/imports
 ❯ VitestRunner.directRequest node_modules/vitest/dist/chunk-vite-node-source-map.61c5ea66.js:222:13

But in the issue you just linked, it seems we also can't install the next version now. Although there was type mis-matching, because different @nuxt/kit and @nuxt/schema was defined it was working.
Do you have a temporary fix that will get my tests running which use imports from aliases such as #imports for the time-being. And is there anything I could do to help. I'm a bit of a novice with the typing, and really trying to get my head into testing too, but if you have theories I could try out or a problem to solve, feel free to ping it my way and I'll see if I can help.

@silverbackdan
Copy link

silverbackdan commented Dec 6, 2022

Interestingly, I reinstalled the test-utils-edge and I'm still having that failed to load issue :(
I hope the could be an easy enough solution soon? I can hopefully just disable that test and I think continue to run unit tests mocking dependencies for now.

Edit: sorry for this, was a frustrating issue but forgot I had started to write a unit test and wasn't mocking the import yet. That's what was causing the issue. When running tests using the test-utils, and setting up the nuxt app, it does seem to work. It's just when I am doing simple unit tests I will be mocking all imports, which is the best way in any case I feel for unit testing

@dsvgl
Copy link

dsvgl commented Jan 5, 2023

Is there any progress on this? Not be able to unit-test really is a blocker.
The demo from Daniel looks great btw.

Copy link
Member

I've open-sourced an experimental library for testing/feedback: vitest-environment-nuxt: https://github.com/danielroe/vitest-environment-nuxt.

At this point please treat this as a playground + a request for comment. Any feedback would be very welcome 😊

@leunis
Copy link

leunis commented Jan 10, 2023

@danielroe

I followed the instructions and added vitest-environment-nuxt to my existing Nuxt3 project.

{
  "private": true,
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "devDependencies": {
    "nuxt": "3.0.0",
    "vitest-environment-nuxt": "^0.3.1"
  },
  "dependencies": {
    "@mdi/font": "^7.1.96",
    "sass": "^1.57.1",
    "vuetify": "^3.0.6"
  }
}

Followed these instructions:

  1. npm i -D vitest-environment-nuxt

  2. create a vitest.config.mjs with the following content:

import { defineConfigWithNuxtEnv } from 'vitest-environment-nuxt/config'

export default defineConfigWithNuxtEnv({
  // any custom vitest config you require
})

The vitest.config.mjs is located in the root of my project.
and when running vitest I get a : command not found: vitest

I think I am doing something wrong. Do you have any suiggestions?

@yassilah
Copy link
Contributor

I think you first need to npm i -D vitest

@leunis
Copy link

leunis commented Jan 10, 2023

Thanks, installed Vitest and after that npm i -D vitest-environment-nuxt. FYI you have to install a specific version:
npm i -D vitest@0.26.0. And now after running npx vitest I am getting errors about problems with a Vuetify node module:

TypeError: CSS.supports is not a function
 ❯ node_modules/vuetify/lib/util/globals.mjs:7:80
      3| export const SUPPORTS_TOUCH = IN_BROWSER && ('ontouchstart' in window || window.navigator.maxTouchPoints > 0);
      4| export const SUPPORTS_FOCUS_VISIBLE = IN_BROWSER && typeof CSS !== 'undefined' && CSS.supports('selector(:focus-visible)');
      5| //# sourceMappingURL=globals.mjs.map
       | 

Is this an easy fix by adding some config items to vitest.config.js?

@danielroe
Copy link
Member

Let's reserve this issue for tracking any issues in nuxt core. If you could move the discussion to https://github.com/danielroe/vitest-environment-nuxt/ that would be much appreciated 🙏

@yassilah
Copy link
Contributor

@leunis have you tried something like this?

// vitest.config.ts
 test: {
    setupFiles: "vuetify.config.js",
    deps: {
      inline: ["vuetify"],
    },
    globals: true,
  },
// vuetify.config.js
global.CSS = { supports: () => false };

@dsvgl
Copy link

dsvgl commented Jan 10, 2023

@danielroe does it makes sense to open-up discussions on https://github.com/danielroe/vitest-environment-nuxt ?

@dsvgl
Copy link

dsvgl commented Jan 25, 2023

https://github.com/danielroe/vitest-environment-nuxt is on a good way!
Are there any plans to do something similar for Jest?
Migrating our big Nuxt 2 app to 3 is a big challenge itself. Not having to migrate all of our Jest unit-tests at the same time would be really helpful 😀

@josecelano
Copy link

I'm also trying to run simple unit tests for this app:

torrust/torrust-index-gui#159

I would not expect this to be so challenging. I've tried with Jest and now I'm trying with Vitest.

@hamzanouali
Copy link

any updates? we are using Nuxt 3 for an Entreprise project and not being able to run unit tests is a blocker, I appreciate your efforts guys, can anyone help?

@MrKoopie
Copy link

any updates? we are using Nuxt 3 for an Entreprise project and not being able to run unit tests is a blocker, I appreciate your efforts guys, can anyone help?

Did you check out https://github.com/danielroe/nuxt-vitest? It has some quirks, but helps greatly to perform unit tests.

@hamzanouali
Copy link

Thanks, @MrKoopie , it works fine so far.

@danielroe danielroe transferred this issue from nuxt/nuxt Nov 6, 2023
@danielroe
Copy link
Member

Closing to track in #297.

The next version of nuxt/test-utils will include support for unit testing in a vitest environment, with a refactor of nuxt-vitest.

@danielroe danielroe transferred this issue from nuxt/test-utils Dec 2, 2023
userquin pushed a commit to userquin/test-utils that referenced this issue Mar 17, 2024
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests