如何使用jest模拟typescript中的外部依赖关系

如何使用jest模拟typescript中的外部依赖关系,typescript,unit-testing,jestjs,Typescript,Unit Testing,Jestjs,我正在无可救药地尝试在typescript中模拟firebase管理依赖性以进行单元测试 我的实际功能如下 import {auth} from 'firebase-admin'; async validateUser(payload: string): Promise<User> { try { const resp = await auth().verifyIdToken(payload, true); return await this.userServ

我正在无可救药地尝试在typescript中模拟firebase管理依赖性以进行单元测试

我的实际功能如下

import {auth} from 'firebase-admin';

async validateUser(payload: string): Promise<User> {
  try {
    const resp = await auth().verifyIdToken(payload, true);

    return await this.userService.findByUsername(resp.email);
  } catch (e) {
    return null;
 }
}
但是我得到一个错误,说
TypeError:cannotread未定义的属性'mockReturnValue'

如果我理解正确,我将通过调用
jest.mock('firebase-admin')
模拟整个
firebase-admin
包。因此,我希望能够调用auth函数中的
mockReturnValue
并再次模拟
verifyIdToken
函数。然而,我甚至不能调用
mockReturnValue
,因为奇怪的是它似乎不存在


我需要如何编写代码才能模拟
auth().verifyIdToken()

这种情况下的问题是
auth
firebase admin
中的类似导出函数被定义为具有
Object.defineProperty
的getter。不幸的是,
jest.mock
在计算模块时无法看到这些,因此它不会为它们添加mock

您需要在提供给
jest.mock
的工厂中模拟
auth
(以及您需要的任何同级函数)。下面介绍如何替换第二个代码段中的
jest.mock
行:

jest.mock('firebase-admin', () =>
{
  const module = jest.createMockFromModule<any>('firebase-admin').default;
  module.auth = jest.fn();
  return module;
});
jest.mock('firebase-admin',()=>
{
const module=jest.createMockFromModule('firebase-admin')。默认值;
module.auth=jest.fn();
返回模块;
});

您还可以选择在该工厂内模拟
auth
的返回值,以进一步简化代码。

这种情况下的问题是
auth
firebase admin
中的类似导出函数被定义为具有
对象的getter。defineProperty
。不幸的是,
jest.mock
在计算模块时无法看到这些,因此它不会为它们添加mock

您需要在提供给
jest.mock
的工厂中模拟
auth
(以及您需要的任何同级函数)。下面介绍如何替换第二个代码段中的
jest.mock
行:

jest.mock('firebase-admin', () =>
{
  const module = jest.createMockFromModule<any>('firebase-admin').default;
  module.auth = jest.fn();
  return module;
});
jest.mock('firebase-admin',()=>
{
const module=jest.createMockFromModule('firebase-admin')。默认值;
module.auth=jest.fn();
返回模块;
});

您还可以选择在该工厂内模拟
auth
的返回值,以进一步简化代码。

用户将模拟工厂与模拟
firebase
模块相结合

jest.mock('firebase-admin', () => {
  return {
    auth: jest.fn(),
  }
});
等级库文件的示例:

import { auth } from 'firebase-admin';
import Test from './index';

jest.mock('firebase-admin', () => {
  return {
    auth: jest.fn(),
  }
});

describe("Test", () => {
  const email = 'mocked-email@example.com';
  const user = { email, username: 'mocked-username' };

  let mockedAuth: jest.Mock;
  let mockVerifyIdToken: jest.Mock;
  let mockUserService: { findByUsername: jest.Mock }; // mock userService
  let testInstance: Test;

  beforeEach(() => {
    mockedAuth = auth as jest.Mock;
    mockVerifyIdToken = jest.fn()
    mockedAuth.mockReturnValue({
      verifyIdToken: mockVerifyIdToken,
    });

    mockUserService = {
      findByUsername: jest.fn(),
    };

    testInstance = new Test(mockUserService);
  });

  test("should return user info when pass correct payload", async () => {
    const payload = 'mocked-payload';

    mockVerifyIdToken.mockResolvedValue({ email });
    mockUserService.findByUsername.mockResolvedValue(user);

    const result = await testInstance.validateUser(payload);

    expect(result).toBe(user);
    expect(mockVerifyIdToken).toHaveBeenCalledWith(payload, true);
    expect(mockUserService.findByUsername).toHaveBeenCalledWith(email);
  });
})


用户向模拟
firebase
模块的模拟工厂开玩笑

jest.mock('firebase-admin', () => {
  return {
    auth: jest.fn(),
  }
});
等级库文件的示例:

import { auth } from 'firebase-admin';
import Test from './index';

jest.mock('firebase-admin', () => {
  return {
    auth: jest.fn(),
  }
});

describe("Test", () => {
  const email = 'mocked-email@example.com';
  const user = { email, username: 'mocked-username' };

  let mockedAuth: jest.Mock;
  let mockVerifyIdToken: jest.Mock;
  let mockUserService: { findByUsername: jest.Mock }; // mock userService
  let testInstance: Test;

  beforeEach(() => {
    mockedAuth = auth as jest.Mock;
    mockVerifyIdToken = jest.fn()
    mockedAuth.mockReturnValue({
      verifyIdToken: mockVerifyIdToken,
    });

    mockUserService = {
      findByUsername: jest.fn(),
    };

    testInstance = new Test(mockUserService);
  });

  test("should return user info when pass correct payload", async () => {
    const payload = 'mocked-payload';

    mockVerifyIdToken.mockResolvedValue({ email });
    mockUserService.findByUsername.mockResolvedValue(user);

    const result = await testInstance.validateUser(payload);

    expect(result).toBe(user);
    expect(mockVerifyIdToken).toHaveBeenCalledWith(payload, true);
    expect(mockUserService.findByUsername).toHaveBeenCalledWith(email);
  });
})