在React测试时无法在MSW中获得响应

发布于 2025-02-11 08:19:07 字数 3940 浏览 2 评论 0原文

我正在尝试测试一个React应用程序,它正在从JSONPLACEHOLDER中获取数据。获取函数通过Create async thunk在Redux Thunk中实现。

我遵循了有关此指南和有关stackoverflow的所有相关答案,但没有工作的答案。

我正在使用MSW进行模拟API提取。


import {fireEvent,screen,render, findByText, waitFor, waitForElementToBeRemoved} from '@testing-library/react'
import { createMemoryHistory } from 'history'
import { BrowserRouter, Router } from 'react-router-dom'
import Dashboard from '../Pages/Dashboard'
import {rest} from 'msw'
import {setupServer} from 'msw/node'
import { Provider } from 'react-redux'
import { configureStore } from '@reduxjs/toolkit'
import { PostsSlice } from '../Redux/reducers'


const postsResponse = rest.get("https://jsonplaceholder.typicode.com/posts",(req,res,ctx)=>{
    console.log('this line never runs')
    return res(
        ctx.json([{id:1,userId:1,title:"hello world",body:"hola hola"}])
    )
})
const handlers = [postsResponse]
const server = new setupServer(...handlers)
beforeAll(()=>server.listen())
afterEach(()=>server.resetHandlers())
afterAll(()=>server.close())


// Redux specific-->
let store = configureStore({
    initialState:[],
    reducer : PostsSlice.reducer,
})
const MockedComponent = ({children})=>{
    return (
        <Provider store={store}>
            <BrowserRouter>
            {children}
            </BrowserRouter>
        </Provider>
    )
}

describe("Dashboard Page Test",()=>{
    test("should render hello world ",async()=>{
        render(<MockedComponent><Dashboard /></MockedComponent>);
        const element =  await findByText("hello world")
        expect(element).toBeInTheDocument();
    })

})

