vue-cli: Default unit tests are failing

Version

3.0.0-rc.5

Reproduction link

https://codesandbox.io/s/vue

Steps to reproduce

vue create vue-jest
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, Linter, Unit
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

duplicate HelloWorld.spec.js (i.e. Users.spec.js)

What is expected?

test should pass.

What is actually happening?

 FAIL  tests/unit/Users.spec.js
  ● Test suite failed to run

    /lab/vue-jest/tests/unit/Users.spec.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import "core-js/modules/es6.array.iterator";
                                                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    SyntaxError: Unexpected string

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

In jest.config.js I added cache: false to solve the error. Other information:

  • yarn v 1.6.0
  • node v10.1.0
  • macos High Sierra

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 25
  • Comments: 48 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I believe I solved this problem by adding the following to the jest.config.js:

transformIgnorePatterns: [
    "node_modules/(?!(babel-jest|jest-vue-preprocessor)/)"
  ]

I sadly have to say “I believe…”, because since I added this option to a newly created Vue project (using Vue CLI v3.0.0-rc.10) it suddenly also works for another project, where I didn’t add this option.

I am therefore not exactly sure what solved the issue and I am not able to reproduce it anymore. But I wanted to leave this here for others to try out.

The following links helped me to find this solution:

I also faced that issue. What helped me was:

  • setting babel-core to ~7.0.0-bridge.0 in package.json
  • running npx jest --clearCache

After that everything worked again.

After spending some time debugging the issue, I think I’ve come up with a feasible solution. It seems like this comes down to a ‘wtf’ moment in terms of how NPM’s dependency resolution strategy works. The following seems to be the solution for me, but your mileage may vary depending on the specific scenario.

TLDR

You can do either of these things:

  1. Clear down node_modules and remove package-lock.json. Re-run npm install.
  2. Run npm cache verify and re-run npm install.

I personally think doing both is the best option to ensure everything is sound and your package-lock.json is more in-line with Vue CLI when it generates a fresh project.

Long explanation

The intention seems to be that cli-plugin-unit-jest tries to depend on the root level babel-core, which in combination with cli-plugin-babel is usually babel-core@7.0.0-bridge.0. This is normally fine, but for some unlucky people, NPM can incorrectly resolve babel-core@6.26.3 as a nested dependency of the plugin (instead of being at the root level of node_modules). As it’s essentially the wrong version, all sorts of weird things probably happen behind the scenes, but the bottom line is that Jest cannot transform the code correctly.

Why does this happen? I’m not 100% sure (I am no expert in the NPM dependency resolution algorithm) but my best guess is that:

  • cli-plugin-unit-jest relies on babel-core@6.26.3 indirectly through one of it’s dependencies. I think it is babel-jest in this case, but as it is a peer dependency, it means that babel-core@7.0.0-bridge.0 should theoretically be used.

  • When NPM has to resolve dependencies for babel-jest on the project level e.g. when updating it in my case, the algorithm gets confused and believes babel-core can’t be resolved as a peer dependency. I believe this is at least partly due to the NPM cache being corrupted or caching incorrect dependencies in some way. NPM resolves babel-core@6.26.3 as a nested dependency instead and everything breaks.

It seems like the way to resolve this involves ensuring the NPM cache is correct and consistent (i.e. npm cache verify), and/or rebuilding the package-lock.json and node_modules entirely to make sure it resolves everything from scratch again (without any external caching factors).

@cars10 you just saved my life, if you accept bitcoin ill send you some 💸

@ChristianAEDev

Thanks, this solved it for me, until I change a test file. After running ./node_modules/jest/bin/jest.js --clearCache the tests are working again.

$ cat tests/unit/HelloWorld.spec.ts
import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';

describe('HelloWorld.vue', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message';
    const wrapper = shallowMount(HelloWorld, {
      propsData: { msg },
    });
    expect(wrapper.text()).toMatch(msg);
  });
});

$ npm run test:unit
> frontend@0.1.0 test:unit /Users/sjo4473/src/simonjohansson/quiz/frontend
> vue-cli-service test:unit

 PASS  tests/unit/HelloWorld.spec.ts
  HelloWorld.vue
    ✓ renders props.msg when passed (26ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.303s, estimated 2s
Ran all test suites.

$ vim tests/unit/HelloWorld.spec.ts
$ cat tests/unit/HelloWorld.spec.ts
import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';

describe('HelloWorld.vue', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message';
    const wrapper = shallowMount(HelloWorld, {
      propsData: { msg },
    });
    expect(wrapper.text()).toMatch(msg);
  });

  it('blurgh', () => {
    expect(true).toBeTruthy();
  });
});

