Jest avec NestJS et fonction asynchrone

Aug 18 2020

J'essaye de tester une fonction asynchrone d'un servicedans nestJS .

cette fonction est asynchrone ... en gros, obtenir une valeur (JSON) de la base de données (en utilisant le référentiel - TypeORM), et quand obtenir les données avec succès, "transformer" en une classe différente (DTO) ... l'implémentation:

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

en utilisant un contrôleur, j'ai vérifié que cela fonctionnait bien. Maintenant, j'essaie d'utiliser Jest pour faire les tests, mais sans succès ... Mon problème est de savoir comment se moquer de la findOnefonction repository...

Edit : j'essaye de me @golevelup/nestjs-testingmoquer Repository!

Je me suis déjà moqué du repository, mais pour une raison quelconque, le resolven'est jamais appelé ..

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);
  });
})
  • les expect(await repo.findOne()).toEqual(mockedConfig);œuvres très bien;
  • expect(await service.getAppConfig()).toEqual(expectedReturn);obtenu un délai => Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout;

en utilisant le débogage, je vois que le service.getAppConfig()est appelé, le repository.findOne()aussi, mais le .thenréférentiel of de findOne n'est jamais appelé.

Mise à jour : j'essaie de me moquer du référentiel en utilisant @golevelup/nestjs-testing, et pour une raison quelconque, le résultat simulé ne fonctionne pas sur le service. Si je me moque du référentiel en utilisant uniquement jest(comme le code ci-dessous), le test fonctionne ... donc, je pense que mon vrai problème est @golevelup/nestjs-testing.

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

Réponses

2 RobertoCorreia Aug 21 2020 at 22:25

Donc, mon problème est de savoir comment je suis moqueur le Repositorysur NestJS. Pour une raison quelconque, lorsque je me moque de l'utilisation de @golevelup/nestjs-testing, des choses étranges se produisent!

Je n'ai vraiment pas trouvé de bonne documentation à ce sujet @golevelup/nestjs-testing, alors j'ai renoncé à l'utiliser.

Ma solution pour la question était d'utiliser uniquement Jestet des NestJSfonctions ... le code de résultat était:

Service :

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

Test :

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

quelques sources utilisées pour cette solution: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

1 Leo Aug 18 2020 at 19:53

Je pense expect(await repo.findOne()).toEqual(mockedConfig);que ça marche parce que tu t'es moqué de ça, donc ça revient tout de suite. Dans le cas de expect(await service.getAppConfig()).toEqual(expectedReturn);, vous ne vous en êtes pas moqués, donc cela prend probablement plus de temps, donc la itfonction retourne avant la Promiserésolution complète.

Les commentaires que vous avez publiés à partir de la documentation de plaisanterie devraient faire l'affaire si vous vous moquez de l'appel à getAppConfig().

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

ou

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