【问题标题】:Mocking Firebase function with Jest (Unit testing)用 Jest 模拟 Firebase 功能(单元测试)
【发布时间】:2021-10-13 07:59:03
【问题描述】:

我正在创建单元测试,但我可以找到一种方法来模拟 firebase 函数并在调用它们时指定返回类型。下面我发布了我想要模拟的内容(account.service.ts)以及我当前进行的测试。我想模拟并指定要使用 admin 返回的内容...(也就是设置 resp 对象值)。

以管理员身份从“firebase-admin”导入 *;

account.service.ts

    const resp = admin
        .auth()
        .createUser({
            email: registerDto.email,
            emailVerified: false,
            password: registerDto.password,
            displayName: registerDto.displayName,
            disabled: false,
        })
        .then(
            (userCredential): Account => ({
                uid: userCredential.uid,
                email: userCredential.email,
                emailVerified: userCredential.emailVerified,
                displayName: userCredential.displayName,
                message: 'User is successfully registered!',
            }),
        )
        .catch((error) => {
            // eslint-disable-next-line max-len
            throw new HttpException(`${'Bad Request Error creating new user: '}${error.message}`, HttpStatus.BAD_REQUEST);
        });

account.service.spec.ts

describe('61396089', () => {
        afterEach(() => {
            jest.restoreAllMocks();
        });

        const obj = {
            uid: 'uid',
            email: 'email',
            emailVerified: 'emailVerified',
            displayName: 'displayName',
            message: 'User is successfully registered!',
        };

        const jestAdminMock = {
            admin: () => ({
                auth: () => ({
                    createUser: () => ({
                        then: () => ({
                            catch: () => obj,
                        }),
                    }),
                }),
            }),
        };

        it('should pass', () => {
            const mockDataTable = {
                admin: jest.fn().mockReturnThis(),
                auth: jest.fn().mockReturnThis(),
                createUser: jest.fn().mockReturnThis(),
                then: jest.fn().mockReturnThis(),
                catch: jest.fn().mockReturnValueOnce(obj),
            };
            jest.spyOn(jestAdminMock, 'admin').mockImplementationOnce(() => mockDataTable);
            const actual = service.registerUser(registerDTO);
            expect(actual).toBe(obj);
        });
    });
});

【问题讨论】:

  • admin 对象从何而来?
  • 以管理员身份从 'firebase-admin' 导入 *;

标签: node.js typescript firebase unit-testing jestjs


【解决方案1】:

我设法做了一个像这个例子这样的测试

这是函数

import admin from 'firebase-admin'

admin.initializeApp({
  credential: admin.credential.cert(credentials),
})

const createClosure = (admin) => {
  if (!admin) {
    throw new Error(Errors.FIREBASE_ADMIN_SDK_NOT_PROVIDED)
  }
  return (data) => {
    if (
      data &&
      !Array.isArray(data) &&
      typeof data === 'object' &&
      Object.keys(data).length > 0
    ) {
      const { firstName, lastName } = data
      const displayName = `${firstName} ${lastName}`
      return admin.auth().createUser({ ...data, displayName })
    }
    throw new Error(Errors.INVALID_DATA)
  }
}

/*
.....
*/

const create = createClosure(admin)

export { create, createClosure }

这是一个测试示例

import { createClosure } from "../path/to/function"

describe('createClosure', () => {
  it('should be a function', () => {
    expect(typeof createClosure).toBe('function')
  })

  describe('when admin is not provided', () => {
    it('should throw "Firebase Admin SDK not provided"', () => {
      const expected = Errors.FIREBASE_ADMIN_SDK_NOT_PROVIDED
      expect(() => createClosure()).toThrow(expected)
    })
  })
  describe('when admin is provided', () => {
    describe('when data is invalid', () => {
      const createUser = jest.fn()
      const admin = {
        auth: () => ({
          createUser,
        }),
      }
      const data1 = 123
      const data2 = 'hello'
      const data3 = ['a', 'b', 'c']
      const data4 = {}

      it('should throw "Invalid data"', () => {
        expect(() => createClosure(admin)()).toThrow(Errors.INVALID_DATA)
        expect(() => createClosure(admin)(data1)).toThrow(Errors.INVALID_DATA)
        expect(() => createClosure(admin)(data2)).toThrow(Errors.INVALID_DATA)
        expect(() => createClosure(admin)(data3)).toThrow(Errors.INVALID_DATA)
        expect(() => createClosure(admin)(data4)).toThrow(Errors.INVALID_DATA)
      })
    })
    describe('when data is valid', () => {
      const data = {
        firstName: 'Alice',
        lastName: 'Alley',
        foo: 'bar',
        baz: {
          boo: 'bii',
          buu: 'byy',
        },
      }
      describe('when createUser rejects', () => {
        const e = new Error('Error happened!')
        const createUser = jest.fn().mockRejectedValue(e)
        const admin = {
          auth: () => ({
            createUser,
          }),
        }
        const create = createClosure(admin)
        it('should call createUser once', async () => {
          try {
            await createUser(data)
          } catch (error) {}
          expect(createUser).toBeCalledTimes(1)
          expect(createUser).toBeCalledWith({ ...data })
        })
        it('should reject', async () => {
          await expect(create(data)).rejects.toEqual(e)
        })
      })
      describe('when save resolves', () => {
        const expected = {
          baz: { boo: 'bii', buu: 'byy' },
          displayName: 'Alice Alley',
          lastName: 'Alley',
        }
        const displayName = `${data.firstName} ${data.lastName}`
        const createUser = jest.fn().mockResolvedValue(expected)
        const admin = {
          auth: () => ({
            createUser,
          }),
        }
        const create = createClosure(admin)
        it('should call save once', async () => {
          try {
            await create(data)
          } catch (error) {}
          expect(createUser).toBeCalledTimes(1)
          expect(createUser).toBeCalledWith({ ...data, displayName })
        })
        it('should resolve', async () => {
          const result = await create(data)
          expect(result).toMatchObject(expected)
        })
      })
    })
  })
})

【讨论】:

  • 非常感谢。我将使用它作为参考,看看我是否可以运行我的测试。如果我设法解决测试,我将关闭问题。
猜你喜欢
  • 1970-01-01
  • 2016-01-27
  • 2021-05-27
  • 1970-01-01
  • 2019-02-12
  • 2019-09-08
  • 2021-05-22
  • 2021-11-05
  • 1970-01-01
相关资源
最近更新 更多