sinon
is being used to mock methods in tests. It is one of the most used package for testing. But Is there a way to mock session objects in tests for express?
I'm working on a project where I upload images to s3 in bulk (albums) and than further apply some processing like resizing/compression/editing on them.
It's a express app with middlewares for authorization, authentication, setting context and is working fine.
Recently I started adding testcases for different routes using mocha
. I'm using cookie-session
for session handling in app.
For one route, I needed to mock req.session
object. (Need to set it's value before calling the other route.)
I have two routes, one is to upload photo to s3 (create) and second one (submit) to apply further processing on uploaded images.
First route (create) set req.session
value and redirect to second one (submit).
exports.create = function(req, res) {
// upload image to s3
var photos = PhotosTable.create(req.files.names); // add entries in database
req.session.count = photos.length; // set count in req.session
res.redirect(`api/image/submit`);
}
exports.submit = function(req, res) {
if (req.session.count && req.session.count > 0) { // get count from req.session
// perform further tasks
res.sendStatus(200);
} else {
res.sendStatus(400);
}
}
Issue is that api/image/submit
route checks for req.session.count
and than perform further tasks, if count
is not set, it sends 400 in reponse.
With mocha
you can only check response from one route, can't wait for result from redirect call.
One easy solution is that I send a req param from testcase, and check it in method if that param is present, than skip checking for req.session.count
. Duh! This seems dumbest solution.
I could also easily get rid of second route and add all logic in one. But should I ? As far as I know, one should never change implementation for sake of testcases. As this problem seemes so common but I couldn't find any solution on internet (I mnea stackoverflow :D). My first guess was that there would be some npm-package to handle this kind of situation. As mocha
, cookie-session
are one the most modules modules with express.
Alas! There isn't any.
cookie-session
maintains the session by keeping signed cookies. It uses cookies
with Keygrip
and Crypto
to set and validate session keys.
It requires a name and a key for setting session cookies.
name is used as cookie name.
key is used to sign cookie value using Keygrip
So, somehow I should set req.session.count
value in testcase, before calling the route.
// name = "my-session" -> base64 value of required object (cookie)
// name.sig = "my-session.sig" -> signed value of cookie using Keygrip
let cookie = Buffer.from(JSON.stringify({"count":2})).toString('base64'); // base64 converted value of cookie
let kg = Keygrip(['testKey']) // same key as I'm using in my app
let hash = kg.sign('my-sessssion=' + cookie);
await request(app).get('api/image/submit').set("Accept", "text/html")
.set('cookie', ['my-session=' + cookie + '; ' + 'my-session.sig=' + hash + ';'])
.expect(200);
That's it. By setting this cookie in request, I was able to set req.session.count
to my desired value. Hah!! xD
exports.submit = function(req, res) {
if(req.session.count && req.session.count > 0) { // true
//do something
res.sendStatus(200);
}
}
This is just one use-case for mocking session in express, but it can be used wherever you need to set req.session
with any value.
I have also created package at npm: mock-session https://www.npmjs.com/package/mock-session
It doesn't work. How can I do it?