簡體   English   中英

如何在 React 測試庫中設置 InitialState

[英]How to set InitialState in React Testing Library

我正在編寫一個需要渲染組件的測試,但我的組件的渲染不起作用,我收到此錯誤:

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

這是因為在我的組件中的componentDidMount function 中,我正在檢查this.props.authentication.user.role === 'EXPERT' 但是, this.props.authenticationuserundefined

這是我的程序的正確初始狀態,但對於測試,我想將我的initialState狀態設置為擁有user initialState 這就是我在測試中重新定義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
    }
  }
}

我還使用了自定義渲染 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 }

也許我來晚了,但也許這對某人有用。 我為 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 提供程序保留在路由內,將其他提供程序保留在外部(但是無論如何,這對我來說沒有多大意義)

商店文件而言,我這樣做了:

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

干杯!

我不確定您在配置商店中在做什么,但我想您的組件的初始 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 }

我希望它會幫助你:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM