You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:57:22