使用 React 测试库访问和修改 Jest 测试中的 React 上下文
Access and modify react context from jest test with react testing library
几天来我一直在与此作斗争,但我无法找到正确的方法来做我需要做的事情。
基本上我有一个上下文,提供从 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();
});
});
更多的是,我尝试注入新状态,组件从未看到变化。
请帮忙?
你的语法有误,试试这个...
我刚刚更改了最终的渲染函数 );
的位置。
test("It renders without crashing", () => {
const renderComponent = render(
<ThemeProvider value={{ loading: false}}>
<CalendarView />
</ThemesProvider>);
expect(renderComponent.getByTestId("picker-component")).toBeInTheDocument();
});
所以我终于找到了一个我认为可以的解决方案,希望这是一个很好的做法。我基本上简化了上下文提供程序。就像现在一样,它是一位同事写的,他已经解构了上下文的 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();
});
});
对于那些不需要向上下文注入新状态的测试,组件可以直接用保存状态的函数包装,如第一个测试所示。
这样我就可以快速识别哪个正在使用状态,哪个正在修改状态。
几天来我一直在与此作斗争,但我无法找到正确的方法来做我需要做的事情。 基本上我有一个上下文,提供从 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();
});
});
更多的是,我尝试注入新状态,组件从未看到变化。
请帮忙?
你的语法有误,试试这个...
我刚刚更改了最终的渲染函数 );
的位置。
test("It renders without crashing", () => {
const renderComponent = render(
<ThemeProvider value={{ loading: false}}>
<CalendarView />
</ThemesProvider>);
expect(renderComponent.getByTestId("picker-component")).toBeInTheDocument();
});
所以我终于找到了一个我认为可以的解决方案,希望这是一个很好的做法。我基本上简化了上下文提供程序。就像现在一样,它是一位同事写的,他已经解构了上下文的 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();
});
});
对于那些不需要向上下文注入新状态的测试,组件可以直接用保存状态的函数包装,如第一个测试所示。
这样我就可以快速识别哪个正在使用状态,哪个正在修改状态。