gpt4 book ai didi

reactjs - 使用 Jest 模拟 React HOC 时出现 "Invalid hook call"

转载 作者:行者123 更新时间:2023-12-04 00:00:42 24 4
gpt4 key购买 nike

我正在使用 react-speech-recognition在我的 React 应用程序中将语音转录为文本。 react-speech-recognition 提供了 SpeechRecognition高阶组件,它注入(inject)额外的属性,如 browserSupportsSpeechRecognition封装成组件。

我的 App 组件如下所示:

// src/App.js
import React, { useEffect } from 'react';
import SpeechRecognition from 'react-speech-recognition';

const App = ({ transcript, browserSupportsSpeechRecognition }) => {
useEffect(() => {
console.log(`transcript changed: ${transcript}`);
}, [transcript]);

if (! browserSupportsSpeechRecognition) {
return <span className="error">Speech recognition not supported</span>;
}

return <span className="transcript">{transcript}</span>;
};

const options = {
autoStart: false,
continuous: false
};

export default SpeechRecognition(options)(App);

我编写了一些测试来模拟支持语音识别的浏览器和不支持语音识别的浏览器:
// src/App.spec.js
import React from 'react';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import chai, { expect } from 'chai';
import chaiEnzyme from 'chai-enzyme';

chai.use(chaiEnzyme());

Enzyme.configure({ adapter: new Adapter() });

// Generate a mock SpeechRecognition HOC with the given props
function mockSpeechRecognition(mockProps) {
return function(options) {
return function(WrappedComponent) {
return function(props) {
return (
<WrappedComponent
{...props}
{...mockProps}
recognition={{}}
/>
);
};
};
};
}

describe('App component', () => {

beforeEach(() => jest.resetModules());

it('should show an error when speech recognition is not supported', () => {
jest.mock('react-speech-recognition', () => mockSpeechRecognition({
browserSupportsSpeechRecognition: false
}));

const App = require('./App').default;
const wrapper = mount(<App />);

expect(wrapper).to.contain.exactly(1).descendants('.error');
expect(wrapper.find('.error'))
.to.have.text('Speech recognition not supported');
});

it('should show the transcript when speech recognition is supported', () => {
jest.mock('react-speech-recognition', () => mockSpeechRecognition({
browserSupportsSpeechRecognition: true,
transcript: 'foo'
}));

const App = require('./App').default;
const wrapper = mount(<App />);

expect(wrapper).to.contain.exactly(1).descendants('.transcript');
expect(wrapper.find('.transcript')).to.have.text('foo');
});

});

当我运行这些测试时,我得到一个 "Invalid hook call" error导致测试失败:
  ● App component › should show an error when speech recognition is not supported

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.

3 |
4 | const App = ({ transcript, browserSupportsSpeechRecognition }) => {
> 5 | useEffect(() => {
| ^
6 | console.log(`transcript changed: ${transcript}`);
7 | }, [transcript]);
8 |

at resolveDispatcher (node_modules/react/cjs/react.development.js:1465:13)
at useEffect (node_modules/react/cjs/react.development.js:1508:20)
at App (src/App.js:5:5)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14803:18)
at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:17482:13)
at beginWork (node_modules/react-dom/cjs/react-dom.development.js:18596:16)
at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:188:14)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:237:16)
at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:292:31)
at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23203:7)
at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22157:12)
at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22130:22)
at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:21756:9)
at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21188:7)
at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:24373:3)
at node_modules/react-dom/cjs/react-dom.development.js:24758:7
at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:21903:12)
at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:24757:5)
at Object.render (node_modules/react-dom/cjs/react-dom.development.js:24840:10)
at fn (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:437:26)
at node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:354:37
at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:21856:12)
at Object.act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:929:14)
at wrapAct (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:354:13)
at Object.render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:423:16)
at new ReactWrapper (node_modules/enzyme/src/ReactWrapper.js:115:16)
at mount (node_modules/enzyme/src/mount.js:10:10)
at Object.<anonymous> (src/App.spec.js:38:25)

