Home  >  Q&A  >  body text

Mocha test error is thrown when rendering MUI component in jsdom using React Testing Library

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粉946437474P粉946437474299 days ago447

reply all(1)I'll reply

  • P粉745412116

    P粉7454121162024-01-17 00:03:09

    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.

    reply
    0
  • Cancelreply