Jest с NestJS и функцией async

Aug 18 2020

Я пытаюсь протестировать асинхронную функцию serviceв nestJS .

эта функция является асинхронной ... в основном получить значение (JSON) из базы данных (используя репозиторий - TypeORM), и при успешном получении данных "преобразовать" в другой класс (DTO) ... реализация:

async getAppConfig(): Promise<ConfigAppDto> {
  return this.configRepository.findOne({
    key: Equal("APPLICATION"),
  }).then(config => {
    if (config == null) {
      return new class implements ConfigAppDto {
        clientId = '';
        clientSecret = '';
      };
    }
    return JSON.parse(config.value) as ConfigAppDto;
  });
}

с помощью контроллера я проверил, все ли работает нормально. Теперь я пытаюсь использовать Jest для проведения тестов, но безуспешно ... Моя проблема в том, как имитировать findOneфункцию из repository..

Изменить : я пытаюсь использовать @golevelup/nestjs-testingдля издевательства Repository!

Я уже издевался над repository, но почему-то так resolveи не называется ..

describe('getAppConfig', () => {
  const repo = createMock<Repository<Config>>();

  beforeEach(async () => {
    await Test.createTestingModule({
      providers: [
        ConfigService,
        {
          provide: getRepositoryToken(Config),
          useValue: repo,
        }
      ],
    }).compile();
  });

  it('should return ConfigApp parameters', async () => {
    const mockedConfig = new Config('APPLICATION', '{"clientId": "foo","clientSecret": "bar"}');
    repo.findOne.mockResolvedValue(mockedConfig);
    expect(await repo.findOne()).toEqual(mockedConfig); // ok

    const expectedReturn = new class implements ConfigAppDto {
      clientId = 'foo';
      clientSecret = 'bar';
    };
    expect(await service.getAppConfig()).toEqual(expectedReturn);

    // jest documentation about async -> https://jestjs.io/docs/en/asynchronous
    // return expect(service.getAppConfig()).resolves.toBe(expectedReturn);
  });
})
  • expect(await repo.findOne()).toEqual(mockedConfig);отлично работает;
  • expect(await service.getAppConfig()).toEqual(expectedReturn);получил тайм-аут => Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout;

используя отладку, я вижу, что service.getAppConfig()вызывается repository.findOne()тоже, но .thenрепозиторий findOne никогда не вызывается.

Обновление : я пытаюсь имитировать репозиторий, используя @golevelup/nestjs-testing, и по какой-то причине фиктивный результат не работает в сервисе. Если я имитирую репозиторий, используя только jest(например, код ниже), тест работает ... так что я думаю, что моя настоящая проблема в этом @golevelup/nestjs-testing.

...
provide: getRepositoryToken(Config),
useValue: {
  find: jest.fn().mockResolvedValue([new Config()])
},
...

Ответы

2 RobertoCorreia Aug 21 2020 at 22:25

Таким образом, моя реальная проблема заключается в том , как я насмешливый RepositoryON NestJS. По какой-то причине, когда я издеваюсь над использованием @golevelup/nestjs-testing, происходят странные вещи!

Я действительно не нашел хорошей документации по этому поводу @golevelup/nestjs-testing, поэтому отказался от ее использования.

Мое решение вопроса было использовать только Jestи NestJSфункции ... код результата был:

Сервис :

// i'm injecting Connection because I need for some transactions later;
constructor(@InjectRepository(Config) private readonly configRepo: Repository<Config>, private connection: Connection) {}

async getAppConfig(): Promise<ConfigApp> {
  return this.configRepo.findOne({
    key: Equal("APPLICATION"),
  }).then(config => {
    if (config == null) {
      return new ConfigApp();
    }
    return JSON.parse(config.value) as ConfigApp;
  })
}

Тест :

describe('getAppConfig', () => {
  const configApi = new Config();
  configApi.key = 'APPLICATION';
  configApi.value = '{"clientId": "foo", "clientSecret": "bar"}';

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ConfigAppService,
        {
          provide: getRepositoryToken(Config),
          useValue: {
            findOne: jest.fn().mockResolvedValue(new
            Config("APPLICATION", '{"clientId": "foo", "clientSecret": "bar"}')),
          },
        },
        {
          provide: getConnectionToken(),
          useValue: {},
        }
      ],
    }).compile();

    service = module.get<ConfigAppService>(ConfigAppService);
  });

  it('should return ConfigApp parameters', async () => {
    const expectedValue: ConfigApp = new ConfigApp("foo", "bar");

    return service.getAppConfig().then(value => {
      expect(value).toEqual(expectedValue);
    })
  });
})

некоторые источники, использованные для этого решения: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

1 Leo Aug 18 2020 at 19:53

Я думаю expect(await repo.findOne()).toEqual(mockedConfig);работает, потому что вы над ним издевались, поэтому он сразу возвращается. В случае expect(await service.getAppConfig()).toEqual(expectedReturn);, если вы не издевались над этим, вероятно, это займет больше времени, поэтому itфункция возвращается до того, как Promiseбудет полностью разрешена.

Комментарии, которые вы разместили из документации jest, должны помочь, если вы имитируете вызов getAppConfig().

service.getAppConfig = jest.fn(() => Promise.resolve(someFakeValue))

или же

spyOn(service, 'getAppConfig').and.mockReturnValue(Promise.resolve(fakeValue))