Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest with NestJS and async function

I'm trying to a test a async function of a service in nestJS.

this function is async... basically get a value (JSON) from database (using repository - TypeORM), and when successfully get the data, "transform" to a different class (DTO)... the implementation:

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

using a controller, I checked that this worked ok. Now, I'm trying to use Jest to do the tests, but with no success... My problem is how to mock the findOne function from repository..

Edit: I'm trying to use @golevelup/nestjs-testing to mock Repository!

I already mocked the repository, but for some reason, the resolve is never called..

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);
  });
})
  • the expect(await repo.findOne()).toEqual(mockedConfig); works great;
  • expect(await service.getAppConfig()).toEqual(expectedReturn); got a timeout => Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout;

using debug, I see that the service.getAppConfig() is called, the repository.findOne() too, but the .then of repository of findOne is never called.

Update: I'm trying to mock the repository using @golevelup/nestjs-testing, and for some reason, the mocked result don't works on service. If I mock the repository using only jest (like code below), the test works... so, I think my real problem it's @golevelup/nestjs-testing.

...
provide: getRepositoryToken(Config),
useValue: {
  find: jest.fn().mockResolvedValue([new Config()])
},
...
like image 652
Roberto Correia Avatar asked Oct 22 '25 22:10

Roberto Correia


1 Answers

So, my real problem is how I'm mocking the Repository on NestJS. For some reason, when I mock using the @golevelup/nestjs-testing, weird things happens!

I really don't found a good documentation about this on @golevelup/nestjs-testing, so, I gave up using it.

My solution for the question was to use only Jest and NestJS functions... the result code was:

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

some sources utilized for this solution: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

like image 97
Roberto Correia Avatar answered Oct 25 '25 20:10

Roberto Correia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!