● App component › should show the transcript when speech recognition is supported

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.

3 |
4 | const App = ({ transcript, browserSupportsSpeechRecognition }) => {
> 5 | useEffect(() => {
| ^
6 | console.log(`transcript changed: ${transcript}`);
7 | }, [transcript]);
8 |

at resolveDispatcher (node_modules/react/cjs/react.development.js:1465:13)
at useEffect (node_modules/react/cjs/react.development.js:1508:20)
at App (src/App.js:5:5)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14803:18)
at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:17482:13)
at beginWork (node_modules/react-dom/cjs/react-dom.development.js:18596:16)
at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:188:14)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:237:16)
at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:292:31)
at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23203:7)
at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22157:12)
at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22130:22)
at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:21756:9)
at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21188:7)
at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:24373:3)
at node_modules/react-dom/cjs/react-dom.development.js:24758:7
at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:21903:12)
at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:24757:5)
at Object.render (node_modules/react-dom/cjs/react-dom.development.js:24840:10)
at fn (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:437:26)
at node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:354:37
at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:21856:12)
at Object.act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:929:14)
at wrapAct (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:354:13)
at Object.render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:423:16)
at new ReactWrapper (node_modules/enzyme/src/ReactWrapper.js:115:16)
at mount (node_modules/enzyme/src/mount.js:10:10)
at Object.<anonymous> (src/App.spec.js:52:25)

但是,当我运行开发服务器并在浏览器中查看页面时,没有此类错误,并且可以看到 useEffect钩子(Hook)将消息记录到控制台。创建生产版本时也没有错误。我认为问题在于我如何模拟 SpeechRecognition HOC。如果我删除 useEffect,则测试通过钩。

这是一个从 create-react-app 开始的全新项目。我只有一份 react 和 react-dom 并且版本匹配:
$ npm ls react react-dom
react-speech-recognition-invalid-hook-call@0.1.0 /Users/NMD/max_programming_projects/react-speech-recognition-invalid-hook-call
├── react@16.13.1
└── react-dom@16.13.1

如何在我的测试中修复此错误?

最佳答案

看起来这是 Jest 中的一个错误:

Invalid hook call after `jest.resetModules` for dynamic `require`s

当您调用 jest.resetModules 时会发生该错误。或 jest.resetModuleRegistry然后 require测试中的组件。

您可以通过删除 jest.resetModules 来解决它。/jest.resetModuleRegistry并包装require s 在调用 jest.isolateModules :

describe('App component', () => {

it('should show an error when speech recognition is not supported', () => {
jest.mock('react-speech-recognition', () => mockSpeechRecognition({
browserSupportsSpeechRecognition: false
}));

jest.isolateModules(() => {
const App = require('./App').default;
const wrapper = mount(<App />);

expect(wrapper).to.contain.exactly(1).descendants('.error');
expect(wrapper.find('.error'))
.to.have.text('Speech recognition not supported');
});
});

it('should show the transcript when speech recognition is supported', () => {
jest.mock('react-speech-recognition', () => mockSpeechRecognition({
browserSupportsSpeechRecognition: true,
transcript: 'foo'
}));

jest.isolateModules(() => {
const App = require('./App').default;
const wrapper = mount(<App />);

expect(wrapper).to.contain.exactly(1).descendants('.transcript');
expect(wrapper.find('.transcript')).to.have.text('foo');
});
});

});

当我运行它时,所有测试都通过了,我可以看到 useEffect 的输出钩:
 PASS  src/App.spec.js
App component
✓ should show an error when speech recognition is not supported (89ms)
✓ should show the transcript when speech recognition is supported (6ms)

console.log src/App.js:6
transcript changed: undefined

console.log src/App.js:6
transcript changed: foo

Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 6.577s
Ran all test suites related to changed files.

关于reactjs - 使用 Jest 模拟 React HOC 时出现 "Invalid hook call",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62360926/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com