1

I'm trying to test a nodejs function using Jest. I'm a complete beginner in Jest, so I assume this is a problem in the way I have structured my tests.

When called manually or from within the application, the function works fine. But when called from a Jest test, it either times out, returns an empty object or otherwise falls over.

The function to be tested:

async function createUser(username, password){
    try{
        const user = await UserModel.create({ username, password });
        return true;
    } catch(error){
        if(error.code == 11000){
            const field = Object.keys(error.keyValue);
            const err = Error("Account with username " + field + " already exists");
            throw err;
        }
        if(error.name == 'ValidationError'){
            const err = Error("Error creating new user");
            throw err;
        }
        const err = Error("Unknown error creating new user");
        throw err;
    }
}

and the Jest tests I have created:

test('createUser: Non empty input should create account and return true', async () => {
    const data = await register.createUser('johnsmith1', 'smithjohn');
    expect(data).toBe(true);
});

test('createUser: Duplicate user/pass should not create user and should throw error', async () => {
    try{
        await register.createUser('johnsmith1', 'smithjohn');
    } catch(error){
        expect(error).toMatch('error');
    }
});

When run both tests timeout:

createUser: Duplicate user/pass should not create user and should throw error

    thrown: "Exceeded timeout of 5000 ms for a test.
    Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

      74 | });
      75 |
    > 76 | test('createUser: Duplicate user/pass should not create user and should throw error', async () => {
         | ^
      77 |     try{
      78 |         await register.createUser('johnsmith1', 'smithjohn');
      79 |     } catch(error){

      at Object.test (tests/register.test.js:76:1)
bobe
  • 11
  • 2

2 Answers2

0

Your createUser takes more than 5 seconds, which is the default timeout in jest.

In order to increase the timeout only for a single test, as a third param to the test function.

More info here: jset setTimeout per test

test('createUser: Non empty input should create account and return true', async () => {
    const data = await register.createUser('johnsmith1', 'smithjohn');
    expect(data).toBe(true);
}, 10000); // Jest will wait 10000 ms

In order to increase the timeout globally, you can read this

configure-jest-timeout-once-for-all-tests

Svetoslav Petkov
  • 1,117
  • 5
  • 13
  • Increasing timeout IMHO is not a good idea. When a test or tests timeouts it means in most cases that you didn't mock some API call or maybe missed some await somewhere. Unit tests should not call external APIs or make network requests. In the tests you have you want to test the `createUser` method and not the `UserModel.create`. My advice is that you should mock the `UserModel.create` method and return the values you want. Then write tests for all `if` and `else` conditions from your catch. – Marek Rozmus Oct 04 '22 at 17:51
0

Thanks to Marek Rozmus.

The solution was that I needed to use mocks to return dummy data instead of using a call to mongoose.

After mocking the calls, the tests worked as expected. Also learned about formulating better tests - we're not testing mongoose, only whether our code can handle what mongoose might return (success, error, timeout etc.)

bobe
  • 11
  • 2