我需要呈现一个自定义钩子,并在有人试图在没有提供者的情况下使用钩子时测试错误消息



使用React, Jest和React测试库

我的自定义钩子

import { useContext } from "react";
import { SelectThemeContext } from "../contexts/SelectThemeContext/SelectThemeContextProvider";
import { isEmpty } from "../utils/functions/isEmpty";
const useSelectThemeContext = () => {
const context = useContext(SelectThemeContext);
if (isEmpty(context)) {
throw Error(
"You have to use useSelectThemeContext inside <SelectThemeContextProvider />",
);
}
const { theme, toggleTheme } = context;
return { theme, toggleTheme };
};
export default useSelectThemeContext;

我的测试

it("[ACAMP-03] - should return error message when trying to use custom hook without provider", async () => {
let message: string;
try {
await renderHook(() => useSelectThemeContext());
message = "";
} catch (e: any) {
message = e.message;
}
expect(message).toEqual(
"You have to use useSelectThemeContext inside <SelectThemeContextProvider />",
);
});

我可以得到消息,但我也在控制台中得到一个错误。

在VirtualConsole。(node_modules/jsdom/lib/jsdom/virtual-console.js: 29:45)在reportException (node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:70:28)
at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:341:9). at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
at htmlknownelementimpl ._dispatch (node_modules/jsdom/lib/jsdom/生活/事件/EventTarget-impl.js: 221:9)在HTMLUnknownElementImpl。dispatchEvent (node_modules/jsdom/lib/jsdom/生活/事件/EventTarget-impl.js: 94:17)在HTMLUnknownElement。dispatchEvent (node_modules/jsdom/lib/jsdom/生活//EventTarget.js:生成231:34)

console.error
The above error occurred in the <TestComponent> component:

at TestComponent (C:Usersrafael.almeidaDocumentsProjectsEstudoacampbase-reactv18-eslint-prettier-confignode_modules@testing-libraryreactdistpure.js:281:5)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
at logCapturedError (node_modules/react-dom/cjs/react-dom.development.js:18687:23)
at update.callback (node_modules/react-dom/cjs/react-dom.development.js:18720:5)
at callCallback (node_modules/react-dom/cjs/react-dom.development.js:13923:12)
at commitUpdateQueue (node_modules/react-dom/cjs/react-dom.development.js:13944:9)
at commitLayoutEffectOnFiber (node_modules/react-dom/cjs/react-dom.development.js:23391:13)
at commitLayoutMountEffects_complete (node_modules/react-dom/cjs/react-dom.development.js:24688:9)  
at commitLayoutEffects_begin (node_modules/react-dom/cjs/react-dom.development.js:24674:7)
at commitLayoutEffects (node_modules/react-dom/cjs/react-dom.development.js:24612:3)

运行测试CodeSandBox测试CodeSandBox

你可以/应该使用@test -library/react-hooks。它提供了一个不同的renderHook方法,可以接受包装器参数,并可以返回错误。

您的测试将看起来像这样。我不认为它必须是异步的。如果您的特定需求需要异步函数,那么请参考jest文档。我记得这和我在测试async时所期望的有点不同。

import { renderHook } from "@testing-library/react-hooks";
it("[ACAMP-03] - should return error message when trying to use custom hook without provider", () => {
const { result } = renderHook(() => useSelectedThemeContext());
expect(result.error?.message).toEqual(
"You have to use useSelectThemeContext inside <SelectThemeContextProvider />",
);
});

如果你想测试提供程序的功能,你可以这样做:

it("does what the hook is supposed to do", () => {
const wrapper = ({ children }) => (
<SelectedThemeContextProvider>
{children}
</SelectedThemeContextProvider>
);
const { result } = renderHook(() => useSelectedThemeContext(), {wrapper});
expect(result.error).toBeUndefined();
// using color as an example
expect(result.color).toEqual("#ffffff");
})

我正在使用一种方法来抑制控制台。专门用于测试的错误,如果算法被设计为不需要使用此方法,请…

const spyConsole = jest
.spyOn(console, "error")
.mockImplementation(() => {});

我能够通过模拟useContext来测试和覆盖错误处理行回报。

import React from 'react';
import { renderHook } from '@testing-library/react';
import { useSelectThemeContext} from '../your-path';
describe('useSelectThemeContext', () => {
it("[ACAMP-03] - should return error message when trying to use custom hook without provider", () => {
jest.spyOn(React, 'useContext').mockImplementation(() => null)
try {
renderHook(useSelectThemeContext);
}
catch (error) {
expect(error).toEqual(new Error("You have to use useSelectThemeContext inside <SelectThemeContextProvider />"))
}
});
})