Intro and TL; DR
In last article: https://jczhang.com/2022/08/08/startup-mvp-recipes-9-nest-js-typeorm-postgres-unit-testing-service-onlywith-jest-pg-mem/, we had a first glance at how to setup unit test with jest, and inject an in-memory postgres for testing the services.
Now we move back to write unit tests for resolvers, and the idea and philosophy here is too test the resolver interface only: we should isolate the resolver and don’t call the real service. Otherwise if the service fail the resolve will also fail and the resolver unit test are not “unit test” anymore, but more like e2e tests. Therefore, instead, we will mock the service and return the mocked result directly.
A quick takeaway from the approach to be introduced is that it will mock the service from the beginning so the actual test code is even longer than the resolver code itself. And since most of our resolvers are just interfaces, we won’t get every resolver covered with test: it will be a overkill at startups.
References
- Official doc https://docs.nestjs.com/fundamentals/testing
The Setup
We will use @golevelup/ts-jest
to create universal mock with Typescript interfaces
npm i @golevelup/ts-jest
The Code
Here is the code and here are some explanations:
- We mock the service by creating custom functions that directly return the result
- The returned result may not be type compatible and we will also use
createMock<>()
to solve the issue - We create the mock service and override it in the original module provider
describe('SmsTemplatesResolver', () => {
let resolver: SmsTemplatesResolver;
let service: SmsTemplatesService;
beforeAll(async () => {
service = createMock<SmsTemplatesService>({
createOneBySellerId: async (
sellerId: number,
createSmsTemplateInput: CreateSmsTemplateInput,
) => {
return createMock<SmsTemplate>({
id: 1,
sellerId,
...createSmsTemplateInput,
cohort: createSmsTemplateInput.cohort ?? 'newsletter',
});
},
});
const module: TestingModule = await Test.createTestingModule({
providers: [SmsTemplatesResolver, SmsTemplatesService],
})
.overrideProvider(SmsTemplatesService)
.useValue(service)
.compile();
resolver = module.get<SmsTemplatesResolver>(SmsTemplatesResolver);
});
it('should be defined', () => {
expect(resolver).toBeDefined();
});
it('should create one', async () => {
const createSmsTemplateInput: CreateSmsTemplateInput = {
name: 'Test Template',
content: 'Test',
cohort: 'newsletter',
};
const result = await resolver.createSmsTemplate(
766,
createSmsTemplateInput,
);
ObjectTyped.keys(createSmsTemplateInput).forEach((key) => {
expect(result[key]).toEqual(createSmsTemplateInput[key]);
});
});
});
Pingback: [Startup MVP recipes #11] Nest.js Run Unit Tests with Github Actions - James Zhang