【问题标题】:How to set InitialState in React Testing Library如何在 React 测试库中设置 InitialState
【发布时间】:2020-11-11 06:15:48
【问题描述】:

我正在编写一个需要渲染组件的测试,但是我的组件的渲染不起作用并且我收到此错误:

Uncaught [TypeError: Cannot read property 'role' of undefined].

这是因为在我的组件中的 componentDidMount 函数中,我正在检查是否为 this.props.authentication.user.role === 'EXPERT'。但是,this.props.authentication 具有 userundefined

对于我的程序,这是正确的 initialState,但对于测试,我想将我的 initialState 设置为具有 user 对象。这就是我在测试中重新定义initialState 的原因。但是,组件不会使用新的initialState 呈现。

这是测试文件:

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()
  })
});

这是组件文件:

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
    }
  }
}

我也在使用下面的自定义渲染函数

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 }

【问题讨论】:

    标签: reactjs react-redux react-testing-library


    【解决方案1】:

    我不确定你在配置存储中做什么,但我想你的组件的初始状态应该在存储中传递。

    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 }
    

    希望对你有帮助:)

    【讨论】:

    • 即使使用该修复程序,我仍然会遇到相同的错误。我不确定我做错了什么。在我的配置商店中,我在 configureStore() 中传递 rootReducer
    • 尝试通过初始状态作为身份验证:{user:{role:Admin}}
    • 我将渲染中的行更改为initialState = {authentication:{user {role:'MEMBER'}}}, store = configureStore(reducer, initialState),但它仍然不起作用
    • 对此的任何更新。我也面临着调用自定义渲染函数时无法通过测试初始化​​存储的问题。
    【解决方案2】:

    也许我来晚了,但也许这对某人有用。我为 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 }
    

    值得一提的是,您可以/应该删除对您的案例没有任何意义的提供者(可能像 FlagsProviderHeaderContextProvider 但我留下来说明我决定将 UI 提供者保留在路线内,而将其他提供者保留在路线之外(但这对我来说没有多大意义)

    store 文件而言,我这样做了:

    //...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
    

    干杯! ?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-15
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 2021-02-20
      • 2021-05-05
      相关资源
      最近更新 更多