有没有办法在函数中模拟 Promise.resolve

is there a way to mock the the Promise.resolve in a function

所以我尝试模拟一个 jwt.verify 函数。下面是函数本身,然后是模拟。

try {
    const decodedJwt = new Promise((resolve, reject) => {
      jwt.verify(
        token,
        getPublicKey,

        {
          algorithms: ['RS256'],
          ignoreExpiration: false,
        },
        (decodeError, decodedValue) => {
          if (decodeError) {
            reject(decodeError);
          }
          resolve(decodedValue);
        }
      );
    });

    return await decodedJwt;
  } catch (error) {
    logger.error(error);
    return null;
  }

验证部分的 Mock

export const jwtVerifyMock = jest.fn();

jest.mock('jsonwebtoken', () => {
  return {
    decode: jwtDecodeMock,
    verify: jwtVerifyMock,
  };
});

那么这就是我在测试中使用它的方式

it('decodeJWT should should verify token', async () => {
    jwtVerifyMock.mockImplementation(async () => Promise.resolve({ exp: config.exp }));
    return decodeJwt(config.jwtToken, true).then(async (value) => {
      console.log('payload2', value);

      const payload = value as Record<string, unknown>;
      expect(payload.exp).toEqual(config.exp);
    });
  });

但由于某种原因,它没有得到解决。我得到一个

Async callback was not invoked within the 60000 ms timeout Error

我尝试使用 mockReturn 值,但效果不佳。所以接下来我猜测是作为回调传递给 jwt.verify 的 resolve 函数是我的问题所在。

您应该模拟 jwt.verify() 的实现并使用不同的参数手动执行回调函数。

例如

decode.ts:

import jwt from 'jsonwebtoken';

export async function decode(token, getPublicKey) {
  try {
    const decodedJwt = new Promise((resolve, reject) => {
      jwt.verify(
        token,
        getPublicKey,

        {
          algorithms: ['RS256'],
          ignoreExpiration: false,
        },
        (decodeError, decodedValue) => {
          if (decodeError) {
            reject(decodeError);
          }
          resolve(decodedValue);
        }
      );
    });

    return await decodedJwt;
  } catch (error) {
    console.error(error);
    return null;
  }
}

decode.test.ts:

import { decode } from './decode';
import jwt, { JsonWebTokenError } from 'jsonwebtoken';

describe('66966317', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should decode value', async () => {
    const decodedvalue = { name: 'teresa teng' };
    const verifySpy = jest.spyOn(jwt, 'verify').mockImplementationOnce((token, getPublicKey, options, callback) => {
      callback!(null, decodedvalue);
    });
    const actual = await decode('teresa teng', true);
    expect(actual).toEqual({ name: 'teresa teng' });
    expect(verifySpy).toBeCalledWith(
      'teresa teng',
      true as any,
      { algorithms: ['RS256'], ignoreExpiration: false },
      expect.any(Function)
    );
  });

  it('should handle decode error', async () => {
    const decodedError = new JsonWebTokenError('network');
    const verifySpy = jest.spyOn(jwt, 'verify').mockImplementationOnce((token, getPublicKey, options, callback) => {
      callback!(decodedError, undefined);
    });
    const actual = await decode('teresa teng', true);
    expect(actual).toBeNull();
    expect(verifySpy).toBeCalledWith(
      'teresa teng',
      true as any,
      { algorithms: ['RS256'], ignoreExpiration: false },
      expect.any(Function)
    );
  });
});

单元测试结果:

 PASS  examples/66966317/decode.test.ts (7.701 s)
  66966317
    ✓ should decode value (3 ms)
    ✓ should handle decode error (17 ms)

  console.error
    JsonWebTokenError { name: 'JsonWebTokenError', message: 'network' }

      23 |     return await decodedJwt;
      24 |   } catch (error) {
    > 25 |     console.error(error);
         |             ^
      26 |     return null;
      27 |   }
      28 | }

      at Object.<anonymous> (examples/66966317/decode.ts:25:13)
          at Generator.throw (<anonymous>)
      at rejected (examples/66966317/decode.ts:1046:32)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 decode.ts |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        8.749 s