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

如何创建含lastRefreshTime的用户,测试Firebase非活跃用户清理云函数?

解决Firebase清理非活跃用户云函数的测试问题

问题背景

你开发了一个每24小时执行的云函数,用于删除metadata.lastRefreshTime为null的非活跃用户,但测试时无法通过createUser自定义该字段,导致无法验证函数逻辑。

可行解决方案

方案1:Mock Firebase Auth服务(推荐)

不依赖真实Firebase Auth实例,直接Mock核心方法,预设测试用的用户数据,专注验证函数的业务逻辑:

import { cleanInactiveAccount } from '../src/functions';
import * as admin from 'firebase-admin';

jest.mock('firebase-admin', () => {
  const mockAuth = {
    listUsers: jest.fn(),
    deleteUsers: jest.fn().mockResolvedValue({ successCount: 1, failureCount: 0 })
  };
  return {
    auth: jest.fn().mockReturnValue(mockAuth),
    initializeApp: jest.fn()
  };
});

describe('cleanInactiveAccount', () => {
  it('should delete users with null lastRefreshTime', async () => {
    // 预设模拟用户列表:1个非活跃用户,1个活跃用户
    const mockListUsersResult = {
      users: [
        { uid: 'inactive-user', metadata: { lastRefreshTime: null } },
        { uid: 'active-user', metadata: { lastRefreshTime: new Date().toISOString() } }
      ],
      pageToken: null
    };

    (admin.auth().listUsers as jest.Mock).mockResolvedValue(mockListUsersResult);

    const wrapped = wrap(cleanInactiveAccount);
    const result = await wrapped();

    expect(result).toEqual('Successful');
    // 验证仅删除了非活跃用户
    expect(admin.auth().deleteUsers).toHaveBeenCalledWith(['inactive-user']);
  });
});

方案2:利用真实Auth实例的默认行为

新创建的Firebase用户默认lastRefreshTime为null(未触发过登录、token刷新等操作),可直接基于此特性测试:

test('cleanInactiveAccount deletes newly created inactive users', async () => {
  // 创建未登录过的非活跃用户(lastRefreshTime默认null)
  const inactiveUser = await defaultAuth.createUser({ email: 'test-inactive@example.com' });
  // 创建活跃用户并模拟登录行为(触发lastRefreshTime更新)
  const activeUser = await defaultAuth.createUser({ email: 'test-active@example.com' });
  await defaultAuth.setCustomUserClaims(activeUser.uid, { lastLogin: new Date().toISOString() });

  const wrapped = wrap(functions.cleanInactiveAccount);
  await expect(wrapped()).resolves.toEqual('Successful');

  // 验证非活跃用户已被删除
  await expect(defaultAuth.getUser(inactiveUser.uid)).rejects.toThrow();
  // 验证活跃用户仍存在
  await expect(defaultAuth.getUser(activeUser.uid)).resolves.toBeDefined();
});

额外优化建议

  • 生产环境中,listAllUsers的递归逻辑可改用循环实现,避免超大用户量下的栈溢出问题
  • 测试结束后清理测试用户,避免残留数据:
    afterAll(async () => {
      const users = await defaultAuth.listUsers();
      await Promise.all(users.users.map(user => defaultAuth.deleteUser(user.uid)));
    });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 10:52:23