我正在用react测试库编写测试用例。为了编写测试用例,我需要模拟react查询的useQuery和useMutation方法。如果有人知道解决方法,请指导我。我在这里添加相关代码。
工作区详细信息部分.test.tsx
import React from 'react'
import '@testing-library/jest-dom'
import '@testing-library/jest-dom/extend-expect'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { WorkspaceDetailsSection } from '../WorkspaceDetailsSection'
import { render } from '../../_utils/test-utils/test-utils'
const mockedFunction = jest.fn()
let realUseContext: any
let useContextMock: any
// Setup mock
beforeEach(() => {
realUseContext = React.useContext
useContextMock = React.useContext = jest.fn()
})
// Cleanup mock
afterEach(() => {
React.useContext = realUseContext
})
jest.mock('../data', () => ({
useMutationHook: () => ({ mutate: mockedFunction })
}))
const WorkspaceContext = {
workspaceInfo: {
name: 'name',
dot: 'name',
type: 'type'
}
}
test('renders section with the valid details', async () => {
useContextMock.mockReturnValue(WorkspaceContext)
render(<WorkspaceDetailsSection />)
expect(screen.getByText('Workspace name:')).toBeInTheDocument()
})
工作区详细信息部分.tsx
import React, { useContext } from 'react'
import { FormModal, useDisclosure } from '@chaine/keychaine'
import { workspaceService } from './data'
import { useMutation } from 'react-query'
import { Section } from '../account-settings'
import { Toast } from '../_shared/components'
import { IWorkspace } from '../_shared/refactoredInterfaces'
import constant from '../_shared/constants/message'
import { WorkspaceContext } from './WorkspacePage'
import capitalizeFirstLetter from '../_utils/capitalizeFirstLetter'
import { queryClient } from '../_shared/infra'
/**
*
* should import section component and return that
*/
export const WorkspaceDetailsSection = () => {
const { isOpen, onOpen, onClose } = useDisclosure()
const { workspaceInfo } = useContext(WorkspaceContext)
const { name, dot, type } = workspaceInfo
const { showToast } = Toast()
const updateWorkspace = useMutation((params: any) => workspaceService.updateWorkspace(params))
const handleSubmit = async (event: any) => {
const params: IWorkspace = {
...event,
id: workspaceInfo.id,
type: event.type.value
}
updateWorkspace.mutate(params, {
onSuccess: () => {
onClose()
queryClient.invalidateQueries('WorkspaceProfile')
},
onError: () => {
showToast({
title: constant.UNABLE_TO_UPDATE_WORKSPACE,
status: 'error'
})
}
})
}
return (
<>
<Section
sectionTitle={'Workspace details'}
multipleFields={[
{ fieldName: 'Workspace name:', value: name },
{ fieldName: 'Workspace type:', value: type },
{ fieldName: 'DOT #:', value: dot }
]}
buttonName={'Edit details'}
onClick={() => onOpen()}
/>
<FormModal
isOpen={isOpen}
onClose={() => onClose()}
title={'Change workspace info'}
size={'lg'}
formSubmitHandler={handleSubmit}
isLoading={updateWorkspace.isLoading}
initialValues={{
dot: dot,
type: { label: capitalizeFirstLetter(type), value: type },
name: name
}}
modalItems={[
{
name: 'name',
type: 'input',
placeHolder: 'Enter you name',
labelText: 'Workspace display name'
},
{ name: 'dot', type: 'input', placeHolder: 'Enter you DOT #', labelText: 'DOT #' },
{
name: 'type',
type: 'select',
placeHolder: type,
labelText: 'Workspace type',
selectOptions: [
{ label: 'Carrier', value: 'carrier' },
{ label: 'Broker', value: 'broker' },
{ label: 'Shipper', value: 'shipper' }
]
}
]}
/>
</>
)
}
工作空间服务.ts
import { BaseAPI } from '../../_shared/infra/services/BaseAPI'
import { ITokenService, IWorkspace } from '../../_shared/refactoredInterfaces'
import { TeamResponseDTO, UpdateWorkspaceResponseDTO, UploadWorkspaceLogoResponseDTO } from './WorkspaceDTO'
export interface IWorkspaceService {
getWorkspace(): Promise<TeamResponseDTO>
updateWorkspace(params: IWorkspace): Promise<UpdateWorkspaceResponseDTO>
uploadWorkspaceLogo(params: any): Promise<UploadWorkspaceLogoResponseDTO>
}
export class WorkspaceService extends BaseAPI implements IWorkspaceService {
constructor(tokenService: ITokenService) {
super(tokenService)
}
async getWorkspace(): Promise<TeamResponseDTO> {
const body = {
url: '/users/account'
}
const { data } = await this.get(body)
return {
team: data?.data,
message: data?.message
}
}
async updateWorkspace(params: IWorkspace): Promise<UpdateWorkspaceResponseDTO> {
const body = {
url: '/accounts',
data: params
}
const { data } = await this.put(body)
return {
message: data.message
}
}
async uploadWorkspaceLogo(params: FormData): Promise<UploadWorkspaceLogoResponseDTO> {
const body = {
url: '/accounts/logos',
data: params,
headers: {
'Content-Type': 'multipart/form-data'
}
}
const response = await this.post(body)
return response
}
}
我也尝试了@TkDodo here提出的解决方案,但对我来说不起作用。这个解决方案将是我的救命稻草,所以提前感谢你们。
6条答案
按热度按时间voj3qocg1#
这对我很有效
vaqhlq812#
我没有足够的声誉来回复@TkDodo上面的评论(我想,这是大多数人潜伏在SO上的“代价”😅),但我 * 已经 * 发现,模拟
react-query
的useQuery()
返回值对于练习特定的渲染结果绝对有用,而不必费心进行到处都是await waitFor()
的异步测试。遗憾的是,我还没有找到一个现成的软件包来为我管理这个问题。
也就是说,我 * 可以 * 报告说,我已经发现了为我的单元测试创建一些帮助函数的价值,这些帮助函数生成了一个带有本文所述的反结构化键的对象。
函数签名如下所示:
然而,毫无价值的是,尽管这些函数做了 * 一些 *(非常轻微!)“健全”检查/预防,比如确保
isError
字段不能被覆盖为generateUseQueryReturnValueError()
的false
,但显然有足够的空间来处理“真实的生活”中“不可能”的结果。db2dz4w83#
是的,有一种方法可以通过拦截端点来模拟useQuery数据。您可以遵循以下示例:https://github.com/MitchelSt/react-course/tree/testing/rtl/react-query
或者这个视频:https://www.youtube.com/watch?v=rGK2KiP9a5Y
7dl7o3gd4#
如果你想模拟一个返回useQuery的方法,你应该做以下事情:例如,我们有一个钩子“useExample”返回一个useQuery:
模拟:
使用这个模拟:
flvlnr445#
我并不总是想拦截端点,我同意在大多数情况下这是最好的方法。在这个例子中,以及我发现的其他例子中,API服务+查询/突变在负载序列化/聚合和实际网络请求之间创建了一个关注点分离,* 在我的用例中 * 我确实想进行单元测试和识别。我想AssertUI部件正在使用正确的有效负载调用变体,而不是API服务部件为了后端需要而聚合/修改该有效负载。
我只是遵循了TkDodo's series的建议,从单个模块中导出了所有查询和变体,然后使用Jest进行模拟和Assert就非常简单了
而对于Assert变异负载就像
n3schb8v6#
这是我使用jest mock文档得到的结果:
这对我很有效,模拟模块和实现没有帮助