Search code examples
typescriptunit-testingjestjsapolloapollo-server

Testing TypeScript with Jest: "no overload matches this call"


I'm working on testing an Apollo Server RESTDataSource using Jest. My app is written in TypeScript. My class, CDCDataSource extends the abstract class RESTDataSource which itself extends the abstract class DataSource. RESTDataSource has the method get which allows you to pull data from an external REST data source. It is this method I wish to mock, since I wish to mock the external data source.

  protected async get<TResult = any>(
    path: string,
    params?: URLSearchParamsInit,
    init?: RequestInit,
  ): Promise<TResult> {
    return this.fetch<TResult>(
      Object.assign({ method: 'GET', path, params }, init),
    );
  }

However, when I try to mock this method using Jest's spyOn -- following the second answer here: Jest: How to mock one specific method of a class --

import CDCDataSource from '../CDCDataSource';

test('Test', () => {
    let dataSource = new CDCDataSource();
    let spy = jest.spyOn(dataSource, 'get').mockImplementation(() => 'Hello');
    expect(dataSource.get()).toBe('Hello');


However, I get the TypeScript error

TS2768: No overload matches this call

over the get in jest.spyOn(dataSource,'get')

and I get

enter image description here

over the get in

expect(dataSource.get()).toBe('Hello');

So it would seem that part of the issue is that this is a protect method -- I'm unclear how to test this method so as to be able to mock the API.

My tsconfig.json is

{
  "compilerOptions": {
    "target": "ES6",
    "lib": [
      "esnext",
      "dom"
    ],
    "skipLibCheck": true,
    "outDir": "dist",
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "sourceMap": true,
    "alwaysStrict": true,
  },
  "exclude": [
    "node_modules"
  ]
}

This is a Node Apollo Server project (using Node 12.14.0 and TypeScript 3.8.3)

Thanks for any clues!


Solution

  • You are trying to access a protected method.

    If you don't want to or can't rearchitect your class, you can use ts-ignore to suppress the error.

        // @ts-ignore`
        let spy = jest.spyOn(dataSource, 'get').mockImplementation(() => 'Hello');
    

    Or you can extend the original class, with a class made only for testing, that will have a public method that will just proxy to the protected method.

    test('Protected method',()=>{
    
      class Test extends OriginalClass {
        testProtected(){
          super.protectedMethod()
        }
      }
      let dataSource = new Test();
      let spy = jest.spyOn(dataSource, 'testProtected').mockImplementation(() => 'Hello');
    })