Jest测试使用新版本18创建React APP index.js

5lwkijsr  于 2022-12-08  发布在  Jest
关注(0)|答案(2)|浏览(178)

我有这个index.js的React版本〈= 17。

import React from 'react';
import ReactDOM from 'react-dom';
import App from './views/App';
import reportWebVitals from './reportWebVitals';
import './assets/scss/app.scss';
import { BrowserRouter } from "react-router-dom";
import { Provider } from 'react-redux';
import store from "./store/index";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

这就是考验:

import React from "react";
import ReactDOM from "react-dom";
import App from "../views/App";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import store from "../store/index";

jest.mock("react-dom", () => ({ render: jest.fn() }));

describe('Test index.js', () => {
  it("Should render app without crashing", () => {
    const div = document.createElement("div");
    div.id = "root";
    document.body.appendChild(div);
    require('../index.js');
    expect(ReactDOM.render).toHaveBeenCalledWith(
      <React.StrictMode>
        <BrowserRouter>
          <Provider store={store}>
            <App />
          </Provider>
        </BrowserRouter>
      </React.StrictMode>,
      div
    );
  });
});

现在,对于版本18,我需要将ReactDOM.render迁移到createRoot

import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './views/App';
import reportWebVitals from './reportWebVitals';
import './assets/scss/app.scss';
import { BrowserRouter } from "react-router-dom";
import { Provider } from 'react-redux';
import store from "./store/index";

const container = document.getElementById('root');
const root = createRoot(container);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);

但难的是考验。
我试过

import React from "react";
import { createRoot } from 'react-dom/client';
import App from "../views/App";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import store from "../store/index";

describe('Test index.js', () => {

  it("Should render app without crashing", () => {
    const div = document.createElement("div");
    div.id = "root";
    document.body.appendChild(div);
    require('../index.js');
    expect(root.render).toHaveBeenCalledWith(
      <React.StrictMode>
        <BrowserRouter>
          <Provider store={store}>
            <App />
          </Provider>
        </BrowserRouter>
      </React.StrictMode>
    );
  });
});

但我得到了壳

Test index.js
    ✕ Should render app without crashing (10 ms)

  ● Test index.js › Should render app without crashing

    expect(received).toHaveBeenCalledWith(...expected)

    Matcher error: received value must be a mock or spy function

    Received has value: undefined

      13 |     document.body.appendChild(div);
      14 |     require('../index.js');
    > 15 |     expect(root.render).toHaveBeenCalledWith(
         |                         ^
      16 |       <React.StrictMode>
      17 |         <BrowserRouter>
      18 |           <Provider store={store}>

      at Object.<anonymous> (src/__tests__/index.test.js:15:25)

我也尝试在describe之前添加jest.mock("react-dom/client");

[...]
jest.mock("react-dom/client");

describe('Test index.js', () => {
[...]

但我得到

Test index.js
    ✕ Should render app without crashing (6 ms)

  ● Test index.js › Should render app without crashing

    TypeError: Cannot read properties of undefined (reading 'render')

      10 | const container = document.getElementById('root');
      11 | const root = createRoot(container);
    > 12 | root.render(
         |      ^
      13 |   <React.StrictMode>
      14 |     <BrowserRouter>
      15 |       <Provider store={store}>

      at Object.<anonymous> (src/index.js:12:6)
      at Object.<anonymous> (src/__tests__/index.test.js:17:5)

如何编写新index.js的测试?

pgky5nke

pgky5nke1#

最后我解开了:

import index from "../index";

describe('Test index.js', () => {

    it("Should render app without crashing", () => {
        expect(
            JSON.stringify(
              Object.assign({}, index, { _reactInternalInstance: 'censored' }),
            ),
          ).toMatchSnapshot();
    });
});

这是修改后的index.js文件:

const container = document.getElementById('root') || document.createElement('div');
const root = createRoot(container);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);
3lxsmp7m

3lxsmp7m2#

这将允许您渲染整个应用程序,减去index.html中实际包含的内容:
Index.tsx

// imports and stuff

export default function main(rootArg?: HTMLElement) {
  const root = ReactDOM.createRoot(rootArg ?? (document.getElementById("root") as HTMLElement));
  root.render(
    <React.StrictMode>
      // big stack of providers
      <App/>
    </React.StrictMode>,
  );
}
if (process.env.NODE_ENV !== "test") {
  // if we're not in test env, call main without args
  main();
}

然后在测试结束

// import main from index.tsx

test("entire app smoke test", async () => {
  render(<div id="root">fake root node</div>);
  await screen.findByText("fake root node");
  await act(async () => {
    main(screen.getByText("fake root node"));
  });
  // assert against what you expect to see here...
});

相关问题