【问题标题】:How to mock external dependency in typescript using jest如何使用 jest 在 typescript 中模拟外部依赖
【发布时间】:2022-03-30 18:02:21
【问题描述】:

我绝望地试图在 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;
 }
}

我正在尝试通过模拟 admin 函数来测试 admin.auth().verifyIdToken(payload, true)。我尝试了如下所示的测试代码

import {auth} from 'firebase-admin';

jest.mock('firebase-admin');

const mockedAuth = auth as jest.Mock;

mockedAuth.mockReturnValue({
  verifyIdToken: jest.fn().mockResolvedValue(true),
});

但我收到一条错误消息:TypeError: Cannot read property 'mockReturnValue' of undefined

如果我理解正确,我通过调用jest.mock('firebase-admin') 来模拟整个firebase-admin 包。所以我希望能够调用mockReturnValue 并再次在auth 函数中模拟verifyIdToken 函数。但是,我什至不能打电话给mockReturnValue,因为奇怪的是它似乎不存在。

我需要如何编写代码才能模拟来自auth().verifyIdToken() 的解析值?

【问题讨论】:

    标签: typescript unit-testing jestjs


    【解决方案1】:

    使用 jest mock factory 模拟 firebase 模块。

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

    spec 文件示例:

    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);
      });
    })
    
    

    【讨论】:

      【解决方案2】:

      这种情况下的问题是authfirebase-admin 中的类似导出函数被定义为带有Object.defineProperty 的getter。不幸的是,jest.mock 在评估模块时看不到这些,因此它不会为它们添加模拟。

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

      jest.mock('firebase-admin', () =>
      {
        const module = jest.createMockFromModule<any>('firebase-admin').default;
        module.auth = jest.fn();
        return module;
      });
      

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

      【讨论】:

        猜你喜欢
        • 2018-07-23
        • 2018-01-21
        • 2020-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-10
        • 2020-12-03
        相关资源
        最近更新 更多