简体   繁体   English

使用 React-Test-Renderer 测试嵌套的 React 组件

[英]Testing of Nested React components using React-Test-Renderer

I have a pure React-Redux application and it is working as expected.我有一个纯 React-Redux 应用程序,它按预期工作。

The App.js App.js

import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import { Router, Route, Switch, Redirect } from "react-router-dom";

import history from "../history";
import LandingPage from "./home/LandingPage";
import { displayModules } from "../actions";
import Cart from "./home/Cart";

const App = () => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(displayModules());
  }, [dispatch]);

  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={LandingPage}></Route>
        <Route path="/cart" exact component={Cart}></Route>
        <Route render={() => <Redirect to="/" />} />
      </Switch>
    </Router>
  );
};

export default App;

The LandingPage has a nested component called Tile. LandingPage有一个名为 Tile 的嵌套组件。

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import Tile from "../common/Tile";

import { addItemToCart, displayCartContents } from "../../actions";
import "./LandingPage.css";

const LandingPage = () => {
  const modules = useSelector(state => state.data.modules);
  const cart = useSelector(state => state.data.cart);
  const dispatch = useDispatch();
  const addToCart = item => {
    dispatch(addItemToCart(item));
  };
  return (
    <div className="app">
      <div className="header">
        <div className="text">Insurance modules</div>
        <i
          className="shopping cart icon"
          onClick={() => {
            dispatch(displayCartContents());
          }}
        >
          <span className="badge">{cart.length}</span>
        </i>
      </div>
      <div className="body">
        {modules.map(module => (
          <Tile key={module.id} module={module} addToCart={addToCart}></Tile>
        ))}
      </div>
    </div>
  );
};

export default LandingPage;

Tile.js has a button which I want to test. Tile.js有一个我想测试的按钮。

import React, { useState } from "react";

import "./Tile.css";

const Tile = props => {
  const { module, addToCart } = props;
  const [coverage, setCoverage] = useState(parseInt(module.coverageMax - module.coverageMin) / 2);
  const [price, setPrice] = useState((coverage * module.risk) / 100);
  return (
    <div className="tile">
      <div className="tile-description">
        <div>
          <i className={`${module.icon} icon`}></i>
        </div>
        <div className="tile-name">{module.name}</div>
        <div className="tile-risk">Risk(%): {module.risk}</div>
      </div>
      <div className="tile-footer">
        <div className="tile-range">
          <div className="field-label">
            Select Coverage: <span className="coverage-display">{coverage}</span>
          </div>
          <div className="slidecontainer">
            <span className="slider-step">{module.coverageMin}</span>
            <input
              type="range"
              min={module.coverageMin}
              max={module.coverageMax}
              value={coverage}
              className="slider"
              onChange={e => {
                setCoverage(e.target.value);
                setPrice((e.target.value * module.risk) / 100);
              }}
            ></input>
            <span className="slider-step">{module.coverageMax}</span>
          </div>
        </div>
        <div>
          PRICE at this Coverage:<span className="tile-price">{price}</span>
        </div>

        <button
          className="tile-button"
          onClick={() => {
            addToCart({
              id: module.id,
              name: module.name,
              coverage: coverage,
              price: price,
              timeStamp: Math.ceil(new Date().getTime() * Math.random() * Math.random())
            });
          }}
        >
          Add module to cart
        </button>
      </div>
    </div>
  );
};

export default Tile;

App.test.js works fine and I am able to find the nested Landing Page div by className prop. App.test.js工作正常,我可以通过 className属性找到嵌套的着陆页 div。

import React from "react";
import configureStore from "redux-mock-store";
import { Provider } from "react-redux";
import renderer from "react-test-renderer";

import App from "../components/App";
import history from "../history";
import { displayModules } from "../actions";
import { DISPLAY_MODULES } from "../actions/types";

const mockStore = configureStore([]);

