Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

undefined returned when using typescript with jest #9

Closed
abhishek-raj opened this issue Oct 15, 2018 · 12 comments
Closed

undefined returned when using typescript with jest #9

abhishek-raj opened this issue Oct 15, 2018 · 12 comments

Comments

@abhishek-raj
Copy link

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.

@keyz
Copy link
Owner

keyz commented Oct 16, 2018

Hi @abhishek-raj. Could you create a repository which I can clone, install, and repro? Thanks

@infctr
Copy link

infctr commented Oct 19, 2018

@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

@abhishek-raj
Copy link
Author

@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.

@kuznetsov-from-wonderland

Hi all! I have the same issue. Do you need my repo to check?

@andribo
Copy link

andribo commented Nov 17, 2018

@abhishek-raj Did you try to enable "esModuleInterop" property in your tsconfig.json?

"esModuleInterop": true,

@bthurlow
Copy link

@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.

@abhishek-raj
Copy link
Author

@bthurlow Yes I am testing against the spfx. Guess we have to wait till they upgrade the typescript version.

@aaronbeall
Copy link

@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

@aaronbeall
Copy link

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.

@flocbit
Copy link

flocbit commented Mar 7, 2019

@aaronbeall there is a workaround for importing with import * as styles from './Styles.css'. Check out #8 (comment)

@abhishek-raj
Copy link
Author

abhishek-raj commented May 16, 2019

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.

andrewconnell added a commit to Voitanos/jest-preset-spfx-react16 that referenced this issue Oct 6, 2019
- added `exModuleInterop` to tsconfig.json
- references keyz/identity-obj-proxy#9 (comment)
- fixes #8
andrewconnell added a commit to Voitanos/jest-preset-spfx-react15 that referenced this issue Oct 6, 2019
- added `exModuleInterop` to tsconfig.json
- references keyz/identity-obj-proxy#9 (comment)
@Link631
Copy link

Link631 commented Nov 27, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants