jest-vue-preprocessor
jest-vue-preprocessor copied to clipboard
TypeScript support is unreliable
It feels a bit weird submitting an issue report against a feature for which I created a PR originally. Anyway...
It appears that TS support I hacked together originally is a bit flaky. It sometimes works and sometimes does not. Apparently, this has something to do with the fact that Vue.js dist contains different types of modules depending on how you import it, and the wrong type (CommonJS vs ESM) gets selected at runtime. TypeScript's compiler will make assumptions that don't hold true when the code is run. For example, it will assume that exports.default is defined by the module, when it's not, and so on.
Long story short, while you can write tests that work with TypeScript and Jest, the code may break when the same code is used with Webpack. I'm currently trying to hack together a workaround for this, but thus far, it's not looking very promising. It also feels wrong to hack around this issue as sooner or later community will realize that this issue is a thing, and may come up with their own solution that breaks this code.
For now, I suggest reverting the TS patches. I'll let you know if I have a promising fix some time in future.
@foxbunny thanks for your feedback, I have/had the same issues with Vue.js and Typescript, from a certain it get too complex and complicated with all the webpack tweaks (vue-loader, ts-awesome-loader which was at that time not supported)
Long story short, I'm convinced that using Vue with TS brings more trouble into the project than it solves. If someone want's to use TS I highly would recommend him TS + Angular which is fully supported or React/Redux + TS.
I generally don't have issues with Vue and TS combo as long as everything is being done by webpack (e.g., karma-webpack plugin works really well).
For anyone finding this bug report, I am able to work around the issues using the below Jest mock:
jest.setMock('vue', (() => {
const Vue = require('vue');
return {
default: Vue,
Vue
};
})());
TSConfig:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
"baseUrl": "",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"importHelpers": true,
"module": "es6",
"moduleResolution": "node",
"newLine": "LF",
"noEmitHelpers": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictNullChecks": true,
"target": "es5",
"lib": [
"dom",
"es5",
"es2015",
"es2016",
"es2017"
],
"paths": {
"src/*": [
"./src/*"
]
}
}
}
Jest configuration:
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,ts}",
"!src/*.{js,ts}",
"!src/**/*.spec.{js,ts}",
"!**/*.interface.ts",
"!src/test-lib/**/*.ts"
],
"collectCoverage": true,
"coverageReporters": [
"lcov"
],
"coverageDirectory": "./coverage",
"globals": {
"__TS_CONFIG__": "tsconfig.json",
"__TRANSFORM_HTML__": true
},
"moduleDirectories": [
"node_modules",
"<rootDir>/"
],
"moduleFileExtensions": [
"ts",
"js"
],
"moduleNameMapper": {
"^vue$": "vue/dist/vue.common.js"
},
"setupTestFrameworkScriptFile": "<rootDir>/src/setup-jest.ts",
"testRegex": "\\.spec\\.(ts|js)$",
"transform": {
".js$": "<rootDir>/node_modules/babel-jest",
".vue$": "<rootDir>/node_modules/jest-vue-preprocessor",
".ts$": "<rootDir>/node_modules/ts-jest/preprocessor"
}
}
Most issues I can get around by using vue.esm and letting babel-jest go into node_modules/vue. I have one big deal breaker however. The problem is illustrated in this jest test: https://github.com/blocka/strange-jest-behavior/blob/master/src/test.test.ts
Basically, in certain cases, the
The problem should be this line:
const transformedScript = script ? transforms[script.lang || 'babel'](script.content) : '';
Basically, the content of the script tag is handled over here, so things should fail in one of these circumstances:
- The content is not recognized correctly.
- There is no content at all, but only an external reference (which is allowed and valid - see attribute
src).
@foxbunny does it make sense to run the code through babel after TS? When everything is esm (jest is pointing to vue.esm, and typescript is generating es2015 modules), we wind up with a module that jest doesn't understand.
I'm not sure exactly when in the pipeline babel-jest kicks in, but seems that it is not in the right place. However, calling transformBabel right after compiling the TS will compile the module to commonjs (assuming the correct setting in .babelrc).
I've tried this out locally and it seems to solve all issues.
@blocka The ts-jest guys are doing something like that, and it seems to help. Probably why it worked for you as well.