React测试等待useDispatch和状态变化。

3

我正在测试一个组件,需要等待调用完成并且等待“loading”状态发生改变。

我使用jest.mock来传递调用结果,但是据我所知结果好像没有被传递...

我的文章详情组件: useEffect(() => {

    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块中加载并调用dispatch,获取结果,但似乎并没有发生这种情况,奇怪的是,dispatch调用成功了,但结果似乎没有传递到组件中。
错误结果:
 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",

回顾一下(我认为)目前的情况是,调用了分派元素,但是组件本身没有读取到结果。我不确定如何解决这个问题或者是否有人能够发现我的明显错误。先谢谢了。
1个回答

5

我找出了自己的错误,并且意识到我对测试一个组件本身的方法也是不正确的。同时,我学到了很多关于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

谢谢。


谢谢,这很有帮助,我已经点赞了。 - GoWin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接