vuejs / vue-jest

Jest Vue transformer
MIT License
748 stars 157 forks source link

Failed parse using external template #45

Open mazipan opened 6 years ago

mazipan commented 6 years ago

I used external template like :

<template
  src="vue2-simplert-core/simplert.html">
</template>

Success when building production file using vue-loader@13.7.0. But unit test failed to run using vue-jest@1.4.0

Here some snippet of my Jest configuration :

 "jest": {
    "mapCoverage": true,
    "coverageDirectory": "test/coverage",
    "moduleNameMapper": {
      "^vue$": "vue/dist/vue.common.js"
    },
    "moduleFileExtensions": [
      "js",
      "vue"
    ],
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
    }
  }

Error that I got is :

ENOENT: no such file or directory, open '~/project/src/vue2-simplert-core/simplert.html'

if I look into error message, it because pointing to my project root folder instead of node_modules folder.

Is there any missing from my side ?

Thanks for all response 👍

eddyerburgh commented 6 years ago

What's the absolute path of simplert.html?

mazipan commented 6 years ago

It's coming from other npm repository, so should be coming from node_modules folder.

eddyerburgh commented 6 years ago

Does this resolve correctly when you use vue-loader?

mazipan commented 6 years ago

Sure, working like charm... That's why I create this issue. Maybe my bad, because I am not familiar with Jest configuration. But I want to know from your side first. Maybe you have some suggestions.

eddyerburgh commented 6 years ago

This is a problem on our side we need to fix. At the moment, we only look for a src that is relative, not in node_modules

Thanks for bring it to my attention, I'll look to get a fix in place 🙂

laggingreflex commented 5 years ago

I'm using relative templates but I still have an issue. The templates do get parsed, but I think they're not "interpreted" correctly.

Repro: https://github.com/laggingreflex/repro-vue-jest-template

It works in the browser but running jest it gives this error

> jest
Cannot use <template> as component root element because it may contain multiple nodes.
 FAIL  src/test.js
  ● Test suite failed to run

Taking hint from the error, if I change my App/template.vue from

<template>
  <div>App</div>
</template>

to just

  <div>App</div>

the test passes, but that's not the correct format for template - the app doesn't work in the browser.

eddyerburgh commented 5 years ago

@laggingreflex can you open a new issue for this so that I can track it?

robwozniak commented 5 years ago

This is a problem on our side we need to fix. At the moment, we only look for a src that is relative, not in node_modules

Thanks for bring it to my attention, I'll look to get a fix in place

@eddyerburgh please check my PR and let me know what do you think :crossed_fingers: Sample scenario:

// TestComponent.spec.js

import { mount } from '@vue/test-utils'
import MyComponent from './MyComponent.vue'

describe('Sample test', () => {
  it('...', () => {
    const wrapper = mount(MyComponent)
    expect(...)
  })
  ...
})
// MyComponent.vue

<template src="@node/dependency/src/MyComponent.html"/>
<script src="@node/dependency/src/MyComponent.js"/>
// jest.config.js

module.exports = {
  'moduleNameMapper': {
    '^@node/dependency/(.*)$': '/node_modules/@node/dependency/$1',
    '^vue$': 'vue/dist/vue.common.js'
  },
  'moduleFileExtensions': [
    'js',
    'vue'
  ],
  'transform': {
    '^.+\\.js$': '/node_modules/babel-jest',
    '.*\\.vue$': '/node_modules/vue-jest'
  },
  'transformIgnorePatterns': ['/node_modules/dependency/node_modules']
}
vladiiliev commented 4 years ago

Hello guys. We have a project that is in a similar situation. This is part of our Webpack configuration (aliases section):

    resolve: {
        alias: {
            assets: path.join(process.cwd(), 'src/assets'),
            controllers: path.join(process.cwd(), 'src/controllers'),
            views: path.join(process.cwd(), 'src/views')
        }
    }

As we can see, each alias is a reference to the "src" directory. And this is how we use them in vue files:

<template>
    <div />
</template>

<script lang="ts" src="controllers/components/FieldClick.ts"></script>

OK, to use Jest we need to replicate the above case in a configuration. This is how it looks:

module.exports = {
    transform: {
        '^.+\\.[t|j]sx?$': '<rootDir>/node_modules/babel-jest',
        '^.+\\.vue$': '<rootDir>/node_modules/vue-jest'
    },
    modulePaths: ['<rootDir>/src'],
    moduleFileExtensions: ['ts', 'tsx', 'js', 'vue', 'json']
};

And the result after the transformation from "vue-jest" is: ENOENT, no such file or directory

Which is absolutely logical, judging by these lines of code in "vue-jest/lib/process":

parts.script.content = fs.readFileSync(join(filePath, '..', parts.script.src), 'utf8')

To the authors: You need to rethink your code to cover cases like ours. moduleNameMapper is useless in the above case if you think it will be useful.

WORKAROUND

We created a file (vue-jest.js) that replicates the function from "vue-jest/lib/process" with the following content:

const process = require('vue-jest/lib/process');
const path = require('path');

module.exports = {
    process: (src, filePath, jestConfig) => {
        return process(src, path.join(jestConfig['modulePaths'][0], path.basename(filePath)), jestConfig);
    }
};

Then in the jest configuration, we just refer to this file:

transform: {
        '^.+\\.[t|j]sx?$': '<rootDir>/node_modules/babel-jest',
        '^.+\\.vue$': '<rootDir>/vue-jest.js'
    },

Now it works like a charm! I hope it helps someone.

GadQ commented 4 years ago

I have the same issue with aliast in src of the template in vue-jest 3.0.6 (and I believe 4.x will have the same problem)

In index.vue I have:

<template src="@components/template.html" />

package.json:

{
  "scripts": {
    "start": "webpack-dev-server",
    "test": "jest",
    "tdd": "jest --watch"
  },
  "repository": "GadQ/vue-jest-template-alias",
  "dependencies": {
    "vue": "^2.6.10"
  },
  "devDependencies": {
    "babel-core": "7.0.0-bridge.0",
    "jest": "^26.4.1",
    "vue-jest": "^3.0.6",
    "vue-loader": "^15.7.0",
    "vue-template-compiler": "^2.6.10",
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.1",
    "webpack-dev-server": "^3.3.1"
  }
}

jest.config.js:

module.exports = {
  moduleFileExtensions: [ 'js', 'vue' ],
  transform: {
    '^.+\\.vue$': 'vue-jest'
  },
  moduleNameMapper: {
    '^vue$': 'vue/dist/vue.js',
    '^@components/(.*)$': '<RootDir>/components',
  },
  collectCoverage: true,
  collectCoverageFrom: [
    'src/**/*.{js,vue}'
  ]
}

When I run the test I get: ENOENT: no such file or directory, open '/home/xyz/template-alias/src/App/@components/template.html'

Alias isn't resolved, but added as relative to tested index.vue directory path.

When i use relative path test works i.e.

<template src="./components/template.html" />

Besides that webpack/vue-loader doesn't have any problem with path with alias and build project correctly.

Reproduction repository: https://github.com/GadQ/vue-jest-template-alias.