使用 UseReducer 和 UseContext 反应测试库未正确更新状态

React Testing Library with UseReducer & UseContext not updating state properly

我创建了一个沙盒来概述主要兴趣点: https://codesandbox.io/s/restless-dawn-nwy0l

请忽略格式,因为这只是我放在一起的 MWE。

当我运行下面test在上面的沙盒

 
import React from "react";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";

import Statistics from "../src/components/Block/Statistics";
import { IAction, IState } from "../src/typings/AppTypes";
import { AppReducer } from "../src/reducers/AppReducer";
import { AppContext } from "../src/context/AppContext";
import * as MineUtil from "../src/utils/mine";
import * as ConversionUtil from "../src/utils/conversion";

const state: IState = {
  verifiedTrans: [
    {
      to: "A",
      from: "B",
      amount: 1.23,
      message: "First Transaction",
      signature: "AB1.23"
    },
    {
      to: "A",
      from: "C",
      amount: 456.78,
      message: "Second Transaction",
      signature: "AC456.78"
    },
    {
      to: "A",
      from: "D",
      amount: 999.99,
      message: "Third Transaction",
      signature: "AD999.99"
    },
    {
      to: "A",
      from: "E",
      amount: 987.65,
      message: "Forth Transaction",
      signature: "AE987.65"
    },
    {
      to: "A",
      from: "F",
      amount: 1.01,
      message: "Fifth Transaction",
      signature: "AF1.01"
    }
  ],
  selectedTrans: [
    {
      to: "A",
      from: "C",
      amount: 456.78,
      message: "Second Transaction",
      signature: "AC456.78"
    }
  ],
  chain: [
    {
      index: 0,
      prevHash: "",
      currHash: new Array(64).fill("0").join(""),
      transactions: [],
      timestamp: Date.parse("04/31/2021"),
      merkleRoot: "",
      valid: true
    },
    {
      index: 1,
      prevHash: new Array(64).fill("0").join(""),
      currHash: new Array(64).fill("A").join(""),
      transactions: [
        {
          to: "A",
          from: "E",
          amount: 987.65,
          message: "Forth Transaction",
          signature: "AE987.65"
        }
      ],
      timestamp: Date.parse("05/01/2021"),
      merkleRoot: "987.65EForthTransactionAE987.65A",
      valid: true
    }
  ],
  preview: {
    index: 2,
    timestamp: Date.parse("05/02/2021"),
    prevHash: new Array(64).fill("A").join(""),
    currHash: "",
    transactions: [],
    merkleRoot: "",
    valid: false
  }
};

const dispatch = (action: IAction) => AppReducer(state, action);

it("keeps mining button disabled after mining due to valid solution", async () => {
  const solution =
    "000a4fda363405b2796986a63e8cedde080e1f29ed774f5f93bd97c42b9a96fc0";
  const target =
    "000b4fda363405b2796986a63e8cedde080e1f29ed774f5f93bd97c42b9a96fc0";

  jest.spyOn(MineUtil, "createTarget").mockReturnValue(Promise.resolve(target));
  jest
    .spyOn(ConversionUtil, "digestMessage")
    .mockReturnValue(Promise.resolve(solution));

  render(
    <AppContext.Provider value={{ state, dispatch }}>
      <Statistics chain={false} />
    </AppContext.Provider>
  );

  expect(screen.getByRole("button", { name: /Block Mine/i })).toBeEnabled();

  // need to await state changes
  fireEvent.click(screen.getByRole("button", { name: /Block Mine/i }));
  await waitFor(() => {
    expect(screen.getByRole("button", { name: /Block Mine/i })).toBeDisabled();
  });

  await waitFor(() => {
    expect(
      screen.getByRole("textbox", { name: /Block Solution/i })
    ).toHaveClass("valid-solution");
  });
});

 
 

我得到:

该测试只是检查,如果您在选择交易后按下挖矿按钮,该按钮将被禁用,一旦 有效 解决方案被挖出,它就会 class更改,因此它变为绿色文本(对于此组件)。由于解决方案有效,该按钮也应保持禁用状态。

此外,预览块将变为绿色,但这超出了本单元测试的范围。

但是,状态预览块(确定解决方案输入文本框上的 class)似乎在测试环境中没有正确更新。在开发过程中,情况并非如此,一切都按预期进行。

任何suggestions/hints?

在您的测试中,您设置了 value, dispatch 的模拟版本,当您单击 Block mine 按钮时它不会触发更新。

但在实际代码中,在 App.tsx 中你使用了 useReducer 钩子(在深处它触发重新渲染并且新的道具通过 Context 传递给 Statistics)。

要修复它,只需使用 useReducer

模拟您的测试
  const Wrapper = () => {
    const [state, dispatch] = useReducer(AppReducer, inititalValues);

    return (
      <AppContext.Provider value={{ state, dispatch }}>
        <Statistics chain={false} />
      </AppContext.Provider>
    );
  };

  render(<Wrapper />);

inititalValues是第12行的变量state

工作沙箱here

输出: