keyz / identity-obj-proxy

An identity object using ES6 proxies. Useful for mocking webpack imports like CSS Modules.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

@keyanzhang

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

@keyanzhang

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");
});

With "esModuleInterop": true the result is:
image

With "esModuleInterop": false the result is:
image

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"
}