Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you mock an Apollo Server RESTDataSource for unit testing with Jest?

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.

like image 992
Cerulean Avatar asked May 26 '20 12:05

Cerulean


People also ask

What is Apollo server GraphQL?

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.

Is Apollo Studio free?

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.


1 Answers

Unit testing

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

Integration testing

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.

TypeScript

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.

like image 111
Lauri Harpf Avatar answered Oct 20 '22 06:10

Lauri Harpf