ts-jest: jest.mock() makes module undefined when importing it no matter what we return in factory function

./src/StatelessComponent.tsx

import * as React from 'react';
import ChildComponent from './ChildComponent';

const StatelessComponent = () => (
  <div>  
    <ChildComponent />
  </div>
);

export default StatelessComponent;

./src/ChildComponent.tsx

import * as React from 'react';

const ChildComponent = () => (<b>Hello</b>);

export default ChildComponent;

./__tests__/StatelessComponent.test.tsx

jest.mock('../src/ChildComponent', () => 'ChildComponent');

// rest of the test here

When running the test in TS, ChildComponent is undefined. When running the test in ES6, ChildComponent is defined.

Can be related to this issue in Jest repo: https://github.com/facebook/jest/issues/2984

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 6
  • Comments: 27 (3 by maintainers)

Most upvoted comments

Ok I have a solution (actually my genius coworker @junseld found it).

It appears to have something to do with the way import/export behaves in Typescript compared to ES6.

Instead of this:

jest.mock('../src/ChildComponent', () => 'ChildComponent');

Do this:

jest.mock('../src/ChildComponent', () => {
  return {
    'default': 'ChildComponent'
  }
});

I guess default export in ES6 allows the exported value to be imported directly, but Typescript creates a named export called “default”. So your mock needs to be an object with a default key: {default: theDefaultExport}

This is still an issue in 2022.

To mock an ES6 dependency module default export using jest:

Instead of:

jest.mock('../src/ChildComponent', () => 'ChildComponent');

What worked for me was:

import ChildComponent from '../src/ChildComponent';
jest.mock('../src/ChildComponent');
ChildComponent.mockImplementation(() => 'ChildComponent');

The other options didn’t work for me.

Maybe we can update the ts-jest documentation to warn users about the differences in mocking compared to ES6?

I ask to reopen this issue due to lacking documentation / warnings of this issue.

The fact that create-react-app-typescript by default creates projects where mocking as documented doesn’t work is a big problem that had me stumbled for hours.

That problem wouldn’t be as dire if ts-jest detected that a combination of typescript configs and jest.mock with second parameter function that returns a undefined and gave a proper warning/error message. This case might be where import '' in typescript never returns a undefined either way (not sure about dynamic import tho).

Hey, I encounter similar issue. @adrifmonte when you do jest.mock(‘…/src/ChildComponent’); and ChildComponent.mockImplementation(() => ‘ChildComponent’); , does it show ts error saying that ‘mockImplementation does not exist on type ChildComponent’ . Please let me know

@dmngu9 be sure to NOT have skipBabel: true in globals > ts-jest of jest configuration, else jest.mock calls won’t be hoisted. Also you can try adding esModuleInterop: true to your tsconfig.json if you have other issues like the original one of this thread.

+1000

+1 in late 2023; running into this issue while trying to mock an RTK Query Api

@bhouser thanks.

The tests in the typescript directory of the linked repo pass if "allowSyntheticDefaultImports": true is added to tsconfig.json

+1000

I’ve just tried (within the repo with the changes I sent above):

diff --git a/typescript/src/__mocks__/ChildComponent.tsx b/typescript/src/__mocks__/ChildComponent.tsx
new file mode 100644
index 0000000..1263b16
--- /dev/null
+++ b/typescript/src/__mocks__/ChildComponent.tsx
@@ -0,0 +1 @@
+export default jest.fn(() => 'ChildComponent')
\ No newline at end of file
diff --git a/typescript/src/__tests__/ParentComponent_test.tsx b/typescript/src/__tests__/ParentComponent_test.tsx
index 4a79a8f..12a1e2a 100644
--- a/typescript/src/__tests__/ParentComponent_test.tsx
+++ b/typescript/src/__tests__/ParentComponent_test.tsx
@@ -1,9 +1,9 @@
-jest.mock('../ChildComponent', () => 'ChildComponent');
-
 import * as React from 'react';
 import * as renderer from 'react-test-renderer';
 import ParentComponent from "../ParentComponent";
 
+jest.mock('../ChildComponent');
+
 test('renders correctly', () => {
     const tree = renderer.create(
         <ParentComponent />
diff --git a/typescript/src/__tests__/__snapshots__/ParentComponent_test.tsx.snap b/typescript/src/__tests__/__snapshots__/ParentComponent_test.tsx.snap
new file mode 100644
index 0000000..2289842
--- /dev/null
+++ b/typescript/src/__tests__/__snapshots__/ParentComponent_test.tsx.snap
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div
+  className="parentComponent"
+>
+  ChildComponent
+  ;
+</div>
+`;

as well as:

diff --git a/typescript/src/__tests__/ParentComponent_test.tsx b/typescript/src/__tests__/ParentComponent_test.tsx
index 4a79a8f..01c2b1b 100644
--- a/typescript/src/__tests__/ParentComponent_test.tsx
+++ b/typescript/src/__tests__/ParentComponent_test.tsx
@@ -1,8 +1,12 @@
-jest.mock('../ChildComponent', () => 'ChildComponent');
-
 import * as React from 'react';
 import * as renderer from 'react-test-renderer';
 import ParentComponent from "../ParentComponent";
+import ChildComponent from '../ChildComponent';
+
+jest.mock('../ChildComponent');
+
+(ChildComponent as jest.Mock).mockImplementation(() => 'ChildComponent')
+
 
 test('renders correctly', () => {
     const tree = renderer.create(

they both work