$ npm run test:unit
> frontend@0.1.0 test:unit /Users/sjo4473/src/simonjohansson/quiz/frontend
> vue-cli-service test:unit

 FAIL  tests/unit/HelloWorld.spec.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /Users/sjo4473/src/simonjohansson/quiz/frontend/tests/unit/HelloWorld.spec.ts:3
    import "core-js/modules/es6.array.iterator";
    ^^^^^^

    SyntaxError: Unexpected token import

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

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        1.079s
Ran all test suites.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! frontend@0.1.0 test:unit: `vue-cli-service test:unit`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the frontend@0.1.0 test:unit script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/sjo4473/.npm/_logs/2018-08-02T15_05_54_261Z-debug.log

$ ./node_modules/jest/bin/jest.js --clearCache
Cleared /var/folders/2z/g6z_y_4d6hn03vfx9k9gwfp8bxwvxb/T/jest_6mf3xn

$ npm run test:unit
> frontend@0.1.0 test:unit /Users/sjo4473/src/simonjohansson/quiz/frontend
> vue-cli-service test:unit

 PASS  tests/unit/HelloWorld.spec.ts
  HelloWorld.vue
    ✓ renders props.msg when passed (23ms)
    ✓ blurgh (1ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.163s
Ran all test suites.

@cars10, also worked for me. After installing babel-core at ~7.0.0-bridge.0, we’re using

"test:unit": "jest --clearCache && vue-cli-service test:unit",

right now, to avoid the errors whenever we test. Obviously, that’s less than ideal if our tests start to get larger. And we’re also not super comfortable about still requiring babel-core when we should likely only be using

"@babel/core": "^7.1.5",

So I’ll keep an eye on this

I found a workaround based on the one posted by @ebertti and the code of the vue-plugin-unit-test module.

Adding the following at the top of the jest.config.js file fixes the problem:

process.env.VUE_CLI_BABEL_TARGET_NODE = true;
process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true;

I tried every single suggestion provided so far, in vain.

@cars10 Solution worked for me.

This is not a perfect soluction, but I think this can be used temporarily

  transformIgnorePatterns: [
    '/node_modules/.*',
  ],

and creating a .env.test on project root dir with this values

VUE_CLI_BABEL_TARGET_NODE=true
VUE_CLI_BABEL_TRANSPILE_MODULES=true

It works great for me running jest directly on Jetbrains IDE test

Like the OP says, for me too putting cache: false in my jest.config.js worked and solved the issue

I Create a new project in vue-cli add “Unit Testing” and copy differences in my project. This work for me. Install the package:

npm install --save-dev @vue/cli-plugin-unit-jest

change test:unit in package.json to:

"test:unit": "vue-cli-service test:unit"

And create file jest.config.js with this value:

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

In my test, work without jest.config.js.

I also faced that issue. What helped me was:

* setting `babel-core` to `~7.0.0-bridge.0` in `package.json`

* running `npx jest --clearCache`

After that everything worked again.

This worked like a charm! Thanks

I Create a new project in vue-cli add “Unit Testing” and copy differences in my project. This work for me. Install the package:

npm install --save-dev @vue/cli-plugin-unit-jest

change test:unit in package.json to:

"test:unit": "vue-cli-service test:unit"

And create file jest.config.js with this value:

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

In my test, work without jest.config.js.

This solution works fine. Please update the guide at https://vue-test-utils.vuejs.org/guides/testing-single-file-components-with-jest.html

It is not guiding to run the tests with jest through vue-cli

I am getting a similar error as well, expect mine says SyntaxError: Unexpected token import

This may be related to this issue:

https://github.com/vuejs/vue-cli/issues/1524#issue-330793755

babel.config.js

module.exports = {
  presets: [
    ['@vue/babel-preset-app', { modules: false }],
  ],
  plugins: [
    'dynamic-import-node',
  ],
  env: {
    test: {
      presets: [
        ['@vue/babel-preset-app', { modules: 'commonjs', useBuiltIns: false }],
      ],
    },
  },
};

jest.config.js

module.exports = {
  moduleFileExtensions: [
    'js',
    'vue',
  ],
  transform: {
    '.*\\.(js|jsx)?$': 'babel-jest',
    '.*\\.(vue)$': 'vue-jest',
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
  transformIgnorePatterns: [
    '<rootDir>/node_modules/',
  ],
};

I found a workaround based on the one posted by @ebertti and the code of the vue-plugin-unit-test module.

Adding the following at the top of the jest.config.js file fixes the problem:

process.env.VUE_CLI_BABEL_TARGET_NODE = true;
process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true;

Personally, I found this solution proposed by @Nivani to be sufficient without any other changes (in a project generated with CLI 3.0.5). I also found that if I don’t want to “pollute” the Jest config file, I can just set the env vars in the IDE’s run configuration.

Another option is to create a separate config file for the IDE to use that looks like this:

process.env.VUE_CLI_BABEL_TARGET_NODE = true;
process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true;

const config = require( './jest.config');
module.exports = config;

I called it jetbrains-jest.config.js and then selected it as the “Configuration file” in the Jest run configuration. That way, Vue CLI can be Vue CLI, and WebStorm can be WebStorm.

The problem seems to be with the environment variables VUE_CLI_BABEL_TARGET_NODE and VUE_CLI_BABEL_TRANSPILE_MODULES. If they are set to true, the issue goes away.

Jianwu Chen on stackoverflow.com found this solution:

https://stackoverflow.com/questions/51365250/run-jest-got-unexpected-string-at-scripttransformer-transformandbuildscript

I used the vant component library when I was executing Vue-cli-service test:unit The following error was encountered during the command: image How should I solve the problem

Had the same issue. The root cause is if you use npm and it doesn’t hoist dependencies to the node_modules folder. Run npm ls vue-jest babel-jest jest-transform-stub, it should show that all deps at the root level:

└─┬ @vue/cli-plugin-unit-jest@3.11.0
  ├── babel-jest@23.6.0 
  ├─┬ jest@23.6.0
  │ └─┬ jest-cli@23.6.0
  │   └─┬ jest-config@23.6.0
  │     └── babel-jest@23.6.0  deduped
  ├── jest-transform-stub@2.0.0 
  └── vue-jest@3.0.5 

if not, then jest just cannot require transformers using require. Then you need to change the path to transformer. For example:

// jest.config.js
module.exports = {
// .....
  transform: {
    '^.+\\.vue$': '<rootDir>/node_modules/@vue/cli-plugin-unit-jest/node_modules/vue-jest',
   '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': '<rootDir>/node_modules/@vue/cli-plugin-unit-jest/node_modules/jest-transform-stub',
    "^.+\\.[t|j]sx?$": "<rootDir>/node_modules/@vue/cli-plugin-unit-jest/node_modules/babel-jest"
  },
}

this works in case you have this from npm ls vue-jest:

└─┬ @vue/cli-plugin-unit-jest@3.11.0
  └── vue-jest@3.0.5 

Alternatively run npm dedupe to hoist and dedupe dependencies (it will update your package-lock.json as well, so the next time you won’t have that issue)

I have solved my problem by switching to node LTS (10.16.3) and changing version of babel-jest to ^23.6.0. Now tests work as expected.

My problem was that the .npmrc pointed to website that hosted our repository’s configuration which was BEHIND A VPN and I happened to not be signed in when I originally ran npm install. Deleted and re-cloned the repo (prob could have just deleted the node_modules directory and package-lock.json) and made sure I was on the VPN when I ran npm install. Worked like a charm (as it should have originally 🤦‍♂️ )

Only change in transform section for ‘^.+\.jsx?$’ and ‘.*\.(vue)$’ and “babel-jest”: “^23.4.2” worked for me :

jest.config.js

module.exports = {
  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
  transform: {
    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
    **// process js with babel-jest
    '^.+\\.jsx?$': '<rootDir>/node_modules/babel-jest',
    // process *.vue files with vue-jest
    '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',**
  },
  transformIgnorePatterns: ['/node_modules/.*'],

  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
  snapshotSerializers: ['jest-serializer-vue'],
  testMatch: ['**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'],
  testURL: 'http://localhost/',
  watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
};

So it’s just changing from ‘babel-jest’ to ‘<rootDir>/node_modules/babel-jest’ (and the same for vue-jest).

@killboard your solution was the one. In my case i followed this steps:

I’ve encountered same problem after updating babel-jest to version 24.1.0. None of the solutions helped. Getting back to 23.6.0 solved problem for now.

I found a workaround based on the one posted by @ebertti and the code of the vue-plugin-unit-test module.

Adding the following at the top of the jest.config.js file fixes the problem:

process.env.VUE_CLI_BABEL_TARGET_NODE = true;
process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true;

this is, IMHO, way faster than waiting for all tests to finish, when you’re only working on one file.

Though it should be noted that it can also be done using npm run test:unit myComponent. or vue-cli-service test:unit "myComponent" (to run myComponent.spec.js) I’m sure it’s documented somewhere, but I haven’t come cross it and stopped looking. However you can’t (seem to) pass more than one argument, so for example, you may either clear a snaptshot or run a specific test, but you cannot clear a snapshot on a specific test.

maybe this:

All Jest command line options are also supported.

The simple

process.env.VUE_CLI_BABEL_TARGET_NODE = true;
process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true;

addition at the top of my jest config file seems to have fixed things for me as well.

@yyx990803, I have the same problem and no default NODE_ENV are set in my shell.

For users seeing the same problem: do you have a default NODE_ENV set for your shell?

Are you running jest directly? That’s not supposed to work. You must run it via vue-cli-service test:unit.