Fighting with Jest / React / Babel / TypeScript / etc.
This is just a rant when the tests of my project suddenly stop working after I upgrade react and react testing library to latest version. I’m getting the error TypeError: actImplementation is not a function with below setup
- react: 18.2.0
- react-dom: 18.2.0
- jest: 29.5.0
- @testing-library/react: 14.0.0
and many more deps and dev-deps that are not super relevant to my issue
TL;DR: It has nothing to do with version conflict. Rather it was me being silly and overlooked the global mock. In my defence, it was not very obvious at first 😛
Starting from scratch
After much hair scratching and head-banging, I decide to re-setup everything from scratch, to see where it might go wrong. I don’t use any utility scripts to bootstrap the project (e.g create-react-app), as they will often obfuscate some interesting details.
I simply bootstrap the project with npm init
, no framework, no typescript, plain and clean.
Then following the guide https://jestjs.io/docs/tutorial-react#setup-without-create-react-app, I install recommended dependancies for babel and jest
npm install — save-dev babel-jest @babel/core @babel/preset-env
npm install --save-dev jest @babel/preset-react
and add the babel config file as per instruction
//babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
Moment of truth, I write a very simple test to see if my setup works
import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
describe("a", () => {
it("asdf", () => {
render(<div />);
});
});
Well, sure enough, it … doesn’t.
N.B: if the error similar to the one below pops up, it’s likely that the preset @babel/preset-react
is missing in the babel config file
Configure Jest
The error was ReferenceError: document is not defined, so obviously I need to tell jest that I’m running test in the DOM environment. So I go head installing the required package and create a jest config file
npm i -D jest-environment-jsdom
// jest.config.js
const config = {
testEnvironment: "jsdom",
};
module.exports = config;
This time, the test run fine!
But when I copy over the exact babel and jest config to my original project, the test still fails, I wonder why …
‘Ah ha’ moment
So there must be something interfering with react-dom/test-utils
module.
Turn out, in my old project, there was a workaround for the previous version of the react-testing-library. It was to mock the react-dom/test-utils module because of some old bugs in the library🤦♂
// __mocks__/react-dom/test-utils.js
// @see https://github.com/testing-library/react-testing-library/issues/315
module.exports = {};
That was the problem because under the hood of latest @testing-library/react
version, it uses the act
function from the react-dom/test-utils
.
How about typescript
Since I’ve got that far, I decide to install typescript on my test project to see what would happen. (TBD)
Moral of the story
- I think “starting-from-scratch” approach is very helpful when debugging a mysterious issue. You can eliminate a lot of uncertainty, and also relearn things that you think you already know.
- When working with any test framework, know exactly what have been mocked, and where are those mocks being setup! This is super important because there’re so many different ways to mock a module.