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

时间:2020-09-08 14:17:47

标签: javascript node.js unit-testing es6-promise sinon

我有此身份验证中间件:

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有关?我怀疑是这样的,因为我还添加了许多其他函数来返回promise,但这是第一个引发此类错误的函数。

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

编辑:

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

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

1 个答案:

答案 0 :(得分:1)

单元测试解决方案:

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/stackoverflow/63795862