Jest测试Profile组件mock useParams报错:Cannot SpyOn原始值
问题:React-Testing-Library测试Profile组件时Mock useParams钩子失败
我正在为调用userService并展示用户信息的Profile组件编写单元测试,使用React-Testing-Library,但在mock组件内执行的useParams()钩子时遇到问题。
Profile组件通常通过React Router动态链接路径参数传入用户ID以生成用户信息,因此需要mock该钩子。
测试代码
import React from 'react' // import API mocking utilities from Mock Service Worker import {rest} from 'msw' import {setupServer} from 'msw/node' // import react-testing methods import {render, fireEvent, waitFor, screen} from '@testing-library/react' import routeData from 'react-router'; // add custom jest matchers from jest-dom import '@testing-library/jest-dom'; import config from "../configuration/Configuration.json"; import {Profile} from "../pages/Profile"; const userId = 1; const server = setupServer( rest.get(config.URL + '/users/' + userId, (req, res, ctx) => { return res(ctx.json({userId: 1, email: 'testEmail@outlook.com', password: null, firstName: 'Test', lastName: 'User'})) }), ) beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close()) beforeEach(() => jest.spyOn(routeData, 'useParams').mockReturnValue(1)) test('loads and displays profile', async () => { render(<Profile />) await waitFor(() => screen.getByRole('Profile')) expect(screen.getByText('testEmail@outlook.com')).toBeVisible(); })
Profile组件代码
export const Profile = () => { //array of compatible users fetched for a user. const [userProfileInformation, setUserProfileInformation] = useState([]); const [isLoading, setLoading] = useState(true); const { userId } = useParams(); useEffect(() => { getUserProfileInformation().then(() => { setLoading(false); }); }, []); const getUserProfileInformation = async () => { const response = await UserService.getUserProfileInformation(userId) .then(response => response.json()) .then(data => { setUserProfileInformation(data); }); } if (isLoading) { return ( <div id="loading"> <h2>Loading...</h2> </div> ) } return ( <div> <div className="profileCard"> <h1 name='fullName'>{getFullName(userProfileInformation.firstName, userProfileInformation.lastName)}</h1> <h2>{userProfileInformation.email}</h2> </div> </div> ) }
报错信息
Error: Cannot spyOn on a primitive value; undefined given at ModuleMocker.spyOn at Object.<anonymous> at Promise.then.completed at new Promise (<anonymous>) at callAsyncCircusFn at _callCircusHook at _runTest frontend\node_modules\jest-circus\build\run.js:148:5) at _runTestsForDescribeBlock at run at runAndTransformResultsToJestFormat
我查阅资料后认为代码应该可行,恳请帮忙解决该问题。
解决方案
1. 修正useParams的导入与Mock方式
报错核心原因是:useParams钩子属于react-router-dom包,而非react-router。你导入的routeData对象中不存在useParams,导致jest.spyOn找不到目标抛出错误。
修改步骤:
- 测试文件中替换导入语句:
import * as reactRouter from 'react-router-dom'; - 调整mock返回值为组件可解构的对象(组件用
const { userId } = useParams();,因此必须返回包含userId属性的对象,而非原始值1):
beforeEach(() => { jest.spyOn(reactRouter, 'useParams').mockReturnValue({ userId: '1' }); });
2. 修正测试中的getByRole错误
测试里的screen.getByRole('Profile')无效,因为组件未设置对应的ARIA角色。改为直接等待目标文本出现:
await waitFor(() => screen.getByText('testEmail@outlook.com'));
3. 补充组件依赖(可选)
确保Profile组件中正确导入所需钩子:
import { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom';
完整修正后的测试代码
import React from 'react' import {rest} from 'msw' import {setupServer} from 'msw/node' import {render, waitFor, screen} from '@testing-library/react' import * as reactRouter from 'react-router-dom'; import '@testing-library/jest-dom'; import config from "../configuration/Configuration.json"; import {Profile} from "../pages/Profile"; const userId = 1; const server = setupServer( rest.get(config.URL + '/users/' + userId, (req, res, ctx) => { return res(ctx.json({userId: 1, email: 'testEmail@outlook.com', password: null, firstName: 'Test', lastName: 'User'})) }), ) beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close()) beforeEach(() => { jest.spyOn(reactRouter, 'useParams').mockReturnValue({ userId: userId.toString() }); }) test('loads and displays profile', async () => { render(<Profile />) await waitFor(() => screen.getByText('testEmail@outlook.com')) expect(screen.getByText('testEmail@outlook.com')).toBeVisible(); })
内容的提问来源于stack exchange,提问作者devo9191
相关产品推荐
相关产品推荐

