Bercanda dengan NestJS dan fungsi async

Aug 18 2020

Saya mencoba menguji fungsi async dari sebuah servicedi nestJS .

fungsi ini async ... pada dasarnya mendapatkan nilai (JSON) dari database (menggunakan repositori - TypeORM), dan ketika berhasil mendapatkan datanya, "transformasikan" ke kelas yang berbeda (DTO) ... implementasinya:

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

menggunakan pengontrol, saya memeriksa bahwa ini berfungsi dengan baik. Sekarang, saya mencoba menggunakan Jest untuk melakukan tes, tetapi tidak berhasil ... Masalah saya adalah bagaimana meniru findOnefungsi dari repository..

Sunting : Saya mencoba menggunakan @golevelup/nestjs-testinguntuk mengejek Repository!

Aku sudah mengejeknya repository, tapi entah kenapa, resolvetidak pernah dipanggil ..

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);karya - karyanya bagus;
  • expect(await service.getAppConfig()).toEqual(expectedReturn);mendapat waktu tunggu => Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout;

menggunakan debug, saya melihat bahwa yang service.getAppConfig()dipanggil, repository.findOne()juga, tetapi .thenrepositori findOne tidak pernah dipanggil.

Pembaruan : Saya mencoba mengejek repositori menggunakan @golevelup/nestjs-testing, dan untuk beberapa alasan, hasil tiruan tidak berfungsi pada layanan. Jika saya mengejek repositori hanya dengan menggunakan jest(seperti kode di bawah), tesnya bekerja ... jadi, saya pikir masalah saya sebenarnya itu @golevelup/nestjs-testing.

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

Jawaban

2 RobertoCorreia Aug 21 2020 at 22:25

Jadi, masalah sebenarnya saya adalah bagaimana saya mengejek Repositorydi NestJS. Untuk beberapa alasan, ketika saya mengejek menggunakan @golevelup/nestjs-testing, hal-hal aneh terjadi!

Saya benar-benar tidak menemukan dokumentasi yang bagus tentang ini @golevelup/nestjs-testing, jadi, saya berhenti menggunakannya.

Solusi saya untuk pertanyaan itu adalah dengan hanya menggunakan Jestdan NestJSfungsi ... kode hasilnya adalah:

Layanan :

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

Tes :

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

beberapa sumber yang digunakan untuk solusi ini: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

1 Leo Aug 18 2020 at 19:53

Saya pikir expect(await repo.findOne()).toEqual(mockedConfig);berhasil karena Anda mengejeknya, jadi itu langsung kembali. Dalam kasus expect(await service.getAppConfig()).toEqual(expectedReturn);, Anda tidak memalsukannya sehingga mungkin memerlukan lebih banyak waktu, sehingga itfungsi tersebut kembali sebelum Promisediselesaikan sepenuhnya.

Komentar yang Anda posting dari dokumentasi lelucon harus melakukan trik jika Anda mengejek panggilan tersebut getAppConfig().

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

atau

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