简体   繁体   中英

Can I use async/await in Jest, when the tested function is not using async/await?

I have a simple controller for adding new users. After the successful resolution (user added), the controller sends a 202 response. As you can see, the function is using then/catch and is not using async/await.

const addUserController = function (req, res, next) {
    Users.addOne(req.userid, req.body.email)
    .then(() => {
      res.status(202).send();
    })
    .catch((err) => {
      console.log(err);
      res.status(500).json({ message: "Internal server error." });
    });
};

When I am testing this function in Jest with the, the function executes immediately, without going to the then() part, resulting in a mistaken 200 code, instead of 202, so the following test fails:

it("Should add a user", () => {
    let req, res, next, pool;
    pool = new Pool();
    req = httpsMocks.createRequest();
    res = httpsMocks.createResponse();
    res.next = null;
    req.userid = 1;
    req.body = {
      id: 2
    }
    pool.query.mockResolvedValue({rows:[], rowCount: 1});
    apiController.addUserController(req, res, next);
    expect(res.statusCode).toBe(202);
    expect(pool.query).toBeCalledTimes(1);
});

However, when I make it like that:

it("Should add a user", async () => {
    let req, res, next, pool;
    pool = new Pool();
    req = httpsMocks.createRequest();
    res = httpsMocks.createResponse();
    res.next = null;
    req.userid = 1;
    req.body = {
      id: 2
    }
    pool.query.mockResolvedValue({rows:[], rowCount: 1});
    await apiController.addUserController(req, res, next);
    expect(res.statusCode).toBe(202);
    expect(pool.query).toBeCalledTimes(1);
});

that is I add async/await, it works alright - the response status code is 202, meaning the function was awaited and the test passes. But why? When I hover over the newly added 'await' VS code is suggesting that

'await' has no effect on the type of this expression.

Well it makes sense - it should have no effect, as the tested function is not async, so it shouldn't work, but well, it works - only when I add the async/await to the Jest function it works fine.

Could someone explain this to me?

I add async/await, it works alright - the response status code is 202, meaning the function was awaited and the test passes. But why?

No, as you concluded from the missing return value, the function is not awaited. Your code is equivalent to

apiController.addUserController(req, res, next);
await undefined;

Now, why does it still make a difference? Because with the await , the test is waiting a tiny bit before running the expect() calls, and that tiny bit is enough for your mocked pool to return a value and have the first .then() handler be executed.

However, you now basically introduced a race condition. Having a longer promise chain in the addUserController would make the test fail. Maybe even a test for the 500 status being created in .then().catch() might already not work.

This is very fragile, don't write a test like that. One solution would be to simply return the promise chain from addUserController and await it - as long as no other callers will be confused by that, it's the simple fix. Another solution is to actually wait for the mock response to be actually sent. If I read the docs of node-mocks-http right, something like this should work:

it("Should add a user", async () => {
    const { once, EventEmitter } = require('events');
    const pool = new Pool();
    const req = httpsMocks.createRequest();
    const res = httpsMocks.createResponse({ eventEmitter: EventEmitter });
    res.next = null;
    req.userid = 1;
    req.body = {
      id: 2
    }
    pool.query.mockResolvedValue({rows:[], rowCount: 1});
    const responseEndPromise = once(res, 'end');
    
    apiController.addUserController(req, res, next);
    await responseEndPromise;

    expect(res.statusCode).toBe(202);
    expect(pool.query).toBeCalledTimes(1);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM