How to test a function which consumes a callback? Or how to defer the assertion?

时间:2017-06-09 12:58:58

标签: javascript unit-testing testing jest

I use Jest to test a function which generates a JSON Web Token. It seems that I can't assert the value since when I assert, the callback hasn't been executed yet.

const issueJWT = function issueJWT(req, res, next) {
    jwt.sign(signUser, function (err, token) {
        if (err) {
            next(err);
            return;
        }
        res.locals.token = token;
        next();
    });
};

This is my test, I mock the request and response, then assert the result:

test('Should return a JWT with proper value if nothing wrong happened', () => {
    issueJWT(request, response, mockNext);

    const JWT = response.locals.token;
    const tokenPayload = jwt.decode(JWT, { complete: true }).payload;
    expect(tokenPayload).toHaveProperty('iat');
    expect(tokenPayload).toHaveProperty('exp');
    expect(tokenPayload).toHaveProperty('id');
});

The error is:

TypeError: Cannot read property 'payload' of null

How to make it work? According to my knowledge, I think the callback is at the task queue which means it will be executed when nothing is in the event loop, right? I wanna find a way to defer my assertion, but don't know how...

Thanks for the tips, I use the done, now the test could pass, but the problem is, whenever there is a problem, the error message doesn't make any sense... Any problem to my solution?

test('Should return a JWT with proper value if nothing wrong happened',  (done) => {
    const callback = () => {
        const JWT = response.locals.token;
        const tokenPayload = jwt.decode(JWT, { complete: true }).payload;

        expect(tokenPayload).toHaveProperty('iat');
        expect(tokenPayload).toHaveProperty('exp');
        expect(tokenPayload).toHaveProperty('id');
        expect(tokenPayload).toHaveProperty('iss');
        done();
    };

    issueJWT(request, response, callback);
});

The error is now:

Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

1 个答案:

答案 0 :(得分:0)

好的,所以在@felixKling的帮助下让我实际上阅读文档,你需要做这样的事情:

test('Should return a JWT with proper value if nothing wrong happened', done => {
    issueJWT(request, response, (e) => {
        const JWT = response.locals.token;
        const tokenPayload = jwt.decode(JWT, { complete: true }).payload;
        expect(tokenPayload).toHaveProperty('iat');
        expect(tokenPayload).toHaveProperty('exp');
        expect(tokenPayload).toHaveProperty('id');
        done();
    });
});

我不在我的开发盒上,所以我无法测试它,但基本上我的想法是你使用'done'参数来测试回调,以表示测试正在等待异步代码。测试框架基本上会等待你的测试在退出之前调用该回调。

在这种情况下,next()来自issueJWT的{​​{1}}来电是我们等待解雇的,然后再检查各种对象是否已更新。如果您未在中间件中使用next(),则可能需要模拟您正在调用的任何响应方法(例如response.end())来进行测试。