Search code examples
typescriptts-jest

Narrowing the Type of a jest.SpyInstance to Address EsLint Errors


I've written some unit tests using jest for a Github action which I am writing in Typescript. The code is all sound and the tests passing, but the linter is not happy.

The actual method under test is:

const JWKS = jose.createRemoteJWKSet<jose.KeyLike>(new URL(`${idp_url}/${jwks_endpoint}`))

I've created a small method that completes the implementation of the mock, but the linter is not happy about the use of any and I'm not sure how to narrow it:

export const buildCreateRemoteJWKSetMock = (
  createRemoteJWKSetMock: jest.SpyInstance<any, any, any>
): void => {
  createRemoteJWKSetMock.mockImplementation(
    (
      url: URL
    ): ((
      protectedHeader?: jose.JWSHeaderParameters | undefined,
      token?: jose.FlattenedJWSInput | undefined
    ) => Promise<jose.KeyLike>) =>
      (protectedHeader, token) =>
        Promise.resolve(testConstants.empty as unknown as jose.KeyLike)
  )
}

Is there an elegant way around this? I have quite a few of these in my code.


Solution

  • Don't make a function to install the mock for you. Instead just make a function that is the mock and install where you need it. Then you don't have to pass strongly typed spies around at all.

    So first make the mock itself a function:

    const createRemoteJWKSetMock = (
        url: URL
    ): ((
        protectedHeader?: jose.JWSHeaderParameters | undefined,
        token?: jose.FlattenedJWSInput | undefined
    ) => Promise<jose.KeyLike>) =>
        (protectedHeader, token) =>
        Promise.resolve(testConstants.empty as unknown as jose.KeyLike)
    

    Then pass that to mySpy.mockImplementation in your test file:

    jest
        .spyOn(jose, 'createRemoteJWKSet')
        .mockImplementation(createRemoteJWKSetMock)
    

    At each call site where you use that, that's really not very different than this:

    buildCreateRemoteJWKSetMock(
      jest.spyOn(jose, 'createRemoteJWKSet')
    )
    

    And I would argue that the former is easier to read and maintain.