How to configure Jest added to an app via Vue cli 3?

Viewed 2144

I'm trying to introduce testing with Jest into an app build with Vue. I've run

vue add unit-jest

and similarly to what testing single file components with Jest guide suggests, created the following simple test file (Paginator.spec.js in the same folder as Paginator.vue, that is /src/components):

import { mount } from '@vue/test-utils'
import Paginator from "./Paginator.vue";

describe('Paginator', () => {
    it('is a Vue instance', () => {
        const wrapper = mount(Paginator);
        // const a = 2;
        expect(wrapper.isVueInstance()).toBeTruthy();
        // expect(a).toBe(2);
    })
});

Initially I had some issue with Jest itself not finding the file. Later I've changed in jest.config.js

testMatch: [
  '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],

to

testMatch: [
  '**/*.spec.(js|ts)|**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],

and after some weird glitches I got it finding the file (did git stash, made sure that the app is working, then git stash pop and it started to find the files).

But I still has the issue of Jest not recognizing import. I get the following errors regardless I run jest or npm test (which is vue-cli-service test:unit). A simple test like this works normally:

describe('tests of components', () => {
    it('work', () => {
        const a = 2;
        expect(a).toBe(2);
    })
});

but the test shown in the beginning of the question brings

Test suite failed to run
[...]

({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { mount } from '@vue/test-utils'
                                                                                                ^
SyntaxError: Unexpected token {
  at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)

and if I switch the import order to

import Paginator from "./Paginator.vue";
import { mount } from '@vue/test-utils'

I get

ā— Test suite failed to run

  C:\NNTC\medkiosk\src\components\Paginator.spec.js:1
  ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Paginator from "./Paginator.vue";
                                                                                                  ^^^^^^^^^

  SyntaxError: Unexpected identifier

    at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)

(I haven't changed jest.config.js in any fashion other than extending the regexp as shown above)

What's the problem here? Looks like Jest doesn't recognize import as a language feature.. is this a webpack misconfiguration issue? Some loader is missing?

  • There's no webpack config file in the project because it was started with vue cli. One guy claims that the actual config is in node_modules/@vue/cli-service/webpack.config.js it's not that helpful:

    // this file is for cases where we need to access the
    // webpack config as a file when using CLI commands.
    
    let service = process.VUE_CLI_SERVICE
    
    if (!service || process.env.VUE_CLI_API_MODE) {
      const Service = require('./lib/Service')
      service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
      service.init(process.env.VUE_CLI_MODE || process.env.NODE_ENV)
    }
    
    module.exports = service.resolveWebpackConfig()
    

    (resolveWebpackConfig seems to be this one)

  • As I understand this, tweaking internal webpack config is done inside vue.config.js, but I don't know that is the initial config to start modifying and also what is actually should be tweaked

  • I've tried npm i babel-jest (not sure if it's installed already by vue cli), adding .babelrc with { "presets": ["latest"] } similarly to what a person with a similar problem did, tried adding to vue.config.js the part the other guy from that thread suggested:

    configureWebpack: {
        module: {
            rules: [
                {
                    loader: "babel-loader",
                    options: {
                        presets: ["latest"]
                    }
                }
            ]
        }
    },
    

    and also some suggestions from here and for now I'm out of ideas

  • below you can see all the config files

  • a bonus: if I rename the Paginator.spec.js into Paginator.spec.ts makes Jest show this instead:

    ā— Test suite failed to run
    
      Passing cached plugin instances is not supported in babel.loadPartialConfig()
    
        at forEach.item (node_modules/@babel/core/lib/config/partial.js:120:13)
            at Array.forEach (<anonymous>)
        at loadPartialConfig (node_modules/@babel/core/lib/config/partial.js:118:27)
        at TsJestTransformer.process (node_modules/ts-jest/dist/ts-jest-transformer.js:110:32)
    

Can anyone suggest how to fix the config? Or how to debug it? From what I've read so far it seems that probably Jest should get a file piped through babel-loader which doesn't seem to be the case, but I'm not sure. I know, I probably don't know enough about how Webpack works exactly, so hints what to learn are welcome as well, I'll post the solution when I find one.

jest.config.js:

module.exports = {
  moduleFileExtensions: [
    'js',
    'jsx',
    'json',
    'vue',
    'ts',
    'tsx'
  ],
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
    '^.+\\.tsx?$': 'ts-jest'
  },
  transformIgnorePatterns: [
    '/node_modules/'
  ],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  snapshotSerializers: [
    'jest-serializer-vue'
  ],
  testMatch: [
    '**/*.spec.(js|ts)|**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
  ],
  testURL: 'http://localhost/',
  watchPlugins: [
    'jest-watch-typeahead/filename',
    'jest-watch-typeahead/testname'
  ],
  globals: {
    'ts-jest': {
      babelConfig: true
    }
  }
};

babel.config.js:

module.exports = {
  presets: [
    '@vue/app'
  ]
}

vue.config.js:

module.exports = {
    // the default value is '/', which may be ok for production but is not suitable for local build/deploy
    publicPath: ''
};

part of package.json:

  "scripts": {
    "lint": "vue-cli-service lint",
    "serve": "vue-cli-service serve",
    "test:unit": "vue-cli-service test:unit",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "core-js": "^2.6.5",
    "vue": "^2.6.10",
    "vuex": "^3.1.1",
    "vue-class-component": "^7.0.2",
    "vue-property-decorator": "^8.2.2",
    "axios": "^0.19.0",
    // more packages
  },
  "devDependencies": {
    "@types/jest": "^23.1.4",
    "@vue/cli-plugin-babel": "^3.11.0",
    "@vue/cli-plugin-eslint": "^3.11.0",
    "@vue/cli-plugin-typescript": "^3.11.0",
    "@vue/cli-plugin-unit-jest": "^3.11.0",
    "@vue/cli-service": "^3.11.0",
    "@vue/eslint-config-typescript": "^4.0.0",
    "@vue/test-utils": "1.0.0-beta.29",
    "babel-core": "7.0.0-bridge.0",
    "babel-eslint": "^10.0.1",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "ts-jest": "^23.0.0",
    "typescript": "^3.4.3",
    "vue-template-compiler": "^2.6.10"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended",
      "@vue/typescript"
    ],
    "rules": {},
    "parserOptions": {
      "parser": "@typescript-eslint/parser"
    },
    "overrides": [
      {
        "files": [
          "**/__tests__/*.{j,t}s?(x)"
        ],
        "env": {
          "jest": true
        }
      }
    ]
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {}
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "allowJs": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": 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"
  ],
  "exclude": [
    "node_modules"
  ]
}
0 Answers
Related