Jest con NestJS e la funzione async

Aug 18 2020

Sto provando a testare una funzione asincrona di servicein nestJS .

questa funzione è asincrona ... fondamentalmente ottiene un valore (JSON) dal database (utilizzando il repository - TypeORM), e quando ottiene i dati con successo, "trasforma" in una classe diversa (DTO) ... l'implementazione:

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

utilizzando un controller, ho verificato che funzionasse correttamente. Ora, sto cercando di utilizzare Jest per eseguire i test, ma senza successo ... Il mio problema è come deridere la findOnefunzione da repository..

Modifica : sto cercando di usare @golevelup/nestjs-testingper deridere Repository!

L'ho già preso in giro repository, ma per qualche motivo resolvenon viene mai chiamato ..

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);
  });
})
  • le expect(await repo.findOne()).toEqual(mockedConfig);opere alla grande;
  • expect(await service.getAppConfig()).toEqual(expectedReturn);ha ottenuto un timeout => Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout;

usando debug, vedo che service.getAppConfig()viene chiamato repository.findOne()anche il, ma il .thenrepository of di findOne non viene mai chiamato.

Aggiornamento : sto cercando di deridere il repository usando @golevelup/nestjs-testinge, per qualche motivo, il risultato deriso non funziona sul servizio. Se derido il repository usando solo jest(come il codice sotto), il test funziona ... quindi, penso che il mio vero problema sia @golevelup/nestjs-testing.

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

Risposte

2 RobertoCorreia Aug 21 2020 at 22:25

Quindi, il mio vero problema è come sto prendendo in giro l' Repositoryon NestJS. Per qualche ragione, quando derido di usare il @golevelup/nestjs-testing, accadono cose strane!

Non ho davvero trovato una buona documentazione su questo @golevelup/nestjs-testing, quindi ho smesso di usarlo.

La mia soluzione per la domanda era usare solo Jeste NestJSfunctions ... il codice del risultato era:

Servizio :

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

Prova :

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

alcune fonti utilizzate per questa soluzione: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

1 Leo Aug 18 2020 at 19:53

Penso expect(await repo.findOne()).toEqual(mockedConfig);che funzioni perché l'hai preso in giro, quindi torna subito. Nel caso di expect(await service.getAppConfig()).toEqual(expectedReturn);, non l'hai preso in giro, quindi probabilmente ci vuole più tempo, quindi la itfunzione ritorna prima che si Promiserisolva completamente.

I commenti che hai postato dalla documentazione jest dovrebbero fare il trucco se deridi la chiamata a getAppConfig().

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

o

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