Search code examples
mocha.jscsrfbddsupertest

Mocha test error CSRF token mismatch


I recently learning how to write tests with mocha and supertest. When I try to testing a post url, it require _csrf property, so I check this [How to test express form post with CSRF?

]1

and put the following code

var request = require('supertest');
var should = require('should');
var app = require('../app');
var $ = require('jquery')(require("jsdom").jsdom().parentWindow);


describe('User', function () {

    it('should create a admin', function (done) {
        request(app)
            .get('/rear')
            .expect(200)
            .end(function (err, res) {
                if (err) return done(err);
                should.not.exist(err);
                var $html = $(res.text);
                var csrf = $html.find('input[name=_csrf]').val();
                console.log(csrf);
                should.exist(csrf);
                request(app)
                    .post('/user/signup')
                    .send({
                        _csrf: csrf,
                        name: 'admin',
                        mobile: '12345678901',
                        password: '123456',
                        repassword: '123456',
                        gender: '0'
                    })
                    .expect(302)
                    .end(function (err, res) {
                        if (err) return done(err);
                        should.not.exist(err);
                        res.header.location.should.include('/rear');
                        done();
                    });
            });
    });
});

The terminal notice that Error: CSRF token mismatch Error: expected 302 "Found", got 403 "Forbidden"

My code imitate user behavior, on the page which /rear router render to get csrf then post it and other info to /user/signup, I don`t know where something wrong and how to fix it. If you found out the reason,please remind me, thanks a lot.


Solution

  • I find out where the trouble. I get csrf which middleware lusca expose form server to front page in the input(name='_csrf') but I ignore that in test env it also should persist a request and its cookies, I check supertest doc again finding that it could call .agent method to implement it.

    var agent = request.agent(app);
    
    describe('User', function () {
    
        it('should create a admin', function (done) {
            agent
                .get('/rear')
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    should.not.exist(err);
                    var $html = $(res.text);
                    var csrf = $html.find('input[name=_csrf]').val();
                    console.log(csrf);
                    should.exist(csrf);
                    request(app)
                        .post('/user/signup')
                        .send({
                            _csrf: csrf,
                            name: 'admin',
                            mobile: '12345678901',
                            password: '123456',
                            repassword: '123456',
                            gender: '0'
                        })
                        .expect(302)
                        .end(function (err, res) {
                            if (err) return done(err);
                            should.not.exist(err);
                            res.header.location.should.include('/rear');
                            done();
                        });
                });
        });
    });