【问题标题】:Access and modify react context from jest test with react testing library使用反应测试库从 jest 测试访问和修改反应上下文
【发布时间】:2020-12-28 01:41:49
【问题描述】:

我已经为此奋斗了几天,但我无法正确地做我需要的事情。 基本上我有一个提供从 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 查看loadingstate 以呈现微调器或其他一些东西。默认呈现微调器。然后我尝试将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();
  });

});


关于我尝试注入新状态的更多信息,组件永远不会看到更改。

请帮忙?

【问题讨论】:

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


    【解决方案1】:

    你的语法错误,试试这个...

    我刚刚改变了渲染函数);的最终位置。

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

    【讨论】:

    • 抱歉,输入错误。我删除了我拥有的一些 cmets 和其他版本。这就是我认为应该是我理解文档的方式。此外,渲染的导入是由"@testing-library/react 提供的,而不是自定义的。
    【解决方案2】:

    所以我终于设法找到了一个我认为没问题的解决方案,希望是一个好的做法。我基本上简化了我的上下文提供程序。就像现在一样,它是由一位同事编写的,他已经解构了上下文的Provider Cosumer。 它使代码看起来很漂亮,但调试起来很复杂。

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

    
    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 直接向其注入值按预期工作:

    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();
      });
    });
    
    
    

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

    这样我可以快速识别出哪些正在消耗状态,哪些正在修改它。

    【讨论】:

      猜你喜欢
      • 2019-09-04
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 2019-06-13
      • 2020-01-21
      • 2020-08-27
      • 2020-08-11
      • 1970-01-01
      相关资源
      最近更新 更多