I'm trying to test a data source in my Apollo Server that based on Apollo Server's RESTDataSource
(https://www.apollographql.com/docs/apollo-server/data/data-sources/#rest-data-source). I'm trying to test it using Jest. The class has methods that pull in data from an external REST API, as well as from another module that calls a second API (so this RESTDataSource
ultimately depends on two external APIs, one of which is called directly here, and one of which is called indirectly).
I'm not an expert on testing, and I'm unclear how to mock the external APIs. GraphQL Tools has some tools that allow you to mock your server, but I'm not sure that's what I want. Or should I use Jest's methods for mocking ES6 classes, forgetting that this is a GraphQL server? If so, since I'm working with a class
, do I just mock the methods using something like MyClass.myMethod
as the mocked method?
Does anything change in how I do this if I'm using TypeScript (which I am), other than setting up Jest to work with TypeScript?
Obviously the correct route is to pick one of the options above, but I'm a bit 'not seeing the forest for the trees', that is, due to my inexperience with testing, I don't know which of these is the correct route to follow.
Thanks for any clues.
Apollo Server is an open-source, spec-compliant GraphQL server that's compatible with any GraphQL client, including Apollo Client. It's the best way to build a production-ready, self-documenting GraphQL API that can use data from any source.
Apollo Studio is a cloud platform that helps you with every phase of GraphQL development, from prototyping to deploying to monitoring. Studio's core features are free for everyone.
You can unit test your data source by mocking the RESTDataSource
in apollo-datasource-rest
as suggested in apollo-datasource-rest + Typescript + Jest in the Apollo Spectrum chat.
For this data source:
import { RESTDataSource } from 'apollo-datasource-rest'
export class MyRestDataSource extends RESTDataSource {
async getStackoverflow(): Promise<string> {
return this.get('https://stackoverflow.com/')
}
}
You could write an unit test like this:
import { MyRestDataSource } from './MyRestDataSource'
const mockGet = jest.fn()
jest.mock('apollo-datasource-rest', () => {
class MockRESTDataSource {
baseUrl = ''
get = mockGet
}
return {
RESTDataSource: MockRESTDataSource,
}
})
describe('MyRestDataSource', () => {
it('getStackoverflow gets data from correct URL', async () => {
const datasource = new MyRestDataSource()
await datasource.getStackoverflow()
expect(mockGet).toBeCalledWith('https://stackoverflow.com/')
})
})
Rather than unit testing the data sources, I'd in most cases prefer integration testing with e.g. apollo-server-testing: you run GraphQL against the server and test the entire path from the resolver to the data source. If you do so, consider using e.g. nock to mock the HTTP requests the data sources make.
The general approaches should be the same regardless of whether you're using TypeScript or JavaScript with just some minor differences. E.g. with JavaScript, your unit test could directly replace the get
in the data source:
const MyRestDataSource = require('./MyRestDataSource')
describe('MyRestDataSource', () => {
it('getStackoverflow gets data from correct URL', async () => {
const datasource = new MyRestDataSource()
datasource.get = jest.fn()
await datasource.getStackoverflow()
expect(datasource.get).toBeCalledWith('https://stackoverflow.com/')
})
})
but with TypeScript that would cause a compiler error as get
is protected:
MyRestDataSource.test.ts:6:16 - error TS2445: Property 'get' is protected and only accessible within class 'RESTDataSource' and its subclasses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With