为什么我承诺的存根方法没有解决?

Why my promisifed stub method doesn't resolve?

我有这个认证中间件:

import { promisify } from 'util';

async function verifyToken(req, res, next) {
    const [type, token] = req.headers.authorization.split(' ');

    try {
         const decoded = await promisify(jwt.verify)(token, process.env.SECRET);
         
         req.userId = decoded.id;
         
         return next();
    } catch (error) {
         return res.status(401).json({ message: 'Invalid token.' });
    }
}

这就是我测试它的方式:

it('should return next and inject user id into the request', async () => { 
    req.headers.authorization = 'Bearer 1234577920fsdaf';

    sandbox.stub(jwt, 'verify').resolves({ id: 'bj435çsfkj' });

    await verifyToken(req, res, next);

    expect(req.userId).to.equal('bj435çsfkj');
    expect(next.calledOnce).to.be.true;
});

但是,在我看来,诺言并没有解决。当我 运行 测试时,我在那次测试中得到 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves。也许和promisify有关?我怀疑它确实如此,因为我已经标记了 return 承诺的许多其他函数,但这是第一个引发此类错误的函数。

在这种情况下,我如何正确存根 jwt.verify

编辑:

jwt.verify 来自 jsonwebtoken 包并具有以下签名:

jwt.verify(token, secretOrPublicKey, [options, callback])

单元测试解决方案:

index.ts:

import { promisify } from "util";
import jwt from "jsonwebtoken";

async function verifyToken(req, res, next) {
  const [type, token] = req.headers.authorization.split(" ");
  try {
    // @ts-ignore
    const decoded = await promisify(jwt.verify)(token, process.env.SECRET || "");
    // @ts-ignore
    // eslint-disable-next-line require-atomic-updates
    req.userId = decoded.id;
    return next();
  } catch (error) {
    return res.status(401).json({ message: "Invalid token." });
  }
}

export { verifyToken };

index.test.ts:

import { verifyToken } from ".";
import sinon from "sinon";
import jwt from "jsonwebtoken";
import { expect } from "chai";

const sandbox = sinon.createSandbox();

describe("63795862", () => {
  afterEach(() => {
    sandbox.restore();
  });
  it("should return next and inject user id into the request", async () => {
    const req = { userId: "", headers: { authorization: "Bearer 1234577920fsdaf" } };
    const res = {};
    const next = sandbox.stub();

    const verifyStub = sandbox.stub(jwt, "verify").callsFake((token, secretOrPublicKey, callback: any) => {
      callback(null, { id: "bj435çsfkj" });
    });

    await verifyToken(req, res, next);
    sandbox.assert.calledWithExactly(verifyStub, "1234577920fsdaf", "", sinon.match.func);
    expect(req.userId).to.equal("bj435çsfkj");
    expect(next.calledOnce).to.be.true;
  });

  it("should return 401 status error", async () => {
    const req = { userId: "", headers: { authorization: "Bearer 1234577920fsdaf" } };
    const res = { status: sandbox.stub().returnsThis(), json: sandbox.stub() };
    const next = sandbox.stub();
    const mError = new Error("invalid token");
    sandbox.stub(jwt, "verify").callsFake((token, secretOrPublicKey, callback: any) => {
      callback(mError);
    });

    await verifyToken(req, res, next);

    expect(req.userId).to.equal("");
    sinon.assert.calledWithExactly(res.status, 401);
    sinon.assert.calledWithExactly(res.json, { message: "Invalid token." });
  });
});

带有覆盖率报告的单元测试结果:

  63795862
    ✓ should return next and inject user id into the request
    ✓ should return 401 status error


  2 passing (24ms)

---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |      100 |      100 |      100 |      100 |                   |
 index.test.ts |      100 |      100 |      100 |      100 |                   |
 index.ts      |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|

源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/Whosebug/63795862