Mocha test error is thrown when rendering MUI component in jsdom using React Testing Library
P粉946437474
P粉946437474 2024-01-16 13:49:47
0
1
490

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?

P粉946437474
P粉946437474

reply all(1)
P粉745412116

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 they cache.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 or yarn add @emotion/react

The code should look like this:

This is dummyComponent.js using more familiar JSX syntax:

const React = require('react');
const { Box } = require('@mui/material');

const DummyComponent = (props) => {
  const { children } = props;
  const [showChild, setShowChild] = React.useState(false);

  return (
    <Box>
      <label htmlFor="toggle">Show/Hide</label>
      <input
        id="toggle"
        type="checkbox"
        onChange={(e) => setShowChild(e.target.checked)}
        checked={showChild}
      />
      {showChild && children}
    </Box>
  );
};

export default DummyComponent;

This is the mocha unit test:

const React = require('react');
const { expect } = require('chai');
const { render, fireEvent } = require('@testing-library/react');
const createCache = require("@emotion/cache");

const DummyComponent = require('./dummyComponent');

describe('pageCenter', function () {
  before(function () {
    this.jsdom = require('global-jsdom')();
  });

  after(function () {
    this.jsdom();
  });
  
  const myCache = createCache({
   key: 'my-prefix-key'
  });

  it('should render', function () {
    const { queryAllByText, getByLabelText } = render(
      <CacheProvider value={myCache}>          
        <DummyComponent>Hi!</DummyComponent>
      </CacheProvider>
    );

    expect(queryAllByText('Hi!')).should.have.length(0);
    fireEvent.click(getByLabelText('Show/Hide'));
    expect(queryAllByText('Hi!')).should.have.length(1);
  });
});

Note that I'm also using some JSX syntax in the test case and const { expect } = require('chai');, which allows me to use should and Chain call other functions from chai.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template