目前我使用带有反应钩子的功能组件。但我无法useState完全测试钩子。考虑这样一个场景,在useEffect钩子中,我正在执行 API 调用并在useState. 对于玩笑/酶,我模拟了要测试的数据,但我无法useState在玩笑中设置初始状态值。
const [state, setState] = useState([]);
我想在玩笑中将初始状态设置为对象数组。我找不到任何类似于类组件的 setState 函数。
javascript reactjs enzyme react-hooks react-hooks-testing-library
我创建了一个自定义的React钩子,该钩子应该可以处理所有不太重要的api请求,但我不想将其存储在redux状态。挂钩工作正常,但我无法对其进行测试。我的测试设置是开玩笑和酶,但是我决定在这里也尝试一下react-hooks-testing-library。
到目前为止,我尝试过的工作是先使用fetch-mock库模拟fetch请求,但效果很好。接下来,我用renderHook方法渲染钩子,该方法来自react-hooks-testing-library。不幸的是,我似乎不太了解该waitForNextUpdate方法。
这就是我的钩子的样子。
useApi钩
export function useApi<R, B = undefined>(
path: string,
body: B | undefined = undefined,
method: HttpMethod = HttpMethod.GET
): ResponseStatus<R> {
const [response, setResponse] = useState();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string | boolean>(false);
useEffect(() => {
const fetchData = async (): Promise<void> => {
setError(false);
setIsLoading(true);
try {
const result = await callApi(method, path, body);
setResponse(result);
} catch (errorResponse) {
setError(errorResponse);
}
setIsLoading(false); …Run Code Online (Sandbox Code Playgroud) 我正在尝试测试以下情况:
为此,我有2个提供者:
两者都有自定义的挂钩,公开了这些组件的共享逻辑,即:fetchResource / expireSesssion
当获取的资源返回401状态时,它将通过共享setState方法在身份验证提供程序中设置isExpiredSession值。
AuthenticationContext.js
从'react'导入React,{createContext,useState};
const AuthenticationContext = createContext([{}, () => {}]);
const initialState = {
userInfo: null,
errorMessage: null,
isExpiredSession: false,
};
const AuthenticationProvider = ({ authStateTest, children }) => {
const [authState, setAuthState] = useState(initialState);
return (
<AuthenticationContext.Provider value={[authStateTest || authState, setAuthState]}>
{ children }
</AuthenticationContext.Provider>);
};
export { AuthenticationContext, AuthenticationProvider, initialState };
Run Code Online (Sandbox Code Playgroud)
useAuthentication.js
import { AuthenticationContext, initialState } from './AuthenticationContext';
const useAuthentication = () => {
const [authState, …Run Code Online (Sandbox Code Playgroud) reactjs react-testing-library react-hooks react-hooks-testing-library
// src/reducers/FooReducer.js
export function FooReducer(state, action) {
switch (action.type) {
case 'update': {
return action.newState;
}
// ... other actions
default:
throw new Error('Unknown action type');
}
}
Run Code Online (Sandbox Code Playgroud)
// src/components/BarComponent.js
export function BarComponent() {
const [state, dispatch] = useReducer(FooReducer, []);
return (
{state.map((item) => (<div />))}
);
}
Run Code Online (Sandbox Code Playgroud)
// src/components/BarComponent.test.js
it('should render as many divs as there are items', () => {
act(() => {
const { result } = renderHook(() => useReducer(FooReducer, [1]));
const [, dispatch] …Run Code Online (Sandbox Code Playgroud) Advanced-hooks#async文档上有一个示例。
\n我对如何waitForNextUpdate运作感到困惑。我做了两个测试用例来比较waitForNextUpdate和act()+ jest.advanceTimersByTime()。
index.ts:
import { useState, useCallback } from \'react\';\n\nexport function useCounter(initialValue = 0) {\n const [count, setCount] = useState(initialValue);\n const increment = () => setCount((x) => x + 1);\n const incrementAsync = useCallback(() => setTimeout(increment, 100, [increment]);\n const reset = useCallback(() => setCount(initialValue), [initialValue]);\n return { count, increment, incrementAsync, reset };\n}\nRun Code Online (Sandbox Code Playgroud)\nindex.test.ts:
import { renderHook, act } from \'@testing-library/react-hooks\';\nimport { useCounter } from …Run Code Online (Sandbox Code Playgroud) 我有以下钩子:
const useBar = () => {
const [myFoo, setFoo] = useState(0);
const [myBar, setBar] = useState(0);
useEffect(() => {
setFoo(myFoo + 1);
console.log("setting foo (1)", myFoo, myBar);
}, [setFoo, myFoo, myBar]);
useEffect(() => {
setBar(myBar + 1);
console.log("setting bar (2)", myFoo, myBar);
}, [setBar, myBar, myFoo]);
};
Run Code Online (Sandbox Code Playgroud)
使用组件时,我有无限循环的预期行为:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const Bar = () => {
useBar();
return <div>Bar</div>;
};
function App() {
return (
<Bar />
);
} …Run Code Online (Sandbox Code Playgroud) 我有一个钩子useEffect。我注意到useEffect运行的次数不会超过两次,因为在一次rerender使用不同数据的调用之后,后续调用不会获取更新的数据。
export default function(lookForUsername) {
const [dashboardHref, setDashboardHref] = useState(`https://www.example.com/`);
useEffect(() => {
// this is where I have code that i want to
// run on re-render, but it won't because it stops getting updated
}, [lookForUsername]);
return [dashboardHref];
}
Run Code Online (Sandbox Code Playgroud)
我的测试发生了这种情况
// this will log false, false on first run
const { rerender, waitForNextUpdate } = renderHook((lookForUsername=false, otherOption=false) => {
console.log(lookForUsername, otherOption);
return useMyHook(lookForUsername);
});
console.log('first re-render');
// this will make the console …Run Code Online (Sandbox Code Playgroud) 我创建了一个公开钩子的上下文以方便使用。在这个钩子中,我已经确保在渲染页面之前预加载一些数据,如下所示:
export const MyContext = React.createContext({} as any);
function useMyContext() {
const context = React.useContext(MyContext);
if (context === undefined) {
throw new Error('useMyContext must be used within a MyContext');
}
return context;
}
function MyContextProvider(props: any) {
const client = useApolloClient();
const { user } = React.useContext(UserContext);
const [data, setData ] = React.useState({});
const findSomethingFromUser = () => {
return client.query({
query: FIND_SOMETHING_FROM_USER,
variables: { userId: user.id },
});
};
const load = () => {
findSomethingFromUser()
.then(({ data, errors …Run Code Online (Sandbox Code Playgroud) javascript reactjs react-testing-library react-hooks react-hooks-testing-library
我想测试一个自定义钩子,该钩子是作为帮助函数实现的,以便与其他钩子重用代码。它正在调用useDispatch并useSelector在其实现中,以及将数据保存在会话存储中:
export function useCustomHook(key, obj)
{
let myObject = {
somefield: obj.someField
};
sessionStorage.setItem(key, JSON.stringify(myObject));
const dispatch = useDispatch();
dispatch(actionCreator.addAction(key, myObject));
}
Run Code Online (Sandbox Code Playgroud)
和测试:
it('should have data in redux and session storage', () =>
{
const obj = {
somefield: 'my val',
};
renderHook(() => useCustomHook('some key', obj));
let savedObj= JSON.parse(sessionStorage.getItem('some key'));
expect(savedObj.someField).toBe('my val');
renderHook(() =>
{
console.log("INSIDE");
let reduxObj = useSelector(state => state.vals);
console.log("THE OBJECT: " );
console.log(reduxObj);
expect(reduxObj).toBe(2); //just to see if it fails the …Run Code Online (Sandbox Code Playgroud) 当使用“@testing-library/react-hooks”中的 renderHook 时,我无法理解如何在没有以下警告的情况下为钩子编写测试。
“警告:测试中对 TestHook 的更新未包含在 act(...) 中。”
基本上,挂钩在状态中设置初始值useState,然后在useEffect挂钩内我异步执行一些操作,最终更新状态值。
import React from "react";
// fake request
const fetchData = () => Promise.resolve("data");
export const useGetData = () => {
const initialData = { state: "loading" };
const [data, setData] = React.useState(initialData);
React.useEffect(() => {
fetchData()
.then(() => setData({ state: "loaded" }));
}, []);
return data;
};
Run Code Online (Sandbox Code Playgroud)
钩子总是简单地返回状态值..所以我编写了一个测试来断言它首先返回初始值并最终返回新的状态值。
import { renderHook } from "@testing-library/react-hooks";
import { useGetData } from "./useGetData";
describe("useGetData", async () => {
it('Should initially …Run Code Online (Sandbox Code Playgroud) react-hooks-testing-library ×10
reactjs ×10
react-hooks ×8
enzyme ×2
javascript ×2
jestjs ×2
react-redux ×1
testing ×1