Files
talk/test/server/services/users.js
T
2017-10-29 18:48:15 -07:00

349 lines
11 KiB
JavaScript

const UsersService = require('../../../services/users');
const SettingsService = require('../../../services/settings');
const MailerService = require('../../../services/mailer');
const chai = require('chai');
chai.use(require('chai-as-promised'));
const sinon = require('sinon');
chai.use(require('sinon-chai'));
const expect = chai.expect;
describe('services.UsersService', () => {
let mockUsers;
beforeEach(async () => {
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
await SettingsService.init(settings);
mockUsers = await UsersService.createLocalUsers([{
email: 'stampi@gmail.com',
username: 'Stampi',
password: '1Coral!-',
}, {
email: 'sockmonster@gmail.com',
username: 'Sockmonster',
password: '2Coral!2'
}, {
email: 'marvel@gmail.com',
username: 'Marvel',
password: '3Coral!3'
}]);
sinon.spy(MailerService, 'sendSimple');
});
afterEach(() => {
MailerService.sendSimple.restore();
});
describe('#findById()', () => {
it('should find a user by id', async () => {
const user = await UsersService.findById(mockUsers[0].id);
expect(user).to.have.property('username', 'Stampi');
});
});
describe('#findByIdArray()', () => {
it('should find an array of users from an array of ids', async () => {
const ids = mockUsers.map((user) => user.id);
const users = await UsersService.findByIdArray(ids);
expect(users).to.have.length(3);
});
});
describe('#findPublicByIdArray()', () => {
it('should find an array of users from an array of ids', async () => {
const ids = mockUsers.map((user) => user.id);
const users = await UsersService.findPublicByIdArray(ids);
expect(users).to.have.length(3);
const sorted = users.sort((a, b) => {
if(a.username < b.username) {return -1;}
if(a.username > b.username) {return 1;}
return 0;
});
expect(sorted[0]).to.have.property('username', 'Marvel');
});
});
describe('#findLocalUser', () => {
it('should find a user', () => {
return UsersService
.findLocalUser(mockUsers[0].profiles[0].id)
.then((user) => {
expect(user).to.have.property('username', mockUsers[0].username);
});
});
});
describe('#createLocalUser', () => {
it('should not create a user with duplicate username', () => {
return UsersService.createLocalUsers([{
email: 'otrostampi@gmail.com',
username: 'StampiTheSecond',
password: '1Coralito!'
}])
.then((user) => {
expect(user).to.be.null;
})
.catch((error) => {
expect(error).to.not.be.null;
});
});
});
describe('#createEmailConfirmToken', () => {
it('should create a token for a valid user', async () => {
const token = await UsersService.createEmailConfirmToken(mockUsers[0], mockUsers[0].profiles[0].id);
expect(token).to.not.be.null;
});
it('should not create a token for a user already verified', async () => {
const token = await UsersService.createEmailConfirmToken(mockUsers[0], mockUsers[0].profiles[0].id);
expect(token).to.not.be.null;
await UsersService.verifyEmailConfirmation(token);
const user = await UsersService.findById(mockUsers[0].id);
return expect(UsersService.createEmailConfirmToken(user, mockUsers[0].profiles[0].id)).to.eventually.be.rejected;
});
});
describe('#verifyEmailConfirmation', () => {
it('should correctly validate a valid token', async () => {
const token = await UsersService.createEmailConfirmToken(mockUsers[0], mockUsers[0].profiles[0].id);
expect(token).to.not.be.null;
return expect(UsersService.verifyEmailConfirmation(token)).to.eventually.not.be.rejected;
});
it('should correctly reject an invalid token', async () => {
return UsersService
.verifyEmailConfirmation('cats')
.catch((err) => {
expect(err).to.not.be.null;
});
});
it('should update the user model when verification is complete', () => {
return UsersService
.createEmailConfirmToken(mockUsers[0], mockUsers[0].profiles[0].id)
.then((token) => {
expect(token).to.not.be.null;
return UsersService.verifyEmailConfirmation(token);
})
.then(() => {
return UsersService.findById(mockUsers[0].id);
})
.then((user) => {
expect(user.profiles[0]).to.have.property('metadata');
expect(user.profiles[0].metadata).to.have.property('confirmed_at');
expect(user.profiles[0].metadata.confirmed_at).to.not.be.null;
});
});
});
describe('#setStatus', () => {
it('should set the status to active', () => {
return UsersService
.setStatus(mockUsers[0].id, 'ACTIVE')
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('status', 'ACTIVE');
})
.then(() => {
expect(MailerService.sendSimple).to.not.have.been.called;
});
});
});
describe('#ignoreUser', () => {
it('should add user id to ignoredUsers set', async () => {
const user = mockUsers[0];
const usersToIgnore = [mockUsers[1], mockUsers[2]];
await UsersService.ignoreUsers(user.id, usersToIgnore.map((u) => u.id));
const userAfterIgnoring = await UsersService.findById(user.id);
expect(userAfterIgnoring.ignoresUsers.length).to.equal(2);
// ignore same user another time, make sure it's not added to the list.
await UsersService.ignoreUsers(user.id, usersToIgnore.slice(0, 1).map((u) => u.id));
const userAfterIgnoring2 = await UsersService.findById(user.id);
expect(userAfterIgnoring2.ignoresUsers.length).to.equal(2);
});
it('should not ignore a staff member', async () => {
const user = mockUsers[0];
const usersToIgnore = [mockUsers[1]];
await UsersService.addRoleToUser(usersToIgnore[0].id, 'STAFF');
try {
await UsersService.ignoreUsers(user.id, usersToIgnore.map((u) => u.id));
} catch (err) {
expect(err.status).to.equal(400);
expect(err.translation_key).to.equal('CANNOT_IGNORE_STAFF');
}
});
});
describe('#ban', () => {
it('should set the status to banned', () => {
return UsersService
.setStatus(mockUsers[0].id, 'BANNED')
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('status', 'BANNED');
})
.then(() => {
expect(MailerService.sendSimple).to.have.been.calledWithMatch({
template: 'banned',
to: mockUsers[0].profiles[0].id
});
});
});
it('should still disable and ban the user if there is no comment', () => {
return UsersService
.setStatus(mockUsers[0].id, 'BANNED')
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('status', 'BANNED');
});
});
});
describe('#unban', () => {
it('should set the status to active', () => {
return UsersService
.setStatus(mockUsers[0].id, 'ACTIVE')
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('status', 'ACTIVE');
});
});
});
describe('#toggleNameEdit', () => {
it('should toggle the canEditName field', () => {
return UsersService
.toggleNameEdit(mockUsers[0].id, true)
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('canEditName', true);
});
});
});
describe('#search', () => {
it('should return all the results without a value', async () => {
expect(await UsersService.search()).to.have.length(3);
});
it('should match the search terms', async () => {
const tests = [
{
search: 'monster',
results: 1,
id: mockUsers[1].id,
},
{
search: 'Stamp',
results: 1,
id: mockUsers[0].id,
},
{
search: 'sockmonster@gmail.com',
results: 1,
id: mockUsers[1].id,
},
{
search: 'marvel',
results: 1,
id: mockUsers[2].id,
},
{
search: 'gmail.com',
results: 3
}
];
for (const test of tests) {
const users = await UsersService.search(test.search);
expect(users).to.have.length(test.results);
if (test.results === 1) {
expect(users[0]).to.have.property('id', test.id);
}
}
});
});
describe('#editName', () => {
it('should let the user edit their username if the proper toggle is set', () => {
return UsersService
.toggleNameEdit(mockUsers[0].id, true)
.then(() => UsersService.editName(mockUsers[0].id, 'Jojo'))
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('username', 'Jojo');
expect(user).to.have.property('canEditName', false);
});
});
it('should let the user submit the same username if user is not banned (create username)', () => {
return UsersService
.toggleNameEdit(mockUsers[0].id, true)
.then(() => UsersService.editName(mockUsers[0].id, mockUsers[0].username))
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('username', mockUsers[0].username);
expect(user).to.have.property('canEditName', false);
});
});
it('should return error when a banned user submits the same username (rejected username)', () => {
return UsersService
.toggleNameEdit(mockUsers[0].id, true)
.then(() => UsersService.setStatus(mockUsers[0].id, 'BANNED'))
.then(() => UsersService.editName(mockUsers[0].id, mockUsers[0].username))
.then(() => UsersService.findById(mockUsers[0].id))
.then(() => {
throw new Error('Error expected');
})
.catch((err) => {
expect(err.status).to.equal(400);
expect(err.translation_key).to.equal('SAME_USERNAME_PROVIDED');
});
});
it('should return an error if canEditName is false', async () => {
return expect(UsersService.editName(mockUsers[0].id, 'Jojo')).to.eventually.be.rejected;
});
it('should return an error if the username is already taken', async () => {
await UsersService.toggleNameEdit(mockUsers[0].id, true);
return expect(UsersService.editName(mockUsers[0].id, 'Marvel')).to.eventually.be.rejected;
});
it('should not allow non-alphanumeric characters in usernames', () => {
return UsersService
.isValidUsername('hi🖕')
.then(() => {
expect(false).to.be.true;
})
.catch((err) => {
expect(err).to.be.ok;
});
});
});
});