[英]Test React Component using Redux and react-testing-library
[英]React-Testing-Library - Wrapping Component with Redux and Router
我正在嘗試設置測試文件以在我的應用程序上呈現路徑/頁面。 我正在嘗試使用Redux和Router包裝所有內容,這就是我所擁有的:
import React from 'react';
import { render } from 'react-testing-library';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from '../../store/reducer';
import {Link, Route, Router, Switch} from 'react-router-dom'
import {createMemoryHistory} from 'history'
import ViewNode from '../Pages/ViewNode';
const customRender = (
ui,
{
route = '/',
history = createMemoryHistory({ initialEntries: [route] }),
initialState,
store = createStore(reducer, initialState),
...options
} = {}
) => ({
...render(
<Provider store={store}>
<Router history={history}>{ui}</Router>
</Provider>,
options
),
history,
});
test('can render with redux and router', () => {
const { getByTestId } = customRender(
<Route path="/server/:env/:nodeName">
<ViewNode />
</Route>,
{
route: '/server/prod/some.server.name.com',
}
);
expect(getByTestId('page-content')).toBeVisible()
})
然后我收到以下錯誤:
Error: Uncaught [TypeError: Cannot read property 'params' of undefined]
拋出錯誤的原因是因為它無法找到React Router參數。 在Im初始化狀態時,它在組件構造函數中失敗:
this.state = {
modal: false,
activeTab: '1',
imageStatus: "loading",
env: props.match.params.env, //failing here
nodeName: props.match.params.nodeName,
environments: props.environments,
}
似乎它沒有正確地包裝路由器與我上面的實現。
如何使用Redux和Router正確包裝我的頁面組件,以便它可以獲得這些路由器參數?
您已將<ViewNode />
組件放置在Route
但忘記傳遞它收到的道具。 這就是為什么props.match
在組件中未定義的原因。
你可以這樣做:
<Route path="/server/:env/:nodeName">
{props => <ViewNode {...props} />}
</Route>
基本上,您可以使用3種方法之一使用<Route>
渲染內容 。
這是一個工作示例:
import React from 'react'
import {Route, Router} from 'react-router-dom'
import {createMemoryHistory} from 'history'
import {render, fireEvent} from '@testing-library/react'
import {createStore} from 'redux'
import {Provider, connect} from 'react-redux'
function reducer(state = {count: 0}, action) {
switch (action.type) {
case 'INCREMENT':
return {
count: state.count + 1,
}
case 'DECREMENT':
return {
count: state.count - 1,
}
default:
return state
}
}
class Counter extends React.Component {
increment = () => {
this.props.dispatch({type: 'INCREMENT'})
}
decrement = () => {
this.props.dispatch({type: 'DECREMENT'})
}
render() {
return (
<div>
<div data-testid="env-display">{this.props.match.params.env}</div>
<div data-testid="location-display">{this.props.location.pathname}</div>
<div>
<button onClick={this.decrement}>-</button>
<span data-testid="count-value">{this.props.count}</span>
<button onClick={this.increment}>+</button>
</div>
</div>
)
}
}
const ConnectedCounter = connect(state => ({count: state.count}))(Counter)
function customRender(
ui,
{
initialState,
store = createStore(reducer, initialState),
route = '/',
history = createMemoryHistory({initialEntries: [route]}),
} = {},
) {
return {
...render(
<Provider store={store}>
<Router history={history}>{ui}</Router>
</Provider>,
),
store,
history,
}
}
test('can render with redux and router', () => {
const {getByTestId, getByText} = customRender(
<Route path="/server/:env/:nodeName">
{props => <ConnectedCounter {...props} />}
</Route>,
{
route: '/server/prod/some.server.name.com',
},
)
expect(getByTestId('env-display')).toHaveTextContent('prod')
expect(getByTestId('location-display')).toHaveTextContent(
'/server/prod/some.server.name.com',
)
fireEvent.click(getByText('+'))
expect(getByTestId('count-value')).toHaveTextContent('1')
})
這就是我測試路線的方式。
import { render } from '@testing-library/react';
import { Router, Switch, Route } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { Provider } from 'react-redux';
import React from 'react';
import createStore from 'redux-mock-store';
jest.mock('../../components/Form/ManagerSelect', () => jest.fn(() => null));
describe('router page', () => {
const createState = state => {
return {
//whatever u need
}
};
const Home = _ => <span>home</span>;
const Profile = _ => <span>profile</span>;
const renderComponent = state => {
const store = createStore()(state);
//this is the "history" of your app like:
// homepage -> about -> contact -> cart page ...
const initialEntries = ['/'];
return render(
<Provider store={store}>
<Router history={createMemoryHistory({ initialEntries })}>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/profile" component={Profile} />
</Switch>
</Router>
</Provider>
);
};
it('missing emergency details should redirect to profile', () => {
const rendered = renderComponent(createState());
expect(rendered.container.innerHTML).toEqual('<span>profile</span>');
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.