javascript - 使用 react 测试库从 Jest 测试访问和修改 react 上下文

标签 javascript reactjs jestjs react-testing-library react-context

我已经为此奋斗了几天,但我无法找到正确的方法来完成我需要的事情。 基本上我有一个上下文,提供从 API 获取的主题。上下文具有主题、加载以及获取和更新加载状态的函数的值。看起来像这样:


import React, { useState } from "react";

import ThemeService from "../services/GetThemes";

const AvailableThemesContext = React.createContext();
const { Provider, Consumer } = AvailableThemesContext;

const ThemesProvider = ({ children }) => {
  const [contextTheme, setTheme] = useState({});
  const [loading, setLoading] = useState(true);

  function handleData(data) {
    setTheme(data);
    setLoading(false);
  }

  function fetchThemes() {
    setLoading(true);
    new ThemeService().getData(handleData);
  }

  function refresh(data) {
    setTheme(data);
  }

  return (
    <Provider value={{ contextTheme, fetchThemes, refresh, setLoading, }}>
      {children}
    </Provider>
  );
};

export { ThemesProvider, Consumer as ThemeConsumer, AvailableThemesContext };


这就是我在 index.js 文件中向应用程序提供所述上下文的方式:


import { ThemesProvider } from "./context/ThemeProvider";

ReactDOM.render(
  <ThemesProvider value={{}}>
   <App />
  </ThemesProvider>,
  document.getElementById("root")
);

在子组件中,有一个 useEffect ,它查看 loading 状态以呈现微调器或其他一些东西。默认情况下呈现微调器。然后我尝试将 loading 的状态更改为 false 但我无法做到这一点。

这是我的测试:


import React from "react";
// import { render } from "@testing-library/react";
import { render, screen } from "./test-utils";
import CalendarView from "../views/CalendarView";
import AvailableThemesContext from "../context/ThemeProvider";

const { loading } = AvailableThemesContext;

describe("<CalendarView />", () => {
  test("It renders without crashing", async () => {
    const { getByLabelText } = render(<CalendarView />);
    expect(getByLabelText("audio-loading")).toBeInTheDocument(); 
    // ---> This looks for the loader ands resolves OK
  });

  test("It renders without crashing", () => {
    const renderComponent = render(
     <ThemeProvider value={{ loading: false}}>
       <CalendarView />);
     </ThemesProvider>
    expect(renderComponent.getByTestId("picker-component")).toBeInTheDocument();
  });

});


更多的是,我尝试注入(inject)新状态,但组件从未看到变化。

请帮忙?

最佳答案

所以我终于找到了一个我认为可以的解决方案,希望是一个很好的实践。我基本上已经简化了我的上下文提供程序。现在的情况是,它是由一位同事编写的,他解构了上下文的 ProviderCosumer。 它的代码看起来很漂亮,但调试起来却很复杂。

现在我的上下文提供程序看起来像这样:


import React, { useState } from "react";
import PropTypes from "prop-types";

import ThemeService from "../services/GetThemes";

export const AvailableThemesContext = React.createContext();

const ThemesProvider = ({ children }) => {
  const [contextTheme, setTheme] = useState([]);
  const [loading, setLoading] = useState(true);

  function handleData(data) {
    setTheme(data);
    setLoading(false);
  }

  function fetchThemes() {
    setLoading(true);
    new ThemeService().getData(handleData);
  }

  function refresh(data) {
    setTheme(data);
  }

  return (
    <AvailableThemesContext.Provider
      value={{ loading, contextTheme, fetchThemes, refresh }}
    >
      {children}
    </AvailableThemesContext.Provider>
  );
};

export default ThemesProvider;

ThemesProvider.propTypes = {
  children: PropTypes.element.isRequired,
};


默认导出是保存状态和操作的上下文函数。 Context 本身是一个 const

测试现在按预期进行。直接使用 Context.Provider 注入(inject)值即可按预期工作:

import ThemesProvider, {
  AvailableThemesContext,
} from "../context/ThemeProvider";

describe("<CalendarView />", () => {
  test("It renders without crashing", async () => {
    const { getByLabelText } = render(
      <ThemesProvider>
        <CalendarView />
      </ThemesProvider>
    );
    expect(getByLabelText("audio-loading")).toBeInTheDocument();
  });

  test("It renders without crashing", () => {
    const { getByTestId } = render(
      <AvailableThemesContext.Provider value={{ loading: false }}>
        <CalendarView />
      </AvailableThemesContext.Provider>
    );
    expect(getByTestId("picker-component")).toBeInTheDocument();
  });
});


对于那些不需要向上下文注入(inject)新状态的测试,可以直接使用保存状态的函数包装组件,如第一个测试所示。

这样我就可以快速识别哪个正在消耗状态以及哪个正在修改它。

关于javascript - 使用 react 测试库从 Jest 测试访问和修改 react 上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63814765/

相关文章:

javascript - 如何使网站移动友好,一个选择是为每个网站制作移动版本

javascript - 使用 jQuery 合并/组合表格单元格的内容

javascript - 如何使用react和react-apollo从graphql服务器获取数据?

node.js - VSCode 新手 : Remote Jest/Node debugging through Docker

javascript - 想了解一些Javascript函数解释

javascript - 为什么在这个例子中我无法使用 moment js 计算日期时间差?

javascript - 仅切换 Reactjs 中单击的菜单

javascript - React Hook "useSelector"在函数中被调用

reactjs - 使用 React 测试库测试登录功能

javascript - 如何在 Jest 中为 ipcRenderer.on 和 ipcRenderer.send 编写单元测试?