undefined returned when using typescript with jest
abhishek-raj opened this issue · comments
I am using jest with typescript in my projects. I am getting undefined for all my .ts files using identity-obj-proxy but .js files work as expected.
This is my tsconfig.json:
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"lib"
]
}
This is my jest configuration:
"jest": {
"unmockedModulePathPatterns": [
"React"
],
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(d\\.ts|ts|tsx)$": "ts-jest"
},
"testMatch": [
"**/src/**/*.test.+(ts|tsx|js)"
],
"setupFiles": [
"raf/polyfill"
],
"collectCoverage": true,
"coverageReporters": [
"json",
"lcov",
"text",
"cobertura"
],
"coverageDirectory": "<rootDir>/jest",
"collectCoverageFrom": [
"**/*.{ts,tsx}",
"!**/*.d.{ts,tsx}",
"!**/*.scss.ts",
"!**/models/**",
"!**/node_modules*/**"
"!**/services/http.ts"
],
"moduleNameMapper": {
"\\.(css|less|scss|sass)$": "identity-obj-proxy",
"^resx-strings/en-us.json": "<rootDir>/node_modules/@microsoft/sp-core-library/lib/resx-strings/en-us.json"
},
"reporters": [
"default",
"jest-junit"
],
"coverageThreshold": {
"global": {
"branches": 50,
"functions": 75,
"lines": 75,
"statements": 75
}
}
}
My test file(.ts):
import styles from './Somefile.module.scss';
describe('Test identity proxy', () => {
test('undefined returned', () => {
expect(styles.notundefined).toBe(undefined);
}
});
If I save the file as .js then everything seems to work but not in .ts or .tsx files.
Hi @abhishek-raj. Could you create a repository which I can clone, install, and repro? Thanks
https://github.com/infctr/ts-jest-object-proxy
About repro:
Jest moduleNameMapper
settings are specified in config-overrides.js
file, react-app-rewire
tweaks jest settings b/c CRA config filters keys that are not allowed.
Adding this line results in missing classnames in the snapshot config.moduleNameMapper = { '\\.styles$': 'identity-obj-proxy' };
It does work with css modules files tho
This is repro:
https://github.com/abhishek-raj/identity-obj-proxy-issue9
The HelloWorld.test.tsx from src/webparts/helloWorld/tests/HelloWorld.test.tsx has a import of styles object which should be replaced with obj-identity-proxy but for some reason it does not as you can see from the tests.
Hi all! I have the same issue. Do you need my repo to check?
@abhishek-raj Did you try to enable "esModuleInterop"
property in your tsconfig.json
?
"esModuleInterop": true,
@abhishek-raj It looks like you're testing against SPFx. I had the same issue as well and attempted @andribo solution, which made identity-obj-proxy work as expected, however, that caused the project to not build as "esModuleInterop"
is not supported under SPFx.
I ended up having to mock my scss, here's the mock that I used inside my test file.
jest.mock('FileName.module.scss',()=>{
return {default:{
shimmer:'shimmer',
container:'container',
row:'row',
column:'column',
title:'title',
subTitle:'subTitle',
description:'description',
button:'button',
label:'label'
}};
});
So it looks like we're stuck with manual mocks inside SPFx testing until they upgrade the typescript version inside gulp build. Hope this helps.
@bthurlow Yes I am testing against the spfx. Guess we have to wait till they upgrade the typescript version.
@andribo I'm confused... you suggest trying "esModuleInterop": true
, but in my case everything was working without that, but when I set "esModuleInterp": true
then I ran into the issue described here.
In other words, in a new project:
npm install typescript jest ts-jest @types/jest identity-obj-proxy
jest config:
"jest": {
"preset": "ts-jest",
"moduleNameMapper": {
"\\.css$": "identity-obj-proxy"
}
}
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"esModuleInterop": true
}
test.spec.ts:
import * as styles from "./test.css";
test("obj proxy", () => {
expect(styles.foo).toEqual("foo");
expect(styles.bar).toEqual("bar");
});
So it appears that with esModuleInterop
the namespace imports do not work with identity-obj-proxy
, even though it does work with TS and the bundled code. In other words:
import * as styles from "./Styles.css"
console.log(styles.foo)
// "Styles__foo__{hash}" in browser
// "undefined" in Jest
import styles from "./Styles.css"
console.log(styles.foo)
// "Styles__foo__{hash}" in browser
// "foo" in Jest -- good
I don't know nearly enough about the inner workings of this library to understand this behavior or if there's anything that can be done about it, but it's certainly an undesirable pitfall.
@aaronbeall there is a workaround for importing with import * as styles from './Styles.css'
. Check out #8 (comment)
Marking it closed as this is working with latest SPFx 1.8.0 and TypeScript 3.3(This is the version I tested - should work with any typescript version after 2.7 which supports esModuleInterop). Need to use "esModuleInterop": true
in the tsconfig.
Hi everyone. I am dependeing on Typescript 2.4.2.
How can i get scss evaluated within my jest tests?
The Configuration with moduleNameMapper here does not work. My scss varaibles are all undefined within a testrun. Is it possible, that the expression under moduleNameMapper simply does not hit filese like: my.module.scss ?
"jest": {
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\.(ts|tsx)$": "ts-jest"
},
"testMatch": [
"/src//*.test.+(ts|tsx|js)"
],
"moduleNameMapper": {
\.(css|less|scss|sass)$": "identity-obj-proxy
}
},
"jest-junit": {
"output": "./jest/summary-jest-junit.xml"
}