4

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"
  ]
}
YakovL
  • 7,557
  • 12
  • 62
  • 102
  • I think its a tsconfig issue - you need commonjs instead esnext - you can use tsConfig option in ts-jest for jest only tsconfig.json – Estradiaz Oct 07 '19 at 15:09
  • 1
    Don't mind above - on https://vue-test-utils.vuejs.org/guides/testing-single-file-components-with-jest.html its stated: `the default Babel config disables ES modules transpilation because webpack already knows how to handle ES modules. However, we do need to enable it for our tests because Jest tests run directly in Node.` so something like: `"presets": [["env", { "targets": { "node": "current" } }]]` - for js files , ts files I guess is commonjs – Estradiaz Oct 07 '19 at 15:25
  • @YakovL Are you running `jest` directly from the command line? – tony19 Oct 12 '19 at 03:11
  • @tony19 well, I've tried both direct call of `jest` and `npm run test` (I've removed the ":unit" bit by the way), both fail, but atm I can't say if there's any difference in the output between the two – YakovL Oct 12 '19 at 08:01
  • Running `jest` directly will likely cause the error you mention. The `@vue/cli-plugin-unit-jest` plugin sets up Babel for Jest, but you won't see the effect of the setup by running `jest` directly (unless you mimic what plugin does beforehand). – tony19 Oct 12 '19 at 08:55
  • Do you have a sample repo that exhibits the error? I might be able to provide a solution if I could reproduce the problem. – tony19 Oct 12 '19 at 08:55
  • @tony19 thanks! Currently I don't have such repo, the project is closed source, but I'll try to provide a [mcve]; unfortunatelly, I can't promise to do that before Monday since I have to visit my office to get the source and adapt it for publication – YakovL Oct 12 '19 at 11:29

0 Answers0