使用React测试库访问和修改来自Jest测试的react上下文

时间:2020-09-09 15:23:09

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

});


对于更多我试图注入新状态的组件,该组件永远不会看到更改。

请帮助?

2 个答案:

答案 0 :(得分:0)

您的语法错误,请尝试...

我刚刚更改了位置的渲染功能);的最终版本。

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

答案 1 :(得分:0)

因此,我终于设法找到了我认为可以的解决方案,并且希望这是一种好的做法。我基本上简化了上下文提供程序。就像现在一样,它是由一位同事撰写的,他已经破坏了上下文的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();
  });
});


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

这样,我可以快速识别出哪个只是在消耗状态并对其进行修改。