feathers-service-verify-reset
Version:
Adds user email verification and password reset capabilities to local feathers-authentication
194 lines (153 loc) • 6.75 kB
JavaScript
/* global assert, describe, it */
/* eslint no-shadow: 0, no-var: 0, one-var: 0, one-var-declaration-per-line: 0,
no-unused-vars: 0 */
const assert = require('chai').assert;
const feathersStubs = require('./../test/helpers/feathersStubs');
const verifyResetService = require('../lib/index').service;
const SpyOn = require('./helpers/basicSpy');
// user DB
const now = Date.now();
const usersDb = [
// The added time interval must be longer than it takes to run ALL the tests
{ _id: 'a', email: 'a', isVerified: true, resetToken: '000', resetExpires: now + 200000 },
{ _id: 'b', email: 'b', isVerified: true, resetToken: null, resetExpires: null },
{ _id: 'c', email: 'c', isVerified: true, resetToken: '111', resetExpires: now - 200000 },
{ _id: 'd', email: 'd', isVerified: false, resetToken: '222', resetExpires: now - 200000 },
];
// Tests
['_id', 'id'].forEach(idType => {
['paginated', 'non-paginated'].forEach(pagination => {
describe(`resetPwdWithLongToken ${pagination} ${idType}`, function () {
this.timeout(5000);
const ifNonPaginated = pagination === 'non-paginated';
describe('basic', () => {
var db;
var app;
var users;
var verifyReset;
const password = '123456';
beforeEach(() => {
db = clone(usersDb);
app = feathersStubs.app();
users = feathersStubs.users(app, db, ifNonPaginated, idType);
verifyResetService().call(app); // define and attach verifyReset service
verifyReset = app.service('verifyReset'); // get handle to verifyReset
});
it('verifies valid token', (done) => {
const resetToken = '000';
const i = 0;
verifyReset.create({ action: 'reset', value: { token: resetToken, password } }, {},
(err, user) => {
assert.strictEqual(err, null, 'err code set');
assert.strictEqual(user.isVerified, true, 'user.isVerified not true');
assert.strictEqual(db[i].isVerified, true, 'isVerified not true');
assert.strictEqual(db[i].resetToken, null, 'resetToken not null');
assert.strictEqual(db[i].resetShortToken, null, 'resetShortToken not null');
assert.strictEqual(db[i].resetExpires, null, 'resetExpires not null');
assert.isString(db[i].password, 'password not a string');
assert.equal(db[i].password.length, 60, 'password wrong length');
done();
});
});
it('user is sanitized', (done) => {
const resetToken = '000';
const i = 0;
verifyReset.create({ action: 'reset', value: { token: resetToken, password } }, {},
(err, user) => {
assert.strictEqual(err, null, 'err code set');
assert.strictEqual(user.isVerified, true, 'isVerified not true');
assert.strictEqual(user.resetToken, undefined, 'resetToken not undefined');
assert.strictEqual(user.resetShortToken, undefined, 'resetShortToken not undefined');
assert.strictEqual(user.resetExpires, undefined, 'resetExpires not undefined');
assert.isString(db[i].password, 'password not a string');
assert.equal(db[i].password.length, 60, 'password wrong length');
done();
});
});
it('error on unverified user', (done) => {
const resetToken = '222';
verifyReset.create({ action: 'reset', value: { token: resetToken, password } }, {},
(err, user) => {
assert.isString(err.message);
assert.isNotFalse(err.message);
done();
});
});
it('error on expired token', (done) => {
const resetToken = '111';
verifyReset.create({ action: 'reset', value: { token: resetToken, password } }, {},
(err, user) => {
assert.isString(err.message);
assert.isNotFalse(err.message);
done();
});
});
it('error on token not found', (done) => {
const resetToken = '999';
verifyReset.create({ action: 'reset', value: { token: resetToken, password } }, {},
(err, user) => {
assert.isString(err.message);
assert.isNotFalse(err.message);
done();
});
});
});
describe('with email', () => {
var db;
var app;
var users;
var spyEmailer;
var verifyReset;
const password = '123456';
beforeEach(() => {
db = clone(usersDb);
app = feathersStubs.app();
users = feathersStubs.users(app, db, ifNonPaginated, idType);
spyEmailer = new SpyOn(emailer);
verifyResetService({ emailer: spyEmailer.callWithCb, testMode: true }).call(app);
verifyReset = app.service('verifyReset'); // get handle to verifyReset
});
it('verifies valid token', (done) => {
const resetToken = '000';
const i = 0;
verifyReset.create({
action: 'reset',
value: { token: resetToken, password } },
{},
(err, user) => {
assert.strictEqual(err, null, 'err code set');
assert.strictEqual(user.isVerified, true, 'user.isVerified not true');
assert.strictEqual(db[i].isVerified, true, 'isVerified not true');
assert.strictEqual(db[i].resetToken, null, 'resetToken not null');
assert.strictEqual(db[i].resetExpires, null, 'resetExpires not null');
const hash = db[i].password;
assert.isString(hash, 'password not a string');
assert.equal(hash.length, 60, 'password wrong length');
assert.deepEqual(spyEmailer.result(), [{
args: [
'resetPwd',
Object.assign({}, sanitizeUserForEmail(db[i])),
{},
''
],
result: [null],
}]);
done();
});
});
});
});
});
});
// Helpers
function emailer(action, user, notifierOptions, newEmail, cb) {
cb(null);
}
function sanitizeUserForEmail(user) {
const user1 = Object.assign({}, user);
delete user1.password;
return user1;
}
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}