Search code examples
node.jstypescriptjestjsoktats-jest

Mock different responses from @okta/jwt-verifier using jest


I am using the @okta/jwt-verifier library to verify JWT's and I am trying to test this functionality by mocking the various responses from the library.

I can mock the verifyAccessToken method once for all tests however I am unsure exactly how to modify this mocked implementation to different tests i.e. the default will be a successful response returning a token however for some tests I need to mock the responses for a failed token verification i.e. an expired token.

This is what I have so far:

Implementation

const oktaJwtVerifier = new OktaJwtVerifier({
  issuer: "issuer domain",
});

export const verifyAccessToken = async (token: string) =>
  oktaJwtVerifier.verifyAccessToken(token, "audience");

Mock in tests

jest.mock("@okta/jwt-verifier", () => {
  return jest.fn().mockImplementation(() => ({
    verifyAccessToken: () => ({
      foo: "bar",
    }),
  }));
});

This mock works as expected and when the code tested call the verifyAccessToken method the mocked implementation is returned.

However I would I return a different response for different tests in the same test suite?


Solution

  • Don't pass the factory argument to jest.mock(), jest.mock() will mock a module with an auto-mocked version. You can call .mockResolvedValueOnce() in each test case to provide different mock values later.

    You can get the instance of the mocked OktaJwtVerifier class via mockFn.mock.instance

    An array that contains all the object instances that have been instantiated from this mock function using new.

    Handle the TS type for mocks using the mocked helper function of the ts-jest module. If you are using the latest Jest, use jest.mocked(source, options?) instead.

    Note: I created a simple string as the resolved value for verifyAccessToken() method, did not match the real TS return type.

    E.g.

    main.ts:

    import OktaJwtVerifier from '@okta/jwt-verifier';
    
    const oktaJwtVerifier = new OktaJwtVerifier({
        issuer: "issuer domain",
    });
    
    export const verifyAccessToken = async (token: string) =>
        oktaJwtVerifier.verifyAccessToken(token, "audience");
    

    main.test.ts:

    import OktaJwtVerifier from '@okta/jwt-verifier';
    import { verifyAccessToken } from './main';
    import { mocked } from 'ts-jest';
    
    jest.mock("@okta/jwt-verifier");
    
    const OktaJwtVerifierMock = mocked(OktaJwtVerifier)
    
    const oktaJwtVerifierInstance = mocked(OktaJwtVerifierMock.mock.instances[0]);
    
    describe('76422353', () => {
        test('should pass 1', async () => {
            oktaJwtVerifierInstance.verifyAccessToken.mockResolvedValueOnce('a' as any);
            const actual = await verifyAccessToken('1');
            expect(actual).toBe('a');
        });
    
        test('should pass 2', async () => {
            oktaJwtVerifierInstance.verifyAccessToken.mockResolvedValueOnce('b' as any);
            const actual = await verifyAccessToken('2');
            expect(actual).toBe('b');
        });
    });
    

    Test result:

     PASS  stackoverflow/76422353/main.test.ts (15.361 s)
      76422353
        ✓ should pass 1 (2 ms)
        ✓ should pass 2
    
    Test Suites: 1 passed, 1 total
    Tests:       2 passed, 2 total
    Snapshots:   0 total
    Time:        18.347 s
    

    package versions:

    "@okta/jwt-verifier": "^3.0.1",
    "jest": "^26.6.3",
    "ts-jest": "^26.4.4",