vuejs / vue-jest

Jest Vue transformer
MIT License
748 stars 156 forks source link

Error while mounting components in Vue 3 with TypeScript #328

Closed timlar closed 3 years ago

timlar commented 3 years ago

NOTE: I previously posted this issue to vue-test-utils-next repository, but then decided to duplicate it here. Maybe someone can help me to understand what I did wrong.

Faced an error while executing shallowMount (this also applies to mount).

Screenshot 2021-02-16 at 16 31 14

The error occurs only if the component contains a <script> block. If there is only <template> block in the component, then everything works.

// jest.config.js

module.exports = {
  preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
  transform: {
    '^.+\\.vue$': 'vue-jest',
  },
}
// tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": ["jest", "webpack-env"],
    "paths": {
      "@/*": ["src/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  },
  "include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.gql", "src/**/*.json", "tests/**/*.ts"],
  "exclude": [".yarn", "node_modules"]
}
// hello-world.vue

<template>
  <div class="hello">
    <h1>{{ message }}</h1>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  props: {
    message: {
      type: String,
      default: '',
    },
  },
})
</script>
// example.spec.ts

import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/hello-world.vue'

describe('HelloWorld.vue', () => {
  it('renders props.message when passed', () => {
    const message = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      props: { message },
    })

    expect(wrapper.text()).toMatch(message)
  })
})
// package.json

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit --coverage",
    "test:e2e": "vue-cli-service test:e2e",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    ...
    "vue": "^3.0.5"
  },
  "devDependencies": {
    ...
    "@vue/cli": "^4.5.11",
    "@vue/cli-plugin-babel": "~4.5.11",
    "@vue/cli-plugin-e2e-cypress": "~4.5.11",
    "@vue/cli-plugin-typescript": "~4.5.11",
    "@vue/cli-plugin-unit-jest": "~4.5.11",
    "@vue/cli-service": "~4.5.11",
    "@vue/compiler-sfc": "^3.0.5",
    "@vue/test-utils": "^2.0.0-rc.1",
    "babel-core": "^6.26.3",
    "babel-jest": "^26.6.3",
    "jest": "^26.6.3",
    "jest-environment-jsdom-fifteen": "^1.0.2",
    "jest-serializer-vue": "^2.0.2",
    "source-map": "^0.7.3",
    "ts-jest": "^26.5.1",
    "typescript": "^4.1.5",
    "vue-jest": "^5.0.0-alpha.8",
    "webpack": "^4.46.0"
  }
}

I tried to investigate the issue. In vue-jest/lib/map-lines.js:12 the variable newMapConsumer is a Promise which does not have eachMapping function.

The value of oldMap is:

{
  version: 3,
  sources: [ '.../src/components/hello-world.vue' ],
  names: [],
  mappings: ';AAOA,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;AAEpC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;EAC7B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;EAClB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACL,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;MACP,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;MACZ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACb,CAAC;EACH,CAAC;AACH,CAAC',
  file: '.../src/components/hello-world.vue',
  sourceRoot: '',
  sourcesContent: [
    '<template>\n' +
      '  <div class="hello">\n' +
      '    <h1>{{ message }}</h1>\n' +
      '  </div>\n' +
      '</template>\n' +
      '\n' +
      '<script lang="ts">\n' +
      "import { defineComponent } from 'vue'\n" +
      '\n' +
      'export default defineComponent({\n' +
      "  name: 'HelloWorld',\n" +
      '  props: {\n' +
      '    message: {\n' +
      '      type: String,\n' +
      "      default: '',\n" +
      '    },\n' +
      '  },\n' +
      '})\n' +
      '</script>\n'
  ]
}

The value of newMap is:

{
  version: 3,
  sources: [ 'module.tsx' ],
  names: [],
  mappings: ';;;;;;;AACA;;eAEe,0BAAgB;AAC7B,EAAA,IAAI,EAAE,YADuB;AAE7B,EAAA,KAAK,EAAE;AACL,IAAA,OAAO,EAAE;AACP,MAAA,IAAI,EAAE,MADC;AAEP,MAAA,OAAO,EAAE;AAFF;AADJ;AAFsB,CAAhB,C',
  sourcesContent: [
    '\n' +
      "import { defineComponent } from 'vue'\n" +
      '\n' +
      'export default defineComponent({\n' +
      "  name: 'HelloWorld',\n" +
      '  props: {\n' +
      '    message: {\n' +
      '      type: String,\n' +
      "      default: '',\n" +
      '    },\n' +
      '  },\n' +
      '})\n'
  ],
  sourceRoot: ''
}

Maybe I do something wrong.

Thanks in advance for any help.

lmiller1990 commented 3 years ago

Thanks for the bug report. Interesting - file is missing in newMap.

I can try reproduce this and debug it. This should definitely work - I don't see any immediately problem.

jolting commented 3 years ago

A hack indeed. https://github.com/mozilla/source-map/blob/7a263408de1b60e60b6220ca3e36d9b3e4aa047d/lib/source-map-consumer.js#L23

jolting commented 3 years ago

Did Alpha.9 fix this?

timlar commented 3 years ago

I tried with alpha.9 and it seems to work. At least shallowMount renders the component without errors. Thanks.

lmiller1990 commented 3 years ago

Seems like it's okay. Closing.

Can reopen if more issues arise.