Jestのエラーの解決方法を教えてください。
解決したいこと
reactのjestを現在学習中の者です。
参考書にて以下のコードのテストを行なっているのですが、
テストは正常終了するものの、ワーニングエラーが出てしまいます。
参考書に詳しい解説がないので、ご存じの方がいらっしゃいましたらご教示いただきたいです。
発生している問題・エラー①
console.error
Warning: An update to DelayInput inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
at onChange (/Users/taikiwakabayashi/Desktop/React&Next/Practice_Project/samples/components/DeleyInput/index.tsx:9:13)
30 | timerRef.current = null;
31 |
> 32 | setIsTyping(false);
| ^
33 |
34 | setViewValue(e.target.value);
35 |
発生している問題・エラー②
console.error
Warning: An update to DelayInput inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
at onChange (/Users/taikiwakabayashi/Desktop/React&Next/Practice_Project/samples/components/DeleyInput/index.tsx:9:13)
32 | setIsTyping(false);
33 |
> 34 | setViewValue(e.target.value);
| ^
35 |
36 | onChange(e);
37 | }, 1000);
テスト対象のコード
import React, { useState, useCallback, useRef } from "react";
type DelayButtonProps = {
onChange: React.ChangeEventHandler<HTMLInputElement>;
}
export const DelayInput = (props: DelayButtonProps) => {
const { onChange } = props;
const [isTyping, setIsTyping] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>('');
const [viewValue, setViewValue] = useState<string>('');
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setIsTyping(true);
setInputValue(e.target.value);
if(timerRef.current !== null) {
clearTimeout(timerRef.current);
}
timerRef.current = setTimeout(() => {
timerRef.current = null;
setIsTyping(false);
setViewValue(e.target.value);
onChange(e);
}, 1000);
}, [onChange])
const text = isTyping ? '入力中...' : `入力したテキスト:${viewValue}`;
return (
<div>
<input type="text" data-testid="input-text" value={inputValue} onChange={handleChange} />
<span data-testid="display-text">{text}</span>
</div>
)
}
テストコード
import { render, screen, RenderResult, fireEvent, act, waitFor } from "@testing-library/react";
import { DelayInput } from "./index";
describe('DelayInput', () => {
let renderResult: RenderResult;
let handleChange: jest.Mock;
beforeEach(() => {
jest.useFakeTimers();
handleChange = jest.fn();
renderResult = render(<DelayInput onChange={handleChange}></DelayInput>)
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
renderResult.unmount();
});
it('should display input text 1second after onChange event occurs', async () => {
const inputNode = screen.getByTestId('input-text') as HTMLInputElement;
const inputText = 'Test Input Text';
fireEvent.change(inputNode, {target: {value: inputText}});
await act(() => {
jest.runAllTimers();
})
const spanNode = screen.getByTestId('display-text') as HTMLSpanElement;
expect(spanNode).toHaveTextContent(`入力したテキスト:${inputText}`);
})
it('should call onChange 1second after onChange event occurs', async () => {
const inputText = 'Test Input Text';
const inputNode = screen.getByTestId('input-text') as HTMLInputElement;
fireEvent.change(inputNode, {target: {value: inputText}});
await act(() => {
jest.runAllTimers();
});
expect(handleChange).toHaveBeenCalled();
})
});
環境
■macOs Monterey - version 12.6
■node.js : v19.2.0
■npm : 8.19.3
■next.js : 13.0.5
■react : 18.2.0
■typescript : 4.9.3
■jest : ^29.3.1
■jest-environment-jsdom : ^29.3.1
■jest.setup.js
import '@testing-library/jest-dom/extend-expect';
■jest.config.js
const nextJest = require('next/jest');
const createJestConfig = nextJest({ dir: './' });
const customJestConfig = {
testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules'],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: 'jest-environment-jsdom',
}
module.exports = createJestConfig(customJestConfig);
0