Thi*_*Not 3 reactjs jestjs enzyme higher-order-components
我正在使用react-speech-recognition在我的 React 应用程序中将语音转录为文本。react-speech-recognition 提供了SpeechRecognition高阶组件,它注入了额外的属性,比如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);
Run Code Online (Sandbox Code Playgroud)
我编写了一些测试来模拟支持语音识别的浏览器和不支持语音识别的浏览器:
// 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');
});
});
Run Code Online (Sandbox Code Playgroud)
当我运行这些测试时,我收到导致测试失败的“Invalid hook call”错误:
? 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)
Run Code Online (Sandbox Code Playgroud)
但是,当我运行开发服务器并在浏览器中查看页面时,没有出现此类错误,并且可以看到useEffect钩子将消息记录到控制台。创建生产版本时也没有错误。我认为问题在于我如何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
Run Code Online (Sandbox Code Playgroud)
如何在测试中修复此错误?
看起来这是 Jest 中的一个错误:
动态`require`s的`jest.resetModules`之后的钩子调用无效
当您在测试中调用jest.resetModules或jest.resetModuleRegistry然后调用require组件时,就会发生错误。
您可以通过删除jest.resetModules/jest.resetModuleRegistry并将requires包装在对的调用中来解决它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');
});
});
});
Run Code Online (Sandbox Code Playgroud)
当我运行它时,所有测试都通过了,我可以看到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.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7522 次 |
| 最近记录: |