【问题标题】:React Testing waiting for useDispatch and state changeReact 测试等待 useDispatch 和状态更改
【发布时间】:2022-02-09 14:09:14
【问题描述】:

我正在测试一个组件,我需要等待调度调用,然后等待“加载”状态也发生变化。

我正在使用jest.mock 传递调度结果,但据我所知,结果似乎没有传递......

我的帖子详细信息组件: 使用效果(() => {

    const postDetail = async () => {
        
        await dispatch(postDetailView(postID))
        console.log('post Detail', postID)
        setLoading(false)
    }

    postDetail()

}, [dispatch])

我的测试设置:

const mockDispatch = jest.fn();

jest.mock('react-redux', () => ({
    ...jest.requireActual('react-redux'),
    useDispatch: () => mockDispatch.mockReturnValueOnce({
        _id: '12345',
        title:'A New Post',
        description: 'A New Description'
    }) // Return a value since I'm expecting a value to be returned before I redirect
}))



describe('Post Detail', () => {

    it('Post Detail Get View', async () => {

        const result = await waitFor(() =>  render(
        <MemoryRouter initialEntries={['/detail/12345']}>
            <Provider store={store}>
                <Routes>
                    <Route path='/detail/:postID' exact element={<PostDetail/>} />
                </Routes>
            </Provider>
        </MemoryRouter>))
    
        // This produces and Error that title does not exist
        const postElementTitle = screen.getByText(/title/i)

        //This test passes
        expect(mockDispatch).toHaveBeenCalledTimes(1)
        
    })

})

我希望会发生的是组件将加载到 waitFor 块中并调用调度,获取结果,但这似乎没有发生,奇怪的是调度调用确实被成功调用,但结果却没有' t 似乎正在进入组件。

错误结果:

 TestingLibraryElementError: Unable to find an element with the text: /title/i. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    Ignored nodes: comments, <script />, <style />
    <body>
      <div>
        <div
          class="card"
        >
          <div
            class="row"
          >
            <div
              class="col"
            >
              <a
                href="/detail/undefined" // this is where the ID of the dispatch results should appear but it's coming up blank
              >
                <p /> //This is where title from the dispatch tests should be appearing but it's blank
              </a>
            </div>
            <div
              class="col"
            >
              <p />
            </div>
            <div
              class="col"
            >
              <button
                class="btn btn-outline-primary"
                type="button"
              >
                Update
              </button>
              <button
                class="btn btn-outline-danger"
                type="button"
              >
                Delete
              </button>
            </div>
            
          </div>
        </div>
      </div>
    </body>

我正在使用的版本:

"@reduxjs/toolkit": "^1.7.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"react": "^17.0.2",
"react-redux": "^7.2.6",
"react-router-dom": "^6.2.1",
"react-scripts": "5.0.0",

回顾一下发生了什么(我认为)是调度元素被调用但结果没有被组件本身读取。我不确定如何解决这个问题,或者是否有人能看到我的明显失误。提前致谢。

【问题讨论】:

    标签: reactjs testing jestjs


    【解决方案1】:

    我发现我做错了什么,并且我也有错误的方法来测试组件本身。此外,我还学到了很多关于 redux 以及测试的复杂性的知识,但学习对我来说是一件好事,可以让我了解更多 redux 的来龙去脉。

    测试文件

    const store = configureStore({
        reducer:{
            post: postReducer,
            alert: alertReducer
        }
    })
    
    const MockComponent = (props={}, history={}) => {
        return(
            <BrowserRouter>
                <Provider store={store}>
                    <PostDetail/>
                </Provider>
            </BrowserRouter>)
    }
    
    const mockDispatch = jest.fn();
    // const mockSelector = jest.fn()
    
    jest.mock('react-redux', () => ({
        ...jest.requireActual('react-redux'),
        useDispatch: () => mockDispatch
        // useSelector: () => mockSelector.mockReturnValueOnce(true)
    }))
    
    // // mock useNavigate
    describe('Post Detail', ()=>{
    
        it('post detail', async () => {
    
            
            render(MockComponent())  
            
            // Use dispatch to update the store correctly
            store.dispatch(postSliceActions.postDetail({_id:1, title:'A new Post', description: 'A new Desc'}))
            
            // Check that dispatch was called within the component
            expect(mockDispatch).toHaveBeenCalledTimes(1)
    
            // Ensure the loading screen has time to go away
            await waitForElementToBeRemoved(() => screen.queryByText(/Loading/i))
    
            // Check for the post title in the component
            expect(screen.getByText(/a new post/i)).toBeInTheDocument()
            
    
            // screen.debug()
    
        })
    
    })
    

    这篇文章也对我有帮助,尤其是在等待删除元素时...https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning

    谢谢,

    【讨论】: