使用 Enzyme 和 useContext 挂钩的简单集成测试应该是什么样的?
What should a simple integration test look like with Enzyme and useContext hook?
帮助在 React 中为一个组件编写一个简单的集成测试(该组件使用 useContext 钩子)。测试应验证是否按下了按钮并调用了处理程序(这是我的代码:https://codesandbox.io/s/lingering-violet-n11hu)。
验证测试的组件代码:
import React, {useContext} from "react";
import {StoreContext} from "../../reducer/context";
import moment from "moment";
import Delay from "../delay/delay";
let queue = Promise.resolve();
const Interface = () => {
const {state, dispatch} = useContext(StoreContext);
const handleLogSet = e => {
const timeout = parseInt(e.target.getAttribute("data-delay"), 10);
const timePress = moment().format("LTS");
queue = queue.then(() => Delay(timeout, timePress)).then(res => dispatch({
type: "SET_LOG", payload: "\n" + res
}));
};
const handleReset = () => {
dispatch({type: "RESET"});
};
return (
<div className="block">
<button className="btn" data-delay="1" onClick={handleLogSet}>Кнопка 1</button>
<button className="btn" data-delay="2" onClick={handleLogSet}>Кнопка 2</button>
<button className="btn" data-delay="3" onClick={handleLogSet}>Кнопка 3</button>
<button className="btn" onClick={handleReset}>Reset</button>
<textarea value={state.join("")} readOnly={true}/>
</div>
);
};
export default Interface;
尝试了不同的测试选项,但 none 有效。例如,我试过这样:
import {configure, shallow } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import Interface from "./interface";
import React, { useContext } from "react";
import { StoreContext } from "../../reducer/context";
configure({ adapter: new Adapter() });
const { state } = useContext(StoreContext);
it(`Click by button calls callback`, () => {
const handleLogSet = jest.fn();
const component = shallow(<Interface
state={state}
/>);
component.find(`.button`).simulate(`click`);
expect(handleLogSet).toHaveBeenCalledTimes(1);
});
出现了各种错误,包括:"Invalid hook call. Hooks can only be called inside of the body of a function component"。
如果能提供一个工作代码示例和简要说明,我将不胜感激。非常感谢大家!
所以一切都很简单。值得注意的是,在使用 Enzyme 库的浅层方法测试使用 useContext 的组件时,存在公认的困难。到现在还没能直接解决。
首先要做的是创建自定义挂钩。你可以这样做:
import React, {useContext} from 'react';
export const useAppContext = () => useContext(AppContext);
const AppContext = React.createContext();
export default AppContext;
这样做是为了不在被测组件中直接使用 useContext。
e2e 测试本身看起来像这样:
import React from "react";
import {configure, shallow} from "enzyme";
import * as AppContext from "../../reducer/context";
import Adapter from "enzyme-adapter-react-16";
import Interface from "./interface";
configure({adapter: new Adapter()});
it(`Click by Set and Reset buttons calls callback`, () => {
const contextValues = {state: ["Mock state"]};
const handleReset = jest.fn();
const handleLogSet = jest.fn();
jest
.spyOn(AppContext, "useAppContext")
.mockImplementation(() => contextValues);
const wrapper = shallow(
<Interface
onReset={handleReset}
onLogSet={handleLogSet}
/>
);
wrapper.find(`.block__btn--reset`).simulate(`click`);
expect(handleReset).toHaveBeenCalledTimes(1);
wrapper.find(`.block__btn--set`).forEach(item => {
item.simulate(`click`);
expect(handleReset).toHaveBeenCalledTimes(1);
});
});
因此,我们模仿自定义代码的实现并将此值传递给上下文对象。
帮助在 React 中为一个组件编写一个简单的集成测试(该组件使用 useContext 钩子)。测试应验证是否按下了按钮并调用了处理程序(这是我的代码:https://codesandbox.io/s/lingering-violet-n11hu)。
验证测试的组件代码:
import React, {useContext} from "react";
import {StoreContext} from "../../reducer/context";
import moment from "moment";
import Delay from "../delay/delay";
let queue = Promise.resolve();
const Interface = () => {
const {state, dispatch} = useContext(StoreContext);
const handleLogSet = e => {
const timeout = parseInt(e.target.getAttribute("data-delay"), 10);
const timePress = moment().format("LTS");
queue = queue.then(() => Delay(timeout, timePress)).then(res => dispatch({
type: "SET_LOG", payload: "\n" + res
}));
};
const handleReset = () => {
dispatch({type: "RESET"});
};
return (
<div className="block">
<button className="btn" data-delay="1" onClick={handleLogSet}>Кнопка 1</button>
<button className="btn" data-delay="2" onClick={handleLogSet}>Кнопка 2</button>
<button className="btn" data-delay="3" onClick={handleLogSet}>Кнопка 3</button>
<button className="btn" onClick={handleReset}>Reset</button>
<textarea value={state.join("")} readOnly={true}/>
</div>
);
};
export default Interface;
尝试了不同的测试选项,但 none 有效。例如,我试过这样:
import {configure, shallow } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import Interface from "./interface";
import React, { useContext } from "react";
import { StoreContext } from "../../reducer/context";
configure({ adapter: new Adapter() });
const { state } = useContext(StoreContext);
it(`Click by button calls callback`, () => {
const handleLogSet = jest.fn();
const component = shallow(<Interface
state={state}
/>);
component.find(`.button`).simulate(`click`);
expect(handleLogSet).toHaveBeenCalledTimes(1);
});
出现了各种错误,包括:"Invalid hook call. Hooks can only be called inside of the body of a function component"。
如果能提供一个工作代码示例和简要说明,我将不胜感激。非常感谢大家!
所以一切都很简单。值得注意的是,在使用 Enzyme 库的浅层方法测试使用 useContext 的组件时,存在公认的困难。到现在还没能直接解决。
首先要做的是创建自定义挂钩。你可以这样做:
import React, {useContext} from 'react';
export const useAppContext = () => useContext(AppContext);
const AppContext = React.createContext();
export default AppContext;
这样做是为了不在被测组件中直接使用 useContext。
e2e 测试本身看起来像这样:
import React from "react";
import {configure, shallow} from "enzyme";
import * as AppContext from "../../reducer/context";
import Adapter from "enzyme-adapter-react-16";
import Interface from "./interface";
configure({adapter: new Adapter()});
it(`Click by Set and Reset buttons calls callback`, () => {
const contextValues = {state: ["Mock state"]};
const handleReset = jest.fn();
const handleLogSet = jest.fn();
jest
.spyOn(AppContext, "useAppContext")
.mockImplementation(() => contextValues);
const wrapper = shallow(
<Interface
onReset={handleReset}
onLogSet={handleLogSet}
/>
);
wrapper.find(`.block__btn--reset`).simulate(`click`);
expect(handleReset).toHaveBeenCalledTimes(1);
wrapper.find(`.block__btn--set`).forEach(item => {
item.simulate(`click`);
expect(handleReset).toHaveBeenCalledTimes(1);
});
});
因此,我们模仿自定义代码的实现并将此值传递给上下文对象。