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

如何在Next.js+Jest中测试cookies.set方法的调用次数

问题原因

你当前的mock设置中,每次调用cookies()都会生成一个全新的包含set方法的对象。这意味着:

  • handleLoginAction里两次调用cookies()时,各自拿到的是不同的set mock函数
  • 你测试代码里调用cookies().set拿到的又是另一个全新的set mock函数
    自然断言调用次数为0,因为这个mock函数根本没被执行过。
解决方案

修改mock逻辑,让cookies()每次调用都返回同一个对象,这样所有地方用到的set都是同一个mock函数。

修改后的测试代码示例

import { AuthService } from '@services';
import { FormStateType } from '@types';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { handleLoginAction } from './useLogin.hook';

// 提前创建共享的mock cookie store对象
const mockCookieStore = {
  set: jest.fn(),
};

jest.mock('next/navigation', () => ({
  ...jest.requireActual('next/navigation'),
  redirect: jest.fn(),
}));

jest.mock('next/headers', () => ({
  ...jest.requireActual('next/headers'),
  // 让cookies()始终返回同一个mock对象
  cookies: jest.fn(() => mockCookieStore),
}));

describe('UseLogin hook tests', () => {
  describe('handleLoginAction tests', () => {
    it('Returns form state on success request', async () => {
      const formState: FormStateType = {};
      const formData: FormData = new FormData();
      const loginResponse: any = { access_token: 'access_token', refresh_token: 'refresh_token' };

      jest.spyOn(AuthService.prototype, 'login').mockResolvedValueOnce(loginResponse);

      const result: FormStateType = await handleLoginAction(formState, formData);

      expect(result).toBeUndefined();
      expect(redirect).toHaveBeenCalled();
      // 直接断言共享的mockSet函数的调用次数
      expect(mockCookieStore.set).toHaveBeenCalledTimes(2);
      // 还可以进一步验证调用参数是否正确
      expect(mockCookieStore.set).toHaveBeenCalledWith(COOKIES_KEYS.ACCESS, 'access_token');
      expect(mockCookieStore.set).toHaveBeenCalledWith(COOKIES_KEYS.REFRESH, 'refresh_token');
    });
  });
});

另一种实现方式

如果不想提前创建共享对象,也可以在测试用例中先获取mock的cookies实例,但前提是mock的cookies()返回同一个对象:

// mock部分返回同一个set函数实例
jest.mock('next/headers', () => {
  const mockSet = jest.fn();
  return {
    ...jest.requireActual('next/headers'),
    cookies: jest.fn(() => ({ set: mockSet })),
  };
});

// 在测试用例中获取并断言
it('Returns form state on success request', async () => {
  const formState: FormStateType = {};
  const formData: FormData = new FormData();
  const loginResponse: any = { access_token: 'access_token', refresh_token: 'refresh_token' };

  jest.spyOn(AuthService.prototype, 'login').mockResolvedValueOnce(loginResponse);

  await handleLoginAction(formState, formData);

  expect(redirect).toHaveBeenCalled();
  // 获取mock的set函数并断言
  const mockSet = (cookies() as ReturnType<typeof cookies>).set;
  expect(mockSet).toHaveBeenCalledTimes(2);
});

内容的提问来源于stack exchange,提问作者William Rizzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:12:39