reactjs - 模拟redux后反应组件未设置状态
问题描述
这是我的测试
const initialRootState = {
accounts: [mockAccounts],
isLoading: false
}
describe('Account Dashboard', () => {
let rootState = {
...initialRootState
}
const mockStore = configureStore()
const store = mockStore({ ...rootState })
const mockFunction = jest.fn()
jest.spyOn(Redux, 'useDispatch').mockImplementation(() => mockFunction)
jest
.spyOn(Redux, 'useSelector')
.mockImplementation((state) => state(store.getState()))
afterEach(() => {
mockFunction.mockClear()
// Reseting state
rootState = {
...initialRootState
}
})
it('renders correctly', () => {
const wrapper = mount(
<TestWrapper>
<AccountDashboard />
</TestWrapper>
)
console.log(wrapper)
})
})
在我的组件中,我正在映射来自该州的帐户。在我的测试中,我收到以下错误TypeError: Cannot read property 'map' of undefined
我想测试if statement
我在组件中使用的一个,以确保它根据我收到的帐户数量返回正确的视图。
但是,当我console.log(store.getState())
正确打印时。我究竟做错了什么?
解决方案
如果你要测试一个 Redux 连接的组件,我建议不要模拟它的内部,而是把它当作一个连接到真实 Redux 存储的 React 组件来测试。
例如,这是一个用于安装连接组件的工厂函数enzyme
:
实用程序/withRedux.jsx
import * as React from "react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { mount } from "enzyme";
import rootReducer from "../path/to/reducers";
/*
You can skip recreating this "store" by importing/exporting
the real "store" from wherever you defined it in your app
*/
export const store = createStore(rootReducer);
/**
* Factory function to create a mounted Redux connected wrapper for a React component
*
* @param {ReactNode} Component - the Component to be mounted via Enzyme
* @function createElement - Creates a wrapper around the passed in component with incoming props so that we can still use "wrapper.setProps" on the root
* @returns {ReactWrapper} - a mounted React component with a Redux store.
*/
export const withRedux = Component =>
mount(
React.createElement(props => (
<Provider store={store}>
{React.cloneElement(Component, props)}
</Provider>
)),
options
);
export default withRedux;
现在,使用上面的工厂函数,我们可以通过简单地使用来测试连接的组件store.dispatch
:
测试/ConnectedComponent.jsx
import * as React from "react";
import withRedux, { store } from "../path/to/utils/withRedux";
import ConnectedComponent from "../index";
const fakeAccountData = [{...}, {...}, {...}];
describe("Connected Component", () => {
let wrapper;
beforeEach(() => {
wrapper = withRedux(<ConnectedComponent />);
});
it("initially shows a loading indicator", () => {
expect(wrapper.find(".loading-indicator")).exists().toBeTruthy();
});
it("displays the accounts when data is present", () => {
/*
Ideally, you'll be dispatching an action function for simplicity
For example: store.dispatch(setAccounts(fakeAccountData));
But for ease of readability, I've written it out below.
*/
store.dispatch({ type: "ACCOUNTS/LOADED", accounts: fakeAccountData }));
// update the component to reflect the prop changes
wrapper.update();
expect(wrapper.find(".loading-indicator")).exists().toBeFalsy();
expect(wrapper.find(".accounts").exists()).toBeTruthy();
});
});
当您开始测试其他 Redux 连接的组件时,这极大地简化了不必一遍又一遍地模拟 store/useSelector/useDispatch。
connect
附带说明一下,如果您在导出未连接的组件时使用 react-redux 的功能,则可以完全跳过此步骤。您可以在测试中导入未连接的组件,而不是导入默认导出...
示例组件:
import * as React from "react";
import { connect } from "react-redux";
export const Example = ({ accounts, isLoading }) => { ... };
const mapStateToProps = state => ({ ... });
const mapDispatchToProps = { ... };
export default connect(mapStateToProps, mapDispatchToProps)(Example);
示例测试:
import * as React from "react";
import { mount } from "enzyme";
import { Example } from "../index";
const initProps = {
accounts: [],
isLoading: true
};
const fakeAccountData = [{...}, {...}, {...}];
describe("Unconnected Example Component", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<Example {...initProps } />);
});
it("initially shows a loading indicator", () => {
expect(wrapper.find(".loading-indicator")).exists().toBeTruthy();
});
it("displays the accounts when data is present", () => {
wrapper.setProps({ accounts: fakeAccountData, isLoading: false });
wrapper.update();
expect(wrapper.find(".loading-indicator")).exists().toBeFalsy();
expect(wrapper.find(".accounts").exists()).toBeTruthy();
});
});
推荐阅读
- javascript - 如何从“日期范围选择器”禁用每天的“点击”事件?
- embedded - 使用 srec_cat 加入三个二进制文件并填充漏洞
- ember.js - Ember-cli-build,排除组件 ember 插件
- python - 如何从 Process- 或 Thread 实例返回值?
- javascript - Axios 在控制台上打印值但返回未定义
- linux - 在 @INC 中找不到 Parallel/ForkManager.pm
- c++ - C和C++中前缀自增运算符的区别
- php - Laravel Mail 未将变量传递给刀片模板
- emacs - 更改代码块的 emacs 组织模式键绑定
- java - Gradle 项目结构