vuetifyjs / vuetify

🐉 Vue Component Framework
https://vuetifyjs.com
MIT License
39.86k stars 6.97k forks source link

[Documentation] How to unit test your app with jest, typescript and vuetify #16764

Closed telion2 closed 1 year ago

telion2 commented 1 year ago

Environment

Browsers: Firefox 110.0 OS: Ubuntu undefined

Steps to reproduce

  1. Create a project with vue cli (vue 3, ts, jest,...)
  2. add vuetify Documentation was bad here as well: https://vuetifyjs.com/en/getting-started/installation/ I ended up using, but since it worked I didn't bother to create a ticket:
    import { createVuetify } from "vuetify";
    import "vuetify/styles";
    import { aliases, fa } from "vuetify/iconsets/fa";
    import "@fortawesome/fontawesome-free/css/all.css";
    const vuetify = createVuetify({
    icons: {
    defaultSet: "fa",
    aliases,
    sets: {
      fa,
    },
    },
    });
    export { vuetify };
    //main.ts
    app.use(vuetify).mount("#app");

Anyways I use

const { VuetifyPlugin } = require("webpack-plugin-vuetify");
...
configureWebpack: {
    plugins: [
      new VuetifyPlugin({ autoImport: true }), // Enabled by default
    ],}
...

Because that was recommended.

  1. Create a jest unit-test Now when creating a jest test, I really hit a road-block. Basically, if I don't import vuetify, I get the warnings from https://github.com/vuetifyjs/vuetify/issues/15217

But if I try to follow the docs from here: https://vuetifyjs.com/en/getting-started/unit-testing/ then this line throws an error:

beforeEach(() => {
    vuetify = new Vuetify()
  })

=> This expression is not constructable. Type 'typeof import("/projectpath/node_modules/vuetify/lib/index")' has no construct signatures.ts(2351

using create

import { createVuetify } from "vuetify";
const vuetify = createVuetify({});

Results in this Error: /projectpath/node_modules/vuetify/lib/framework.mjs:2 import { createDefaults, DefaultsSymbol } from "./composables/defaults.mjs"; ^^^^^^ SyntaxError: Cannot use import statement outside a module I like to note that the test run fine without trying to add vuetify to the mounted components, but the amount of warnings (https://github.com/vuetifyjs/vuetify/issues/15217) is getting unacceptable.

Expected Behavior

I expect documentation that has a clear and working way to use vuetify in a jest context.

Actual Behavior

Following the documentation will instantly lead to an Error. In fact, I simply don't know how to use vuetify 3 in a jest environment, after reading the documentation, googling and asking chatgpt.

Reproduction Link

https://vuetifyjs.com/en/getting-started/unit-testing/

Other comments

Note: When running/building the app, vuetify works without Issue. The git Issue https://github.com/vuetifyjs/vuetify/issues/14749 is chaos and finding a solution there is difficult since the solutions/problems are not applicable.

I also edited my jest.config.js multiple times:

module.exports = {
  preset: "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
  setupFilesAfterEnv: ["./tests/unit/setup.ts"],
  //added the following after debugging and fixing attempts.
  transformIgnorePatterns: [
    "/node_modules/(?!vuetify|axios)/", 
  ],
};

As additional Information the tsconfig.json (mainly generated by vue cli with minor adaptations):

 {
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "useDefineForClassFields": true,
    "resolveJsonModule": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": ["webpack-env", "jest"],
    "paths": {
      "@/*": ["src/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx",
    "tests/somespecificFolder/somespecificFile.js",
    "tests/somespecificFolder/somespecificFile.js",
  ],
  "exclude": ["node_modules", "tests/somespecificFolder/**/*"]
}
tobi-fis commented 1 year ago

Hi @telion2

I ran into the same issue while trying to migrate my unit tests to Vuetify 3.

What solved this for me was explicitly adding the .mjs extension to my transform option within jest.config.js like so:

module.exports = {
...
 transform: {
        '^.+\\.(ts|js|mjs)x?$': 'babel-jest',
    },
}

The problem seems to be, that the .mjs files (and most importantly the import statement) don't get transformed to CJS otherwise, but jest tries to read them as that. And import does not work in CJS, as it uses requires instead.

If you also run into the Can't find module 'vuetify/components' afterwards, make sure to also add the following lines to your jest config:

...
 moduleNameMapper: {
        '^vuetify/components$':
            '<rootDir>/node_modules/vuetify/lib/components/index.mjs',
        '^vuetify/directives$':
            '<rootDir>/node_modules/vuetify/lib/directives/index.mjs',
    },
...

Hope that helps! Cheers

telion2 commented 1 year ago

@tobi-fis Hi, finally had time to check your solution. First Issue: Babel-jest couldn't handle typescript files. At least not my test files, and immediately threw errors that it can't a line like this: const someVar: someType = "someValue"

So I removed 'ts' from your transform line and used @vue/cli-plugin-unit-jest/presets/typescript-and-babel for those again.

Then I tried to use the vuetify = new Vuetify() which still threw

This expression is not constructable.
Type 'typeof import("/projectpath/node_modules/vuetify/lib/index")' has no construct signatures.ts(2351

I tried using createVuetify which at least run the tests but still warned about missing vuetify components. All this time I used this jest.config.js while switching each setting on and off.

module.exports = {
  preset: "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",   //commenting that out means Syntax errors
  transform: {
    "^.+\\.(js|mjs)x?$": "babel-jest",   //using it with ts mean the described TS Sysntax Error. Without the preset in previous line is needed
  },
  moduleNameMapper: {
    "^vuetify/components$": "./node_modules/vuetify/lib/components/index.mjs",  //these make no difference. Yes I checked the links.
    "^vuetify/directives$": "./node_modules/vuetify/lib/directives/index.mjs",
  },
  transformIgnorePatterns: [
    "/node_modules/(?!vuetify|axios)/", // Switching these of means an import Error on Axios. Removing vuetify from there makes no difference to the previously mentioned Errors. 
  ],
  setupFilesAfterEnv: ["./tests/unit/setup.ts"],  //shouldn'T be relevant to the current problem
};

So to sum up: No didn't work and the preset @vue/cli-plugin-unit-jest/presets/typescript-and-babel is needed to make jest work with ts and vue.

In the mean time the Link https://vuetifyjs.com/en/getting-started/unit-testing/ is not online anymore in case anyone is wondering.

krkaa commented 1 year ago

I have the same issue. Are there any solutions?

KaelWD commented 1 year ago

Duplicate of #14749

AdeWang0629 commented 7 months ago

@telion2

I would like to express my warmest gratitude to you. As a Vue developer, I also ran into a similar problem while migrating Vuetify2 to Vuetify3. However, I solved this problem after reading @telion2 's answer. I look forward to many good action from you in the future.

Best regards!