Насмешливая функция Firebase с шуткой (модульное тестирование)

# #node.js #typescript #firebase #unit-testing #jestjs

Вопрос:

Я создаю модульные тесты, но я могу найти способ имитировать функции firebase и уточнять тип возвращаемого значения при их вызове. Ниже я опубликовал то, что я хочу высмеять(account.service.ts), и какой тест у меня есть в настоящее время. Я хочу поиздеваться и указать, что должно быть возвращено с помощью администратора… (он же задает значение объекта resp).

импорт * в качестве администратора из «firebase-администратор»;

учетная запись.сервис.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);
        });
 

учетная запись.сервис.спецификация.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);
        });
    });
});
 

Комментарии:

1. Откуда берется этот admin предмет?

2. импорт * в качестве администратора из «firebase-администратор»;

Ответ №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 amp;amp;
      !Array.isArray(data) amp;amp;
      typeof data === 'object' amp;amp;
      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)
        })
      })
    })
  })
}) 

Комментарии:

1. Большое спасибо. Я собираюсь использовать это в качестве ссылки и посмотреть, смогу ли я выполнить свои тесты. Я закрою вопрос, если мне удастся решить задачу тестирования.