Because enzyme
is not maintained and does not support react 18, I am trying to migrate 1750+ existing unit tests to react-testing-library
global- jsdom
to run so our application can continue to run the latest version of react. All of our tests are written using mocha
, chai
, enzyme
and I want to make migration as easy as possible. In other words, I would never rewrite 1750+ tests in a completely new framework like jest
.
I'm trying to follow the example of using react-testing-library
to unit test a react component. If I use simple elements like 'div'
or 'input'
when using React.createElement
it works fine, but when I use When using material UI components, an error occurs:
TypeError: Cannot read property of null (read "registered") In C:\Users\user\Documents\project\node_modules@emotion\styled\base\dist\emotion-styled-base.cjs.dev.js:143:53
The above error occurred in the <Styled(div)> component:
at C:\Users\user\Documents\project\node_modules\@emotion\react\dist\emotion-element-b63ca7c6.cjs.dev.js:43:23 at Box (C:\Users\user\Documents\project\node_modules\@mui\system\createBox.js:29:41) at DummyComponent (C:\Users\user\Documents\project\act-app\src\component\page\dummyComponent.js:2:346)Consider adding error boundaries to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries. The stack trace is not accurate, but it fails when I try to do
h(Box, {},...)
(create mui element).
This is the dummyComponent.js
I'm trying to render:
const { Box } = require('@mui/material'); const React = require('react'); const h = React.createElement; const DummyComponent = (props) => { const { children } = props; const [showChild, setShowChild] = React.useState(false); return ( h(Box, {}, h('label', { htmlFor: 'toggle' }, 'Show/Hide'), h('input', { id: 'toggle', type: 'checkbox', onChange: (e) => setShowChild(e.target.checked), checked: showChild }), showChild && children) ); }; module.exports = DummyComponent;
This is the mocha unit test:
const React = require('react'); const { render, fireEvent } = require('@testing-library/react'); const h = React.createElement; const DummyComponent = require('./dummyComponent'); describe('pageCenter', function () { before(function () { this.jsdom = require('global-jsdom')(); }); after(function () { this.jsdom(); }); it('should render', function () { const w = render(h(DummyComponent, {}, 'Hi!')); w.queryAllByText('Hi!').should.have.length(0); fireEvent.click(w.getByLabelText('Show/Hide')); w.queryAllByText('Hi!').should.have.length(1); }); });
It feels like I'm missing some context to allow the MUI component to render, but I can't seem to figure out what, or if this is actually the issue. There aren't many Google results for this specific error. Any ideas?
According to the dependencies of the MUI library, I found that they use @emotion/react and @emotion/styled in some rendering processes, which seems to be an issue with MUI v5 , they changed the cache object and accidentally deleted the cache object provided by @emotion/react, which resulted in a
TypeError: Cannot read property 'registered' of undefined
error because theycache.registered
is not added to the new cache.Solution: I solved this problem by wrapping the @emotion/react provider ({my component}) in my component. You can try following the example provided by @emotion.react: https://emotion.sh/docs/cache-provider
Also make sure the dependencies from @emotion/react are installed correctly by running:
npm install --save @emotion/react
oryarn add @emotion/react
The code should look like this:
This is dummyComponent.js using more familiar JSX syntax:
This is the mocha unit test:
Note that I'm also using some JSX syntax in the test case and
const { expect } = require('chai');
, which allows me to useshould
and Chain call other functions from chai.