Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: Cannot read property 'render' of undefined in Jest test using ReactDOM

Tags:

webpack

jestjs

I'm trying to add Jest support for testing code in my webpack based application. I think I have the basic configuration right, as a non-component based test (like 'adds numbers' below) passes. However, when I try to interact with the DOM, an error results. I'm trying a variation of the smoketest scenario described in the create-react-apps docs docs (Test components section). My test file look like this:

import React from 'react';
import ReactDOM from 'react-dom';

it('adds number', () => {
  expect(2 + 2).toBe(4);
});

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<div/>, div);
});

and the output is:

v adds number (10ms)

× renders without crashing (3ms)

renders without crashing

TypeError: Cannot read property 'render' of undefined

 44 | it('renders without crashing', () => {
 45 |   const div = document.createElement('div');
 46 |   ReactDOM.render(<div/>, div);
    |            ^
 47 | });
  at Object.<anonymous> (/pathto/TestFile.test.tsx:46:12)

My application is not built with create-react-app. Instead I tried to follow the instructions in Jest webpack documentation, modifying it in support of Typescript. Should I expect the sample 'renders without crashing' to work in my application? Do I need to set any browser Jest configuration to support this? This is the main configuration in my package.json related to Jest:

"jest": {
  "roots": [
    "src/app/react"
  ],
  "moduleNameMapper": {
    "\\.(css)$": "identity-obj-proxy"
  },
  "transform": {
    "^.+\\.tsx?$": "ts-jest",
    "^.+\\.(js|jsx)$": "babel-jest",
    ".+\\.(scss)$": "./node_modules/jest-css-modules-transform"
  },
  "moduleFileExtensions": [
    "js",
    "ts",
    "tsx"
  ]
},
like image 980
Notre Avatar asked Jan 02 '23 02:01

Notre


2 Answers

Add this to your tsconfig.json:

{
  "compilerOptions": {
    ...
    "esModuleInterop": true
  },
  ...
}

Details

The issue stems from how this line is transpiled:

import ReactDOM from 'react-dom';

That line means import the default export from the react-dom module as ReactDOM.

react-dom ships as a CommonJS module so technically it doesn't have a default export.

Setting the esModuleInterop flag to true lets you import its single exported value as if it was the default export of a TypeScript or ES6 module.

like image 137
Brian Adams Avatar answered Jan 03 '23 14:01

Brian Adams


If you don't want to add esModuleInterop config for some reason, the correct syntax to import a module in TypeScript as a single name is:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
like image 34
Mohamed Radhi Guennichi Avatar answered Jan 03 '23 14:01

Mohamed Radhi Guennichi