describe("App Component test", () => {
  let store = {};
  let wrappedComponent = {};
  const expectedActions = {
    type: DISPLAY_MODULES,
    payload: [
      {
        id: 0,
        icon: "bicycle",
        name: "Bike",
        coverageMin: 0,
        coverageMax: 3000,
        risk: 30
      },
      {
        id: 1,
        icon: "gem",
        name: "Jewelry",
        coverageMin: 500,
        coverageMax: 10000,
        risk: 5
      },
      {
        id: 2,
        icon: "microchip",
        name: "Electronics",
        coverageMin: 500,
        coverageMax: 6000,
        risk: 35
      },
      {
        id: 3,
        icon: "football ball",
        name: "Sports Equipment",
        coverageMin: 0,
        coverageMax: 20000,
        risk: 30
      }
    ]
  };
  beforeEach(() => {
    store = mockStore({
      data: {
        modules: [],
        cart: [],
        total: 0
      }
    });
    store.dispatch = jest.fn(displayModules);
    wrappedComponent = renderer.create(
      <Provider store={store}>
        <App />
      </Provider>
    );
  });

  it("should render with given state from Redux store", () => {
    expect(wrappedComponent.toJSON()).toMatchSnapshot();
  });
  it("should have an app from Landing Page", () => {
    expect(wrappedComponent.root.findByProps({ className: "app" })).toBeDefined();
  });

  it("should show landing page for default route", () => {
    *debugger;
    expect(wrappedComponent.root.findByProps({ className: "shopping cart icon" })).toBeDefined();*
  });
  it("should show cart page for /cart route", () => {
    history.push("/cart");
    expect(wrappedComponent.root.findByProps({ className: "backward icon" })).toBeDefined();
  });
  it("should redirect to landing page for unmatched 404 routes", () => {
    history.push("/someRandomRoute");
    expect(wrappedComponent.root.findByProps({ className: "shopping cart icon" })).toBeDefined();
  });
  it("should dispatch displayModules action on app mount", async () => {
    const actualAction = await store.dispatch();
    expect(actualAction).toEqual(expectedActions);
  });
});

But If you see the test debugger但是如果你看到测试调试器在此处输入图片说明

The children of div with className: body has no children. className: body的 div 的孩子没有孩子。 That is why it is not able to find the Tile component.这就是为什么它无法找到 Tile 组件的原因。 Can you suggest why the children are null for the body?你能建议为什么孩子们对身体来说是空的吗? I have seen this before, even i tried with Enzyme i faced this issue.我以前见过这个,即使我尝试使用 Enzyme 我也遇到了这个问题。 Since it is a Redux wrapped component the , i cant directly create the Landing page or Tile component for testing.由于它是一个 Redux 包装的组件,因此我无法直接创建登陆页面或 Tile 组件进行测试。 How to test the nested items?如何测试嵌套项?

You are providing an empty array to modules inside redux state:您正在为 redux 状态中的模块提供一个空数组:

store = mockStore({
  data: {
    modules: [], // your modules is empty so no tiles will render
    cart: [],
    total: 0
  }
});

Another issue is that you mock store.dispatch so it no longer changes the redux store even if some action is dispatched:另一个问题是您模拟 store.dispatch 以便即使调度了某些操作它也不再更改 redux 存储:

store.dispatch = jest.fn(displayModules);

If you want to test that an action was dispatched you can use:如果你想测试一个动作是否被调度,你可以使用:

const actions = store.getActions()

Which will give you all actions which were dispatched.这将为您提供已调度的所有操作。

If you want to test how your app renders based on your store data you can either:如果您想根据商店数据测试应用程序的呈现方式,您可以:

  1. Setup the store in the test:在测试中设置商店:
const existingModules = [ ... ]; // list of modules
store = mockStore({
  data: {
    modules: existingModules, 
    cart: [],
    total: 0
  }
});
  1. You can mock useSelector in your test:您可以在测试中模拟 useSelector:
const existingModules = [ ... ]; // list of modules
const spy = jest.spyOn(redux, 'useSelector')
spy.mockReturnValue(existingModules)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用react-test-renderer进行快照测试 - snapshot testing with react-test-renderer 使用 react-test-renderer 测试异步 componentDidMount() - Testing async componentDidMount() with react-test-renderer 如何使用@testing-library/react 和 react-test-renderer 测试由 Redux 状态控制的输入值? - how to test input value controlled by Redux state using @testing-library/react and react-test-renderer? 使用带有样式组件和主题的 react-test-renderer (React Native) - Using react-test-renderer w/ styled-components & Theme (React Native) 将 react-test-renderer 与 react-testing-library 一起使用有什么意义吗? - Is there any point for using react-test-renderer with react-testing-library? 测试 Formik 使用 react-test-renderer 验证 function - Testing Formik validate function with react-test-renderer 使用 react-test-renderer<Switch> 导致“无状态功能组件无法提供参考”警告 - Using react-test-renderer with <Switch> causes "Stateless function components cannot be given refs" warning 使用Jest和React-test-renderer测试伪类 - Test for pseudo class using Jest and React-test-renderer react-test-renderer不正确的对等依赖 - react-test-renderer incorrect peer dependency 为什么react-test-renderer在React中只能在同一个文件中findByType功能组件? - Why can react-test-renderer only findByType functional components in the same file in React?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM