Added success indicator for members magic links

- Add a query param that indicates whether signin/up succeeded or failed
- Add unit tests for all 3 possible cases for the createSessionFromMagicLink middleware
- Added an acceptance test to show the behaviour works in principle
This commit is contained in:
Hannah Wolfe 2020-05-08 13:03:44 +01:00
parent 11f7834800
commit 998eb62e22
3 changed files with 109 additions and 4 deletions

View File

@ -108,16 +108,18 @@ const createSessionFromMagicLink = async function (req, res, next) {
// We need to include the subdirectory,
// members is already removed from the path by express because it's a mount path
const redirectPath = `${urlUtils.getSubdir()}${req.path}?${searchParams.toString()}`;
let redirectPath = `${urlUtils.getSubdir()}${req.path}`;
try {
await membersService.ssr.exchangeTokenForSession(req, res);
// Do a standard 302 redirect
return res.redirect(redirectPath);
// Do a standard 302 redirect, with success=true
searchParams.set('success', true);
} catch (err) {
logging.warn(err.message);
return res.redirect(redirectPath);
searchParams.set('success', false);
} finally {
res.redirect(`${redirectPath}?${searchParams.toString()}`);
}
};

View File

@ -89,6 +89,18 @@ describe('Basic Members Routes', function () {
return request.put('/members/api/subscriptions/123')
.expect(400);
});
it('should serve theme 404 on members endpoint', function () {
return request.get('/members/')
.expect(404)
.expect('Content-Type', 'text/html; charset=utf-8');
});
it('should redirect invalid token on members endpoint', function () {
return request.get('/members/?token=abc&action=signup')
.expect(302)
.expect('Location', '/?action=signup&success=false');
});
});
});
@ -161,6 +173,16 @@ describe('Basic Members Routes', function () {
return request.put('/members/api/subscriptions/123')
.expect(404);
});
it('should serve 404 on members endpoint', function () {
return request.get('/members/')
.expect(404);
});
it('should not redirect members endpoint with token', function () {
return request.get('/members/?token=abc&action=signup')
.expect(404);
});
});
});
});

View File

@ -0,0 +1,81 @@
const should = require('should');
const sinon = require('sinon');
const urlUtils = require('../../../../core/server/lib/url-utils');
const membersService = require('../../../../core/server/services/members');
const membersMiddleware = require('../../../../core/server/services/members/middleware');
describe('Members Service Middleware', function () {
describe('createSessionFromMagicLink', function () {
let req;
let res;
let next;
beforeEach(function () {
req = {};
res = {};
next = sinon.stub();
res.redirect = sinon.stub().returns('');
// Stub the members Service, handle this in separate tests
membersService.ssr.exchangeTokenForSession = sinon.stub();
sinon.stub(urlUtils, 'getSubdir').returns('/blah');
});
afterEach(function () {
sinon.restore();
});
it('calls next if url does not include a token', async function () {
// This recreates what express does, note: members is mounted so path will be /
req.url = '/members';
req.path = '/';
req.query = {};
// Call the middleware
await membersMiddleware.createSessionFromMagicLink(req, res, next);
// Check behaviour
next.calledOnce.should.be.true();
next.firstCall.args.should.be.an.Array().with.lengthOf(0);
});
it('redirects correctly on success', async function () {
// This recreates what express does, note: members is mounted so path will be /
req.url = '/members?token=test&action=signup';
req.path = '/';
req.query = {token: 'test', action: 'signup'};
// Fake token handling success
membersService.ssr.exchangeTokenForSession.resolves();
// Call the middleware
await membersMiddleware.createSessionFromMagicLink(req, res, next);
// Check behaviour
next.calledOnce.should.be.false();
res.redirect.calledOnce.should.be.true();
res.redirect.firstCall.args[0].should.eql('/blah/?action=signup&success=true');
});
it('redirects correctly on failure', async function () {
// This recreates what express does, note: members is mounted so path will be /
req.url = '/members?token=test&action=signup';
req.path = '/';
req.query = {token: 'test', action: 'signup'};
// Fake token handling failure
membersService.ssr.exchangeTokenForSession.rejects();
// Call the middleware
await membersMiddleware.createSessionFromMagicLink(req, res, next);
// Check behaviour
next.calledOnce.should.be.false();
res.redirect.calledOnce.should.be.true();
res.redirect.firstCall.args[0].should.eql('/blah/?action=signup&success=false');
});
});
});