Jest + supertest in NodeJS, async/await

13,852

Solution 1

As a result, i had to move the test to test.js:

// test.js

it('delete user', async () => {
    const userByEmail = await request(app)
      .get('/users/get-by-email/user@test')
      .set('Accept', 'application/json')
      .set('Authorization', config.get('test.tokens.admin'));

    const result = await testIt('delete', `/users/${userByEmail.body._id}`);
    expect(result).toEqual([401, 403, 401, 200]);
  });

// testIt.js

const config  = require('config');
const request = require('supertest');
const app     = require('../app');

const tokensConfig = config.get('test.tokens');

async function testIt(method = 'get', url = '/', body = {}) {
  const testNames = ['unauthorized', 'user', 'adminTokenExpired', 'admin'];
  const tokens = [null, tokensConfig.userTokenInfinity, tokensConfig.adminTokenExpired, tokensConfig.adminTokenInfinity];
  let result = [];

  for (let i = 0; i < testNames.length; i++) {
    const response = await request(app)
      [method](url)
      .set('Accept', 'application/json')
      .set('Authorization', tokens[i])
      .send(body);

    result.push(response.statusCode);
  }

  return result;
}

module.exports = testIt;

But i had to confine myself to one answer to all roles instead individual answer to every role, because i want less code.

Solution 2

Looks like you need to let jest know that the expect is an async method, with resolves.

Here is the sample code from Jest's documentation:

// async/await can be used.
it('works with async/await', async () => {
  expect.assertions(1);
  const data = await user.getUserName(4);
  expect(data).toEqual('Mark');
});

// async/await can also be used with `.resolves`.
it('works with async/await and resolves', async () => {
  expect.assertions(1);
  await expect(user.getUserName(5)).resolves.toEqual('Paul');
});

https://facebook.github.io/jest/docs/en/tutorial-async.html#async-await

Share:
13,852
Alexander Dozmorov
Author by

Alexander Dozmorov

Js, Frontend developer

Updated on June 25, 2022

Comments

  • Alexander Dozmorov
    Alexander Dozmorov almost 2 years

    I try to test my api with Jest. I want more abstraction, so i created this function:

    const tokensConfig = config.get('test.tokens');
    
    function testIt(method = 'get', url = '/', statuses = [], body = {}) {
          const testNames = ['unauthorized', 'user', 'admin'];
          const tokens = [null, tokensConfig.user, tokensConfig.admin];
        
          for (let i = 0; i < testNames.length; i++) {
            test(testNames[i], async () => {
              const response = await request(app)
                [method](url)
                .set('Accept', 'application/json')
                .set('Authorization', tokens[i])
                .send(body);
              expect(response.statusCode).toBe(statuses[i]);
            });
          }
        }

    In test.js file i run:

    const config  = require('config');
    const request = require('supertest');
    const testIt  = require('./testIt');
    const app     = require('../app');
    
    // It's work
    describe('get user by email', () => {
        testIt('get', '/users/get-by-email/user@test', [401, 403, 200]);
      });
      
    // It's not work  
    describe('delete user', async () => {
        const userByEmail = await request(app)
          .get('/users/get-by-email/user@test')
          .set('Accept', 'application/json')
          .set('Authorization', config.get('test.tokens.admin'));
    
        testIt('delete', `/users/${userByEmail._id}`, [401, 403, 200]);
      });

    Trouble in async/await - testIt running before request user.

    If i move test (or it) to describe block from function testIt and create request user inside test, it will work. But i want more abstraction (test block very big for many tests)

    How fix it?