0

I'm am trying to get an integration test using jest (test environment : node) to pass, for a login form which uses csurf for csrf protection (using the cookie option).

I've extracted the csrfToken from the login form and the set-cookie headers yet the test still fails with a 403 - invalid csrf token.

I can't see what the issue is and would appreciate a steer in the right direction.

test file :

const request   = require('supertest');
const {User}    = require('../../server/models/user');
const cheerio   = require('cheerio');
const app       = require('../../app');

let user, csrfToken, password, cookies;

beforeEach( async () => {
  user = await new User({
    firstName: "Name",
    lastName: "Surname",
    email: "email@example.com",
    password: "password",
    isAdmin : true
  }).save();
});

afterEach( async () => {
  await User.deleteMany();
});

describe('/login', () => {

  describe('GET /', () => {

    const exec = async () => {
      const res = await request(app).get(`/login`);
      let $ = cheerio.load(res.text);
      csrfToken = $('[name=_csrf]').val();
      return res;
    };

    it('should return the login form', async () => {
      const res = await exec();
      expect(res.status).toBe(200);
      expect(res.text).toMatch(/Sign In/);
    });
  });

  describe('POST /', () => {

    const getLoginCsrfs = async () => {
      const res = await request(app).get(`/login`);
      let $ = cheerio.load(res.text);
      csrfToken = $('[name=_csrf]').val();
      cookies = res.headers['set-cookie'];
      return res;
    };

    const postLogin = async () => {
      return request(app).post(`/login`)
        .set('Cookie', cookies)
        .send({ email: user.email,
                password: password,
                _csrf: csrfToken
        });
    };

    it('should return 401 without incorrect user info', async () => {
      await getLoginCsrfs();
      password = 'wrongpassword';
      const res = await postLogin();
      expect(res.status).toBe(401)
    });

    it('should return 403 without csrf token/header credentials', async () => {
      await getLoginCsrfs();
      csrfToken = '';
      cookies = '';
      password = 'password';
      const res = await postLogin();
      expect(res.status).toBe(403)
    });

    it('should return 200 with correct credentials', async () => {
      await getLoginCsrfs();
      password = 'password';
      const res = await postLogin();
      expect(res.status).toBe(200)
    });
  });
});
 FAIL  tests/integration/login.test.js
  /login
    GET /
      ✓ should return the login form (300ms)
    POST /
      ✕ should return 401 without incorrect user info (150ms)
      ✓ should return 403 without csrf token/header credentials (130ms)
      ✕ should return 200 with correct credentials (131ms)

  ● /login › POST / › should return 401 without incorrect user info

    expect(received).toBe(expected) // Object.is equality

    Expected: 401
    Received: 403

      61 |       password = 'wrongpassword';
      62 |       const res = await postLogin();
    > 63 |       expect(res.status).toBe(401)
         |                          ^
      64 |     });
      65 |
      66 |     it('should return 403 without csrf token/header credentials', async () => {

      at Object.toBe (tests/integration/login.test.js:63:26)

  ● /login › POST / › should return 200 with correct credentials

    expect(received).toBe(expected) // Object.is equality

    Expected: 200
    Received: 403

      77 |       password = 'password';
      78 |       const res = await postLogin();
    > 79 |       expect(res.status).toBe(200)
         |                          ^
      80 |     });
      81 |   });
      82 | });

      at Object.toBe (tests/integration/login.test.js:79:26)

s33dco
  • 1
  • 2

1 Answers1

0

initially I thought the problem related to _csrf in set-cookie but after rechecking through the solution was straightforward,

    const postLogin = async () => {
      return request(app).post(`/login`)
        .type('form')
        .set('Cookie', cookies)
        .send({ email: user.email,
                password: password,
                _csrf: csrfToken
        });
    };

i had omitted the .type('form'), the 403 related to the csrfToken from the form, (all form data), not being seen.

 PASS  tests/integration/login.test.js (5.661s)
  /login
    GET /
      ✓ should return the login form (489ms)
    POST /
      ✓ should return 401 without incorrect user info (443ms)
      ✓ should return 403 without csrf token/header credentials (131ms)
      ✓ should return 200 with correct credentials (255ms)

I had been googling around and considered the issues to relate to jest / supertest and multiple cookies but as ever the solution was much more straightforward and closer to home.

s33dco
  • 1
  • 2