[英]How to set InitialState in React Testing Library
I am writing a test where I need to render a component, but the rendering of my component is not working and I am receiving this error:我正在编写一个需要渲染组件的测试,但我的组件的渲染不起作用,我收到此错误:
Uncaught [TypeError: Cannot read property 'role' of undefined].
This is because in the componentDidMount
function in my component I am checking if this.props.authentication.user.role === 'EXPERT'
.这是因为在我的组件中的
componentDidMount
function 中,我正在检查this.props.authentication.user.role === 'EXPERT'
。 However, this.props.authentication
has user
as undefined
.但是,
this.props.authentication
的user
为undefined
。
This is the correct initialState
for my program, but for the test I want to set my initialState
to have a user
object.这是我的程序的正确初始状态,但对于测试,我想将我的
initialState
状态设置为拥有user
initialState
。 That is why I redefine initialState
in my test.这就是我在测试中重新定义
initialState
的原因。 However, the component does not render with that new initialState
.但是,组件不会使用新的
initialState
进行渲染。
Here is the testing file:这是测试文件:
import { Component } from '../Component.js';
import React from 'react';
import { MemoryRouter, Router } from 'react-router-dom';
import { render, cleanup, waitFor } from '../../test-utils.js';
import '@testing-library/jest-dom/extend-expect';
afterEach(cleanup)
describe('Component Testing', () => {
test('Loading text appears', async () => {
const { getByTestId } = render(
<MemoryRouter><Component /></MemoryRouter>,
{
initialState: {
authentication: {
user: { role: "MEMBER", memberID:'1234' }
}
}
},
);
let label = getByTestId('loading-text')
expect(label).toBeTruthy()
})
});
Here is the Component file:这是组件文件:
class Component extends React.Component {
constructor(props) {
super(props)
this.state = {
tasks: [],
loading: true,
}
this.loadTasks = this.loadTasks.bind(this)
}
componentDidMount() {
if (
this.props.authentication.user.role == 'EXPERT' ||
this.props.authentication.user.role == 'ADMIN'
) {
this.loadTasks(this.props.location.state.member)
} else {
this.loadTasks(this.props.authentication.user.memberID)
}
}
mapState(state) {
const { tasks } = state.tasks
return {
tasks: state.tasks,
authentication: state.authentication
}
}
}
I am also using a custom render function that is below我还使用了自定义渲染 function 如下
import React from 'react'
import { render as rtlRender } from '@testing-library/react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { initialState as reducerInitialState, reducer } from './_reducers'
import rootReducer from './_reducers'
import configureStore from './ConfigureStore.js';
import { createMemoryHistory } from 'history'
function render(ui, {
initialState = reducerInitialState,
store = configureStore({}),
...renderOptions
} = {}
) {
function Wrapper({ children }) {
return <Provider store={store}>{children}</Provider>
}
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions })
}
// re-export everything
export * from '@testing-library/react'
// override render method
export { render }
Perhaps I am coming super late to the party but maybe this can serve to someone.也许我来晚了,但也许这对某人有用。 What I have done for a Typescript setup is the following (all this is within
test-utils.tsx
)我为 Typescript 设置所做的工作如下(所有这些都在
test-utils.tsx
内)
const AllProviders = ({
children,
initialState,
}: {
children: React.ReactNode
initialState?: RootState
}) => {
return (
<ThemeProvider>
<Provider store={generateStoreWithInitialState(initialState || {})}>
<FlagsProvider value={flags}>
<Router>
<Route
render={({ location }) => {
return (
<HeaderContextProvider>
{React.cloneElement(children as React.ReactElement, {
location,
})}
</HeaderContextProvider>
)
}}
/>
</Router>
</FlagsProvider>
</Provider>
</ThemeProvider>
)
}
interface CustomRenderProps extends RenderOptions {
initialState?: RootState
}
const customRender = (
ui: React.ReactElement,
customRenderProps: CustomRenderProps = {}
) => {
const { initialState, ...renderProps } = customRenderProps
return render(ui, {
wrapper: (props) => (
<AllProviders initialState={initialState}>{props.children}</AllProviders>
),
...renderProps,
})
}
export * from '@testing-library/react'
export { customRender as render }
Worth to mention that you can/should remove the providers that doesn't make any sense for your case (like probably the FlagsProvider
or the HeaderContextProvider
) but I leave to illustrate I decided to keep UI providers within the route and the others outside (but this is me making not much sense anyway)值得一提的是,您可以/应该删除对您的情况没有任何意义的提供程序(可能是
FlagsProvider
或HeaderContextProvider
) ,但我留下来说明我决定将 UI 提供程序保留在路由内,将其他提供程序保留在外部(但是无论如何,这对我来说没有多大意义)
In terms of the store file I did this:就商店文件而言,我这样做了:
//...omitting extra stuff
const storeConfig = {
// All your store setup some TS infer types may be a extra challenge to solve
}
export const store = configureStore(storeConfig)
export const generateStoreWithInitialState = (initialState: Partial<RootState>) =>
configureStore({ ...storeConfig, preloadedState: initialState })
//...omitting extra stuff
Cheers!干杯!
I am not sure what you are doing in the configure store, but I suppose the initial state of your component should be passed in the store.我不确定您在配置商店中在做什么,但我想您的组件的初始 state 应该在商店中传递。
import React from 'react'
import { render as rtlRender } from '@testing-library/react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { initialState as reducerInitialState, reducer } from './_reducers'
import { createMemoryHistory } from 'history'
function render(
ui,
{
initialState = reducerInitialState,
store = createStore(reducer,initialState),
...renderOptions
} = {}
) {
function Wrapper({ children }) {
return <Provider store={store}>{children}</Provider>
}
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions })
}
// re-export everything
export * from '@testing-library/react'
// override render method
export { render }
I hope it will help you:)我希望它会帮助你:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.