我遇到了以下错误,

 ● Dashboard Page Test › should render hello world 

    TypeError: Cannot read property 'map' of undefined

      42 |       
      43 | <Grid sx={{padding:2}}  container spacing={4}>
    > 44 |     {posts.map(item=>(
         |            ^
      45 |   <Grid item xs={12} md={8} lg={4} xl={2} key={item.id}  >
      46 |     <div className='postitems' onClick={()=>handleNavigation(item.id)} >
      47 |       <PostItem title={item.title}  />

我尝试了使用2个React应用程序的MSW,一个是这个错误,而另一个没有REDUX很简单。这两者都失败了。

尝试的Whatwg-fetch无效。 尝试等待fetch没用 尝试WaitforelementToberemaver也没有起作用。

提前致谢。

编辑:仪表板组件的代码

import { CircularProgress, Grid } from '@mui/material'
import React,{useEffect} from 'react'
import { useDispatch } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import PostItem from '../Components/PostItem'
import { PostsType } from '../Helper/interfaces'
import { useAppDispatch, useAppSelector } from '../Hooks/reduxhooks'
import useGetError from '../Hooks/useGetError'
import useGetPosts from '../Hooks/useGetPosts'
import useGetStatus from '../Hooks/useGetStatus'
import { FetchPosts } from '../Redux/reducers'

const Dashboard: React.FC = () => {
  let dispatch = useAppDispatch()
  let navigate = useNavigate()
  let posts = useGetPosts()
  const status = useGetStatus()
  const error = useGetError()

  const handleNavigation:(id:number)=>void = (id)=>{
      navigate(`/posts/${id}`)
  }
  useEffect(()=>{
    if (status === 'idle'){
      dispatch(FetchPosts())
    }
    
  },[])

  if(status === 'loading'){
    return <CircularProgress color='success' />
  }

  if (status === 'failed'){
    return <div>{error}</div>
  }


  return (
    <div>
      <h1>Dashboard</h1>
      
<Grid sx={{padding:2}}  container spacing={4}>
    {posts.map(item=>(
  <Grid item xs={12} md={8} lg={4} xl={2} key={item.id}  >
    <div className='postitems' onClick={()=>handleNavigation(item.id)} >
      <PostItem title={item.title}  />
    </div>
  </Grid>
    ))}
</Grid>
    </div>
  )
}

export default Dashboard

I am trying to test a react app where it is fetching the data from jsonplaceholder. The fetch function is implemented in redux thunk via create async thunk.

i followed every guide and every related answer on stackoverflow regarding this but got no working answer.

i'm using msw for mock api fetching.


import {fireEvent,screen,render, findByText, waitFor, waitForElementToBeRemoved} from '@testing-library/react'
import { createMemoryHistory } from 'history'
import { BrowserRouter, Router } from 'react-router-dom'
import Dashboard from '../Pages/Dashboard'
import {rest} from 'msw'
import {setupServer} from 'msw/node'
import { Provider } from 'react-redux'
import { configureStore } from '@reduxjs/toolkit'
import { PostsSlice } from '../Redux/reducers'


const postsResponse = rest.get("https://jsonplaceholder.typicode.com/posts",(req,res,ctx)=>{
    console.log('this line never runs')
    return res(
        ctx.json([{id:1,userId:1,title:"hello world",body:"hola hola"}])
    )
})
const handlers = [postsResponse]
const server = new setupServer(...handlers)
beforeAll(()=>server.listen())
afterEach(()=>server.resetHandlers())
afterAll(()=>server.close())


// Redux specific-->
let store = configureStore({
    initialState:[],
    reducer : PostsSlice.reducer,
})
const MockedComponent = ({children})=>{
    return (
        <Provider store={store}>
            <BrowserRouter>
            {children}
            </BrowserRouter>
        </Provider>
    )
}

describe("Dashboard Page Test",()=>{
    test("should render hello world ",async()=>{
        render(<MockedComponent><Dashboard /></MockedComponent>);
        const element =  await findByText("hello world")
        expect(element).toBeInTheDocument();
    })

})

I'm getting the following error

 ● Dashboard Page Test › should render hello world 

    TypeError: Cannot read property 'map' of undefined

      42 |       
      43 | <Grid sx={{padding:2}}  container spacing={4}>
    > 44 |     {posts.map(item=>(
         |            ^
      45 |   <Grid item xs={12} md={8} lg={4} xl={2} key={item.id}  >
      46 |     <div className='postitems' onClick={()=>handleNavigation(item.id)} >
      47 |       <PostItem title={item.title}  />

i tried msw with 2 react app, one is this and other was pretty simple without redux. it failed in both.

tried whatwg-fetch didn't worked.
tried await with fetch didn't worked
tried waitForElementToBeRemoved also didn't worked.

Thanks in advance.

Edit: the code for dashboard component

import { CircularProgress, Grid } from '@mui/material'
import React,{useEffect} from 'react'
import { useDispatch } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import PostItem from '../Components/PostItem'
import { PostsType } from '../Helper/interfaces'
import { useAppDispatch, useAppSelector } from '../Hooks/reduxhooks'
import useGetError from '../Hooks/useGetError'
import useGetPosts from '../Hooks/useGetPosts'
import useGetStatus from '../Hooks/useGetStatus'
import { FetchPosts } from '../Redux/reducers'

const Dashboard: React.FC = () => {
  let dispatch = useAppDispatch()
  let navigate = useNavigate()
  let posts = useGetPosts()
  const status = useGetStatus()
  const error = useGetError()

  const handleNavigation:(id:number)=>void = (id)=>{
      navigate(`/posts/${id}`)
  }
  useEffect(()=>{
    if (status === 'idle'){
      dispatch(FetchPosts())
    }
    
  },[])

  if(status === 'loading'){
    return <CircularProgress color='success' />
  }

  if (status === 'failed'){
    return <div>{error}</div>
  }


  return (
    <div>
      <h1>Dashboard</h1>
      
<Grid sx={{padding:2}}  container spacing={4}>
    {posts.map(item=>(
  <Grid item xs={12} md={8} lg={4} xl={2} key={item.id}  >
    <div className='postitems' onClick={()=>handleNavigation(item.id)} >
      <PostItem title={item.title}  />
    </div>
  </Grid>
    ))}
</Grid>
    </div>
  )
}

export default Dashboard

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

七七 2025-02-18 08:19:07

在尝试了几天后,我发现了一个错误。
如果其他人没有从MSW中获得回复,这可以为您提供帮助。

MSW没有返回任何回应,因为我正在覆盖商店。

您需要做的是将rtlrenderer与自定义提供商一起使用(有关此此详细信息的更多详细信息)

,在测试案例中,请勿提供任何提供商。最有可能您会使用React-Router-Dom,因此请确保将其提供给组件,并且一切都可以完美地工作。

同样对于JSON占位符API,我必须使用完整的URL,即“ https://jsonplaceholder.typicode.com/posts”,但在文档中,建议仅使用“/posts”。

After experimenting for few days with it i found the mistake.
if anyone else isn't getting the response back from msw this can help you.

msw is not returning any response because i'm overriding the store.

what you need to do is use the rtlRenderer with custom provider (visit redux testing section for more details on this)

and in the test case don't provide any provider. Most probably you'll be using react-router-dom so make sure you're providing it to the component and everything will work perfectly.

Also for json placeholder api i had to use the complete url that is "https://jsonplaceholder.typicode.com/posts" but in the docs it is suggested to use only "/posts".

丑丑阿 2025-02-18 08:19:07

store.ts配置必须如下更改,公共目录也应包含MockServiceWorker.js

import { combineReducers, configureStore } from '@reduxjs/toolkit'
import { setupListeners } from '@reduxjs/toolkit/query'

import counterReducer from './features/counter/counterSlice'
import { docsApi } from './services/docs'

const rootReducer = combineReducers({
  counter: counterReducer,
  [docsApi.reducerPath]: docsApi.reducer,
})

export const store = configureStore({
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(docsApi.middleware),
  reducer: rootReducer,
  preloadedState: {}
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

setupListeners(store.dispatch)

store.ts configuration must be changed as below and also public directory should contain mockServiceWorker.js

import { combineReducers, configureStore } from '@reduxjs/toolkit'
import { setupListeners } from '@reduxjs/toolkit/query'

import counterReducer from './features/counter/counterSlice'
import { docsApi } from './services/docs'

const rootReducer = combineReducers({
  counter: counterReducer,
  [docsApi.reducerPath]: docsApi.reducer,
})

export const store = configureStore({
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(docsApi.middleware),
  reducer: rootReducer,
  preloadedState: {}
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

setupListeners(store.dispatch)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文