fixing and separating broken tests /client /server

This commit is contained in:
Belen Curcio
2017-03-23 12:27:30 -03:00
parent 341a7320f9
commit 2e80d2a36e
24 changed files with 104 additions and 196 deletions
+64
View File
@@ -0,0 +1,64 @@
const expect = require('chai').expect;
const User = require('../../../models/user');
const Context = require('../../../graph/context');
const errors = require('../../../errors');
describe('graph.Context', () => {
describe('#constructor: with a user', () => {
let c;
beforeEach(() => {
c = new Context({user: new User({id: '1'})});
});
it('creates a context with a user', (done) => {
expect(c).to.have.property('user');
expect(c.user).to.have.property('id', '1');
done();
});
it('does have access to mutators', () => {
return c.mutators.Action.create({
item_id: '1',
item_type: 'COMMENTS',
action_type: 'LIKE'
})
.then((action) => {
expect(action).to.have.property('item_id', '1');
expect(action).to.have.property('item_type', 'COMMENTS');
expect(action).to.have.property('action_type', 'LIKE');
});
});
});
describe('#constructor: without a user', () => {
let c;
beforeEach(() => {
c = new Context({user: undefined});
});
it('creates a context without a user', (done) => {
expect(c).to.not.have.property('user');
done();
});
it('does not have access to mutators', () => {
return c.mutators.Action.create({
item_id: '1',
item_type: 'COMMENTS',
action_type: 'LIKE'
})
.then((action) => {
expect(action).to.be.null;
})
.catch((err) => {
expect(err).to.be.equal(errors.ErrNotAuthorized);
});
});
});
});
+151
View File
@@ -0,0 +1,151 @@
const {expect} = require('chai');
const {graphql} = require('graphql');
const schema = require('../../../../graph/schema');
const Context = require('../../../../graph/context');
const UserModel = require('../../../../models/user');
const AssetModel = require('../../../../models/asset');
const SettingsService = require('../../../../services/settings');
const ActionModel = require('../../../../models/action');
const CommentModel = require('../../../../models/comment');
describe('graph.loaders.Metrics', () => {
beforeEach(() => SettingsService.init());
describe('#Comments', () => {
const query = `
query CommentMetrics($from: Date!, $to: Date!) {
liked: commentMetrics(from: $from, to: $to, sort: LIKE) {
id
}
flagged: commentMetrics(from: $from, to: $to, sort: FLAG) {
id
}
}
`;
describe('different comment states', () => {
beforeEach(() => CommentModel.create([
{id: '1', body: 'a new comment!'},
{id: '2', body: 'a new comment!'},
{id: '3', body: 'a new comment!'}
]));
[
{liked: 0, flagged: 0, actions: []},
{liked: 1, flagged: 0, actions: [{action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'}]},
{liked: 0, flagged: 1, actions: [{action_type: 'FLAG', item_id: '1', item_type: 'COMMENTS'}]},
{liked: 1, flagged: 1, actions: [
{action_type: 'FLAG', item_id: '1', item_type: 'COMMENTS'},
{action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'}
]},
{liked: 3, flagged: 1, actions: [
{action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'},
{action_type: 'LIKE', item_id: '2', item_type: 'COMMENTS'},
{action_type: 'LIKE', item_id: '3', item_type: 'COMMENTS'},
{action_type: 'FLAG', item_id: '3', item_type: 'COMMENTS'}
]}
].forEach(({liked, flagged, actions}) => {
describe(`with actions=${actions.length}`, () => {
beforeEach(() => ActionModel.create(actions));
it(`returns the correct amount of metrics liked=${liked} flagged=${flagged}`, () => {
const context = new Context({user: new UserModel({roles: ['ADMIN']})});
return graphql(schema, query, {}, context, {
from: (new Date()).setMinutes((new Date()).getMinutes() - 5),
to: (new Date()).setMinutes((new Date()).getMinutes() + 5)
})
.then(({data, errors}) => {
expect(errors).to.be.undefined;
expect(data.liked).to.have.length(liked);
expect(data.flagged).to.have.length(flagged);
});
});
});
});
});
});
describe('#Assets', () => {
const query = `
fragment metrics on Asset {
id
action_summaries {
type: __typename
actionCount
actionableItemCount
}
}
query Metrics($from: Date!, $to: Date!) {
assetsByFlag: assetMetrics(from: $from, to: $to, sort: FLAG) {
...metrics
}
assetsByLike: assetMetrics(from: $from, to: $to, sort: LIKE) {
...metrics
}
}
`;
describe('different comment states', () => {
beforeEach(() => Promise.all([
AssetModel.create([
{id: 'a1', url: 'http://localhost:3030/article/1'},
{id: 'a2', url: 'http://localhost:3030/article/2'}
]),
CommentModel.create([
{id: 'c1', asset_id: 'a1', body: 'a new comment!'},
{id: 'c2', asset_id: 'a1', body: 'a new comment!'},
{id: 'c3', asset_id: 'a1', body: 'a new comment!'}
])
]));
[
{liked: 0, flagged: 0, actions: []},
{liked: 1, flagged: 0, actions: [{action_type: 'LIKE', item_id: 'c1', item_type: 'COMMENTS'}]},
{liked: 0, flagged: 1, actions: [{action_type: 'FLAG', item_id: 'c1', item_type: 'COMMENTS'}]},
{liked: 1, flagged: 1, actions: [
{action_type: 'FLAG', item_id: 'c1', item_type: 'COMMENTS'},
{action_type: 'LIKE', item_id: 'c1', item_type: 'COMMENTS'}
]},
{liked: 1, flagged: 1, actions: [
{action_type: 'LIKE', item_id: 'c1', item_type: 'COMMENTS'},
{action_type: 'LIKE', item_id: 'c2', item_type: 'COMMENTS'},
{action_type: 'LIKE', item_id: 'c3', item_type: 'COMMENTS'},
{action_type: 'FLAG', item_id: 'c3', item_type: 'COMMENTS'}
]}
].forEach(({liked, flagged, actions}) => {
describe(`with actions=${actions.length}`, () => {
beforeEach(() => ActionModel.create(actions));
it(`returns the correct amount of metrics liked=${liked} flagged=${flagged}`, () => {
const context = new Context({user: new UserModel({roles: ['ADMIN']})});
return graphql(schema, query, {}, context, {
from: (new Date()).setMinutes((new Date()).getMinutes() - 5),
to: (new Date()).setMinutes((new Date()).getMinutes() + 5)
})
.then(({data, errors}) => {
expect(errors).to.be.undefined;
expect(data.assetsByLike).to.have.length(liked);
expect(data.assetsByFlag).to.have.length(flagged);
});
});
});
});
});
});
});
@@ -0,0 +1,62 @@
const expect = require('chai').expect;
const {graphql} = require('graphql');
const schema = require('../../../../graph/schema');
const Context = require('../../../../graph/context');
const UserModel = require('../../../../models/user');
const SettingsService = require('../../../../services/settings');
const CommentsService = require('../../../../services/comments');
describe('graph.mutations.addCommentTag', () => {
let comment;
beforeEach(async () => {
await SettingsService.init();
comment = await CommentsService.publicCreate({body: `hello there! ${ String(Math.random()).slice(2)}`});
});
const query = `
mutation AddCommentTag ($id: ID!, $tag: String!) {
addCommentTag(id:$id, tag:$tag) {
comment {
tags {
name
}
}
errors {
translation_key
}
}
}
`;
it('moderators can add tags to comments', async () => {
const user = new UserModel({roles: ['MODERATOR' ]});
const context = new Context({user});
const response = await graphql(schema, query, {}, context, {id: comment.id, tag: 'BEST'});
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
expect(response.data.addCommentTag.comment.tags).to.deep.equal([{name: 'BEST'}]);
});
describe('users who cant add tags', () => {
Object.entries({
'anonymous': undefined,
'regular commenter': new UserModel({}),
'banned moderator': new UserModel({roles: ['MODERATOR'], status: 'BANNED'})
}).forEach(([ userDescription, user ]) => {
it(userDescription, async function () {
const context = new Context({user});
const response = await graphql(schema, query, {}, context, {id: comment.id, tag: 'BEST'});
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
expect(response.data.addCommentTag.errors).to.deep.equal([{'translation_key':'NOT_AUTHORIZED'}]);
expect(response.data.addCommentTag.comment).to.be.null;
});
});
});
});
@@ -0,0 +1,233 @@
const expect = require('chai').expect;
const {graphql} = require('graphql');
const schema = require('../../../../graph/schema');
const Context = require('../../../../graph/context');
const UserModel = require('../../../../models/user');
const AssetModel = require('../../../../models/asset');
const SettingsService = require('../../../../services/settings');
const ActionModel = require('../../../../models/action');
describe('graph.mutations.createComment', () => {
beforeEach(() => SettingsService.init());
const query = `
mutation CreateComment($body: String = "Here's my comment!") {
createComment(asset_id: "123", body: $body) {
comment {
id
status
tags {
name
}
}
errors {
translation_key
}
}
}
`;
describe('context with different user properties', () => {
beforeEach(() => AssetModel.create({id: '123'}));
[
{user: null, error: 'NOT_AUTHORIZED'},
{user: new UserModel({}), error: null}
].forEach(({user, error}) => {
describe(user != null ? 'with user' : 'without user', () => {
it(error ? 'does not create the comment' : 'creates the comment', () => {
const context = new Context({user});
return graphql(schema, query, {}, context)
.then(({data, errors}) => {
expect(errors).to.be.undefined;
if (error) {
expect(data.createComment).to.have.property('comment').null;
expect(data.createComment).to.have.property('errors').not.null;
expect(data.createComment.errors[0]).to.have.property('translation_key', error);
} else {
expect(data.createComment).to.have.property('comment').not.null;
expect(data.createComment).to.have.property('errors').null;
}
});
});
});
});
});
describe('users with different statuses', () => {
beforeEach(() => AssetModel.create({id: '123'}));
[
{user: new UserModel({status: 'ACTIVE'}), error: null},
{user: new UserModel({status: 'BANNED'}), error: 'NOT_AUTHORIZED'},
{user: new UserModel({status: 'PENDING'}), error: null},
{user: new UserModel({status: 'APPROVED'}), error: null}
].forEach(({user, error}) => {
describe(`user.status=${user.status}`, () => {
it(error ? 'does not create the comment' : 'creates the comment', () => {
const context = new Context({user});
return graphql(schema, query, {}, context)
.then(({data, errors}) => {
expect(errors).to.be.undefined;
if (error) {
expect(data.createComment).to.have.property('comment').null;
expect(data.createComment).to.have.property('errors').not.null;
expect(data.createComment.errors[0]).to.have.property('translation_key', error);
} else {
expect(data.createComment).to.have.property('comment').not.null;
expect(data.createComment).to.have.property('errors').null;
}
});
});
});
});
});
describe('assets with different statuses', () => {
[
{asset: new AssetModel({id: '123', closedAt: new Date((new Date()).getTime() + (10 * 86400000))}), error: null},
{asset: new AssetModel({id: '123', closedAt: new Date((new Date()).getTime() - (10 * 86400000))}), error: 'COMMENTING_CLOSED'}
].forEach(({asset, error}) => {
describe(`asset.isClosed=${asset.isClosed}`, () => {
beforeEach(() => asset.save());
it(error ? 'does not create the comment' : 'creates the comment', () => {
const context = new Context({user: new UserModel({status: 'ACTIVE'})});
return graphql(schema, query, {}, context)
.then(({data, errors}) => {
expect(errors).to.be.undefined;
if (error) {
expect(data.createComment).to.have.property('comment').null;
expect(data.createComment).to.have.property('errors').not.null;
expect(data.createComment.errors[0]).to.have.property('translation_key', error);
} else {
expect(data.createComment).to.have.property('comment').not.null;
expect(data.createComment).to.have.property('errors').null;
}
});
});
});
});
});
describe('comments made with different asset moderation settings', () => {
[
{moderation: 'PRE', status: 'PREMOD'},
{moderation: 'POST', status: 'NONE'}
].forEach(({moderation, status}) => {
describe(`moderation=${moderation}`, () => {
beforeEach(() => AssetModel.create({id: '123', settings: {moderation}}));
it(`creates comment with status=${status}`, () => {
const context = new Context({user: new UserModel({status: 'ACTIVE'})});
return graphql(schema, query, {}, context)
.then(({data, errors}) => {
expect(errors).to.be.undefined;
expect(data.createComment).to.have.property('comment').not.null;
expect(data.createComment).to.have.property('errors').null;
expect(data.createComment.comment).to.have.property('status', status);
});
});
});
});
});
describe('comments with/without banned words', () => {
beforeEach(() => Promise.all([
AssetModel.create({id: '123'}),
SettingsService.update({wordlist: {banned: ['WORST'], suspect: ['EH']}})
]));
[
{message: 'comment does not contain banned/suspect words', body: 'This is such a nice comment!', status: 'NONE', flagged: false},
{message: 'comment contains banned words', body: 'This is the WORST comment!', status: 'REJECTED', flagged: false},
{message: 'comment contains suspect words', body: 'This is the EH comment!', status: 'NONE', flagged: true}
].forEach(({message, body, status, flagged}) => {
describe(message, () => {
it(`should create a comment with status=${status} and it ${flagged ? 'should' : 'should not'} be flagged`, () => {
const context = new Context({user: new UserModel({status: 'ACTIVE'})});
return graphql(schema, query, {}, context, {
body
})
.then(({data, errors}) => {
expect(errors).to.be.undefined;
expect(data.createComment).to.have.property('comment').not.null;
expect(data.createComment.comment).to.have.property('status', status);
expect(data.createComment).to.have.property('errors').null;
return ActionModel.find({
item_id: data.createComment.comment.id,
action_type: 'FLAG'
});
})
.then((actions) => {
if (flagged) {
expect(actions).to.have.length(1);
} else {
expect(actions).to.have.length(0);
}
});
});
});
});
});
describe('users with different roles', () => {
beforeEach(() => AssetModel.create({id: '123'}));
[
{roles: [], tag: null},
{roles: ['ADMIN'], tag: 'STAFF'},
{roles: ['MODERATOR'], tag: 'STAFF'},
{roles: ['ADMIN', 'MODERATOR'], tag: 'STAFF'}
].forEach(({roles, tag}) => {
describe(`user.roles=${JSON.stringify(roles)}`, () => {
it(`creates comment ${tag ? `with tag=${tag}` : 'without tags'}`, () => {
const context = new Context({user: new UserModel({roles})});
return graphql(schema, query, {}, context)
.then(({data, errors}) => {
expect(errors).to.be.undefined;
expect(data.createComment).to.have.property('comment').not.null;
expect(data.createComment).to.have.property('errors').null;
if (tag) {
expect(data.createComment.comment).to.have.property('tags').length(1);
expect(data.createComment.comment.tags[0]).to.have.property('name', tag);
} else {
expect(data.createComment.comment).to.have.property('tags').length(0);
}
});
});
});
});
});
});
@@ -0,0 +1,69 @@
const expect = require('chai').expect;
const {graphql} = require('graphql');
const schema = require('../../../../graph/schema');
const Context = require('../../../../graph/context');
const UserModel = require('../../../../models/user');
const SettingsService = require('../../../../services/settings');
const CommentsService = require('../../../../services/comments');
describe('graph.mutations.removeCommentTag', () => {
let comment;
beforeEach(async () => {
await SettingsService.init();
comment = await CommentsService.publicCreate({body: `hello there! ${ String(Math.random()).slice(2)}`});
});
const query = `
mutation RemoveCommentTag ($id: ID!, $tag: String!) {
removeCommentTag(id:$id, tag:$tag) {
comment {
tags {
name
}
}
errors {
translation_key
}
}
}
`;
it('moderators can add remove tags from comments', async () => {
const user = new UserModel({roles: ['MODERATOR' ]});
const context = new Context({user});
// add a tag first
await CommentsService.addTag(comment.id, 'BEST');
const response = await graphql(schema, query, {}, context, {id: comment.id, tag: 'BEST'});
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
expect(response.data.removeCommentTag.errors).to.be.null;
expect(response.data.removeCommentTag.comment.tags).to.deep.equal([]);
});
describe('users who cant remove tags', () => {
Object.entries({
'anonymous': undefined,
'regular commenter': new UserModel({}),
'banned moderator': new UserModel({roles: ['MODERATOR'], status: 'BANNED'})
}).forEach(([ userDescription, user ]) => {
it(userDescription, async function () {
const context = new Context({user});
// add a tag first
await CommentsService.addTag(comment.id, 'BEST');
const response = await graphql(schema, query, {}, context, {id: comment.id, tag: 'BEST'});
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
expect(response.data.removeCommentTag.errors).to.deep.equal([{'translation_key':'NOT_AUTHORIZED'}]);
expect(response.data.removeCommentTag.comment).to.be.null;
});
});
});
});
+7
View File
@@ -0,0 +1,7 @@
const kue = require('../../services/kue');
beforeEach(() => {
// Empty the test tasks before finishing.
kue.TestQueue.splice(0, kue.TestQueue.length);
});
+15
View File
@@ -0,0 +1,15 @@
const mongoose = require('../helpers/mongoose');
before(function(done) {
this.timeout(30000);
mongoose.waitTillConnect(done);
});
beforeEach(function(done) {
mongoose.clearDB(done);
});
after(function(done) {
mongoose.disconnect(done);
});
+25
View File
@@ -0,0 +1,25 @@
const authorization = require('../../middleware/authorization');
// Add the passport middleware here before it's setup.
authorization.middleware.push((req, res, next) => {
req.user = JSON.parse(new Buffer(req.get('X-Mock-Authorization'), 'base64').toString('ascii'));
next();
});
const MockStrategy = {
/**
* Injects the new user into the request header for the mock middleware to
* interpret.
* @param {Object} user the user to inject
* @return {Object} the headers to add to the request
*/
inject(user) {
return {
'X-Mock-Authorization': new Buffer(JSON.stringify(user)).toString('base64')
};
}
};
module.exports = MockStrategy;
+71
View File
@@ -0,0 +1,71 @@
const passport = require('../../../passport');
const app = require('../../../../../app');
const chai = require('chai');
const expect = chai.expect;
const SettingsService = require('../../../../../services/settings');
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
// Setup chai.
chai.should();
chai.use(require('chai-http'));
const UsersService = require('../../../../../services/users');
describe('/api/v1/account/username', () => {
let mockUser;
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
}));
describe('#put', () => {
it('it should enable a user to edit their username if canEditName is enabled', () => {
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/username-enable`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.then(() => chai.request(app)
.put('/api/v1/account/username')
.set(passport.inject({id: mockUser.id, roles: []}))
.send({username: 'MojoJojo'}))
.then((res) => {
expect(res).to.have.status(204);
});
});
it('it should return an error if the wrong user tries to edit a username', (done) => {
chai.request(app)
.post(`/api/v1/users/${mockUser.id}/username-enable`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.then(() => chai.request(app)
.put('/api/v1/account/username')
.set(passport.inject({id: 'wrongid', roles: []}))
.send({username: 'MojoJojo'}))
.then(() => {
done(new Error('Exected Error'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
it('it should return an error when the user tries to edit their username if canEditName is disabled', (done) => {
chai.request(app)
.put('/api/v1/account/username')
.set(passport.inject({id: mockUser.id, roles: []}))
.send({username: 'MojoJojo'})
.then(() => {
done(new Error('Exected Error'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
});
});
+153
View File
@@ -0,0 +1,153 @@
const passport = require('../../../passport');
const app = require('../../../../../app');
const chai = require('chai');
const expect = chai.expect;
// Setup chai.
chai.should();
chai.use(require('chai-http'));
const AssetModel = require('../../../../../models/asset');
const AssetsService = require('../../../../../services/assets');
const SettingsService = require('../../../../../services/settings');
describe('/api/v1/assets', () => {
beforeEach(() => {
const settings = {id: '1', moderation: 'PRE', domains: {whitelist: ['test.com']}};
return SettingsService.init(settings).then(() => {
return AssetModel.create([
{
url: 'https://coralproject.net/news/asset1',
title: 'Asset 1',
description: 'term1',
closedAt: Date.now()
},
{
url: 'https://coralproject.net/news/asset2',
title: 'Asset 2',
description: 'term2',
closedAt: null
}
]);
});
});
describe('#get', () => {
it('should return all assets without a search query', () => {
return chai.request(app)
.get('/api/v1/assets')
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
const body = res.body;
expect(body).to.have.property('count', 2);
expect(body).to.have.property('result');
const assets = body.result;
expect(assets).to.have.length(2);
});
});
it('should return assets that we search for', () => {
return chai.request(app)
.get('/api/v1/assets?search=term2')
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
const body = res.body;
expect(body).to.have.property('count', 1);
expect(body).to.have.property('result');
const assets = body.result;
expect(assets).to.have.length(1);
const asset = assets[0];
expect(asset).to.have.property('url', 'https://coralproject.net/news/asset2');
expect(asset).to.have.property('title', 'Asset 2');
});
});
it('should not return assets that we do not search for', () => {
return chai.request(app)
.get('/api/v1/assets?search=term3')
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
const body = res.body;
expect(body).to.have.property('count', 0);
expect(body).to.have.property('result');
expect(body.result).to.be.empty;
});
});
it('should return only closed assets', () => {
return chai.request(app)
.get('/api/v1/assets?filter=closed')
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
const body = res.body;
expect(body).to.have.property('count', 1);
expect(body).to.have.property('result');
const assets = body.result;
expect(assets[0]).to.have.property('title', 'Asset 1');
});
});
it('should return only opened assets', () => {
return chai.request(app)
.get('/api/v1/assets?filter=open')
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
const body = res.body;
expect(body).to.have.property('count', 1);
expect(body).to.have.property('result');
const assets = body.result;
expect(assets[0]).to.have.property('title', 'Asset 2');
});
});
});
describe('#put', () => {
it('should close the asset', function() {
const today = Date.now();
return AssetsService.findOrCreateByUrl('http://test.com')
.then((asset) => {
expect(asset).to.have.property('isClosed', null);
expect(asset).to.have.property('closedAt', null);
return chai.request(app)
.put(`/api/v1/assets/${asset.id}/status`)
.set(passport.inject({roles: ['ADMIN']}))
.send({closedAt: today});
})
.then((res) => {
expect(res).to.have.status(204);
return AssetsService.findByUrl('http://test.com');
})
.then((asset) => {
expect(asset).to.have.property('isClosed', true);
expect(asset).to.have.property('closedAt').and.to.not.equal(null);
});
});
});
});
+99
View File
@@ -0,0 +1,99 @@
const app = require('../../../../../app');
const chai = require('chai');
const expect = chai.expect;
chai.use(require('chai-http'));
const UsersService = require('../../../../../services/users');
describe('/api/v1/auth', () => {
describe('#get', () => {
it('should return nothing when no user is logged in', () => {
return chai.request(app)
.get('/api/v1/auth')
.then((res) => {
expect(res.status).to.be.equal(204);
expect(res).to.not.have.a.body;
});
});
});
});
const SettingsService = require('../../../../../services/settings');
describe('/api/v1/auth/local', () => {
let mockUser;
beforeEach(() => {
const settings = {requireEmailConfirmation: false, wordlist: {banned: ['bad'], suspect: ['naughty']}};
return SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('maria@gmail.com', 'password!', 'Maria')
.then((user) => {
mockUser = user;
});
});
});
describe('email confirmation disabled', () => {
describe('#post', () => {
it('should send back the user on a successful login', () => {
return chai.request(app)
.post('/api/v1/auth/local')
.send({email: 'maria@gmail.com', password: 'password!'})
.then((res2) => {
expect(res2).to.have.status(200);
expect(res2).to.be.json;
expect(res2.body).to.have.property('user');
expect(res2.body.user).to.have.property('username', 'Maria');
});
});
it('should not send back the user on a unsuccessful login', () => {
return chai.request(app)
.post('/api/v1/auth/local')
.send({email: 'maria@gmail.com', password: 'password!3'})
.catch((err) => {
expect(err).to.not.be.null;
expect(err.response).to.have.status(401);
expect(err.response.body).to.have.property('message', 'not authorized');
});
});
});
});
describe('email confirmation enabled', () => {
beforeEach(() => SettingsService.update({requireEmailConfirmation: true}));
describe('#post', () => {
it('should not allow a login from a user that is not confirmed', () => {
return chai.request(app)
.post('/api/v1/auth/local')
.send({email: 'maria@gmail.com', password: 'password!'})
.catch((err) => {
expect(err).to.have.status(401);
err.response.body.should.have.property('error');
err.response.body.error.should.have.property('metadata');
err.response.body.error.metadata.should.have.property('message', 'maria@gmail.com');
return UsersService.createEmailConfirmToken(mockUser.id, mockUser.profiles[0].id);
})
.then(UsersService.verifyEmailConfirmation)
.then(() => {
return chai.request(app)
.post('/api/v1/auth/local')
.send({email: 'maria@gmail.com', password: 'password!'});
})
.then((res) => {
expect(res).to.have.status(200);
expect(res).to.be.json;
expect(res.body).to.have.property('user');
expect(res.body.user).to.have.property('username', 'Maria');
});
});
});
});
});
+51
View File
@@ -0,0 +1,51 @@
const passport = require('../../../passport');
const app = require('../../../../../app');
const chai = require('chai');
const expect = chai.expect;
chai.should();
chai.use(require('chai-http'));
const SettingsService = require('../../../../../services/settings');
const defaults = {id: '1', moderation: 'PRE'};
describe('/api/v1/settings', () => {
beforeEach(() => SettingsService.init(defaults));
describe('#get', () => {
it('should return a settings object', () => {
return chai.request(app)
.get('/api/v1/settings')
.set(passport.inject({
roles: ['ADMIN']
}))
.then((res) => {
expect(res).to.have.status(200);
expect(res).to.be.json;
expect(res.body).to.have.property('moderation', 'PRE');
});
});
});
describe('#put', () => {
it('should update the settings', () => {
return chai.request(app)
.put('/api/v1/settings')
.set(passport.inject({roles: ['ADMIN']}))
.send({moderation: 'POST'})
.then((res) => {
expect(res).to.have.status(204);
return SettingsService.retrieve();
})
.then((settings) => {
expect(settings).to.have.property('moderation', 'POST');
});
});
});
});
+100
View File
@@ -0,0 +1,100 @@
const passport = require('../../../passport');
const app = require('../../../../../app');
const mailer = require('../../../../../services/mailer');
const chai = require('chai');
const expect = chai.expect;
const SettingsService = require('../../../../../services/settings');
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
// Setup chai.
chai.should();
chai.use(require('chai-http'));
const UsersService = require('../../../../../services/users');
describe('/api/v1/users/:user_id/email/confirm', () => {
let mockUser;
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
}));
describe('#post', () => {
it('should send an email when we hit the endpoint', () => {
expect(mailer.task.tasks).to.have.length(0);
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/email/confirm`)
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
expect(res).to.have.status(204);
expect(mailer.task.tasks).to.have.length(1);
});
});
it('should send a 404 on not matching a user', () => {
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/email/confirm`)
.set(passport.inject({roles: ['ADMIN']}))
.then((res) => {
expect(res).to.have.status(204);
expect(mailer.task.tasks).to.have.length(1);
});
});
});
});
describe('/api/v1/users/:user_id/actions', () => {
let mockUser;
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
}));
describe('#post', () => {
it('it should update actions', () => {
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/actions`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.send({'action_type': 'FLAG', metadata: {reason: 'Bio is too awesome.'}})
.then((res) => {
expect(res).to.have.status(201);
expect(res).to.have.body;
expect(res.body).to.have.property('action_type', 'FLAG');
expect(res.body).to.have.property('item_id', mockUser.id);
});
});
});
});
describe('/api/v1/users/:user_id/username-enable', () => {
let mockUser;
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
}));
describe('#post', () => {
it('it should enable a user to edit their username', () => {
return chai.request(app)
.post(`/api/v1/users/${mockUser.id}/username-enable`)
.set(passport.inject({id: '456', roles: ['ADMIN']}))
.then((res) => {
expect(res).to.have.status(204);
});
});
});
});
+107
View File
@@ -0,0 +1,107 @@
const ActionModel = require('../../../models/action');
const ActionsService = require('../../../services/actions');
const expect = require('chai').expect;
describe('services.ActionsService', () => {
let mockActions = [];
beforeEach(() => ActionModel.create([
{
action_type: 'FLAG',
item_id: '123',
item_type: 'COMMENTS',
user_id: 'flagginguserid'
},
{
action_type: 'FLAG',
item_id: '456',
item_type: 'COMMENTS'
},
{
action_type: 'FLAG',
item_id: '123',
item_type: 'COMMENTS'
},
{
action_type: 'LIKE',
item_id: '123',
item_type: 'COMMENTS'
}
]).then((actions) => {
mockActions = actions;
}));
describe('#findById()', () => {
it('should find an action by id', () => {
return ActionsService.findById(mockActions[0].id).then((result) => {
expect(result).to.not.be.null;
expect(result).to.have.property('action_type', 'FLAG');
});
});
});
describe('#findByItemIdArray()', () => {
it('should find an array of actions from an array of item_ids', () => {
return ActionsService.findByItemIdArray(['123', '456']).then((result) => {
expect(result).to.have.length(4);
});
});
});
describe('#getActionSummaries()', () => {
it('should return properly formatted summaries from an array of item_ids', () => {
return ActionsService
.getActionSummaries(['123', '789'])
.then((summaries) => {
expect(summaries).to.have.length(2);
expect(summaries).to.deep.include({
action_type: 'LIKE',
count: 1,
item_id: '123',
item_type: 'COMMENTS',
current_user: null
});
expect(summaries).to.deep.include({
action_type: 'FLAG',
count: 2,
item_id: '123',
item_type: 'COMMENTS',
current_user: null
});
});
});
it('should include a current user when one is passed', () => {
return ActionsService
.getActionSummaries(['123'], 'flagginguserid')
.then((summaries) => {
expect(summaries).to.have.length(2);
let summary = summaries.find((s) => s.item_id === '123' && s.action_type === 'FLAG');
expect(summary).to.not.be.undefined;
expect(summary.current_user).to.not.be.null;
expect(summary.current_user).to.have.property('item_id', '123');
expect(summary.current_user).to.have.property('item_type', 'COMMENTS');
expect(summary.current_user).to.have.property('user_id', 'flagginguserid');
expect(summary.current_user).to.have.property('action_type', 'FLAG');
});
});
it('should not include a current user when one is passed for a user that doesn\'t have an action', () => {
return ActionsService
.getActionSummaries(['123'], 'flagginguserid2')
.then((summaries) => {
expect(summaries).to.have.length(2);
summaries.forEach((summary) => {
expect(summary).to.not.be.undefined;
expect(summary).to.have.property('current_user', null);
});
});
});
});
});
+123
View File
@@ -0,0 +1,123 @@
const AssetModel = require('../../../models/asset');
const AssetsService = require('../../../services/assets');
const SettingsService = require('../../../services/settings');
const chai = require('chai');
const expect = chai.expect;
// Use the chai should.
chai.should();
describe('services.AssetsService', () => {
beforeEach(() => {
const settings = {id: '1', moderation: 'PRE', domains: {whitelist: ['new.test.com', 'test.com', 'override.test.com']}};
const defaults = {url:'http://test.com'};
return SettingsService.init(settings).then(() => {
return AssetModel.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true});
});
});
describe('#findById', ()=> {
it('should find an asset by the id', () => {
return AssetsService.findById(1)
.then((asset) => {
expect(asset).to.have.property('url')
.and.to.equal('http://test.com');
});
});
});
describe('#findByUrl', ()=> {
beforeEach(() => AssetsService.findOrCreateByUrl('http://test.com'));
it('should find an asset by a url', () => {
return AssetsService
.findByUrl('http://test.com')
.then((asset) => {
expect(asset).to.have.property('url', 'http://test.com');
});
});
it('should return null when a url does not exist', () => {
return AssetsService
.findByUrl('http://new.test.com')
.then((asset) => {
expect(asset).to.be.null;
});
});
});
describe('#findOrCreateByUrl', ()=> {
it('should find an asset by a url', () => {
return AssetsService
.findOrCreateByUrl('http://test.com')
.then((asset) => {
expect(asset).to.have.property('url')
.and.to.equal('http://test.com');
});
});
it('should return a new asset when the url does not exist and its domain is whitelisted', () => {
return AssetsService
.findOrCreateByUrl('http://new.test.com')
.then((asset) => {
expect(asset).to.have.property('id')
.and.to.not.equal(1);
});
});
it('should return an error when the url does not exist and its domain is not whitelisted', () => {
return AssetsService
.findOrCreateByUrl('http://bad.test.com')
.then((asset) => {
expect(asset).to.be.null;
})
.catch((error) => {
expect(error).to.not.be.null;
});
});
});
describe('#overrideSettings', () => {
it('should update the settings', () => {
return AssetsService
.findOrCreateByUrl('https://override.test.com/asset')
.then((asset) => {
expect(asset).to.have.property('settings');
expect(asset.settings).to.be.null;
return AssetsService.overrideSettings(asset.id, {moderation: 'PRE'});
})
.then(() => {
return AssetsService.findOrCreateByUrl('https://override.test.com/asset');
})
.then((asset) => {
expect(asset).to.have.property('settings');
expect(asset.settings).is.an('object');
expect(asset.settings).to.have.property('moderation', 'PRE');
});
});
});
describe('#findOrCreateByUrl', ()=> {
it('should find an asset by a url', () => {
return AssetsService
.findOrCreateByUrl('http://test.com')
.then((asset) => {
expect(asset).to.have.property('url')
.and.to.equal('http://test.com');
});
});
it('should return a new asset when the url does not exist', () => {
return AssetsService
.findOrCreateByUrl('http://new.test.com')
.then((asset) => {
expect(asset).to.have.property('id')
.and.to.not.equal(1);
});
});
});
});
+317
View File
@@ -0,0 +1,317 @@
const CommentModel = require('../../../models/comment');
const ActionModel = require('../../../models/action');
const ActionsService = require('../../../services/actions');
const UsersService = require('../../../services/users');
const SettingsService = require('../../../services/settings');
const CommentsService = require('../../../services/comments');
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
const expect = require('chai').use(require('chai-as-promised')).expect;
describe('services.CommentsService', () => {
const comments = [{
body: 'comment 10',
asset_id: '123',
status_history: [],
parent_id: '',
author_id: '123',
id: '1'
}, {
body: 'comment 20',
asset_id: '123',
status_history: [{
type: 'ACCEPTED'
}],
status: 'ACCEPTED',
parent_id: '',
author_id: '123',
id: '2'
}, {
body: 'comment 30',
asset_id: '456',
status_history: [],
parent_id: '',
author_id: '456',
id: '3'
}, {
body: 'comment 40',
asset_id: '123',
status_history: [{
type: 'REJECTED'
}],
status: 'REJECTED',
parent_id: '',
author_id: '456',
id: '4'
}, {
body: 'comment 50',
asset_id: '1234',
status_history: [{
type: 'PREMOD'
}],
status: 'PREMOD',
parent_id: '',
author_id: '456',
id: '5'
}, {
body: 'comment 60',
asset_id: '1234',
status_history: [{
type: 'PREMOD'
}],
status: 'PREMOD',
parent_id: '',
author_id: '456',
id: '6'
}];
const users = [{
id: 'u1',
email: 'stampi@gmail.com',
username: 'Stampi',
password: '1Coral!!'
}, {
email: 'sockmonster@gmail.com',
username: 'Sockmonster',
password: '2Coral!!'
}];
const actions = [{
action_type: 'FLAG',
item_id: '3',
item_type: 'COMMENTS',
user_id: '123'
}, {
action_type: 'LIKE',
item_id: '1',
item_type: 'COMMENTS',
user_id: '456'
}];
beforeEach(() => {
return SettingsService.init(settings).then(() => {
return Promise.all([
CommentModel.create(comments),
UsersService.createLocalUsers(users),
ActionModel.create(actions)
]);
});
});
describe('#publicCreate()', () => {
it('creates a new comment', () => {
return CommentsService
.publicCreate({
body: 'This is a comment!',
status: 'ACCEPTED'
}).then((c) => {
expect(c).to.not.be.null;
expect(c.id).to.not.be.null;
expect(c.id).to.be.uuid;
expect(c.status).to.be.equal('ACCEPTED');
});
});
it('creates many new comments', () => {
return CommentsService
.publicCreate([{
body: 'This is a comment!',
status: 'ACCEPTED'
}, {
body: 'This is another comment!'
}, {
body: 'This is a rejected comment!',
status: 'REJECTED'
}]).then(([c1, c2, c3]) => {
expect(c1).to.not.be.null;
expect(c1.id).to.be.uuid;
expect(c1.status).to.be.equal('ACCEPTED');
expect(c2).to.not.be.null;
expect(c2.id).to.be.uuid;
expect(c2.status).to.be.equal('NONE');
expect(c3).to.not.be.null;
expect(c3.id).to.be.uuid;
expect(c3.status).to.be.equal('REJECTED');
});
});
});
describe('#findById()', () => {
it('should find a comment by id', () => {
return CommentsService
.findById('1')
.then((result) => {
expect(result).to.not.be.null;
expect(result).to.have.property('body', 'comment 10');
});
});
});
describe('#findByAssetId()', () => {
it('should find an array of all comments by asset id', () => {
return CommentsService
.findByAssetId('123')
.then((result) => {
expect(result).to.have.length(3);
result.sort((a, b) => {
if (a.body < b.body) {return -1;}
else {return 1;}
});
expect(result[0]).to.have.property('body', 'comment 10');
expect(result[1]).to.have.property('body', 'comment 20');
expect(result[2]).to.have.property('body', 'comment 40');
});
});
});
describe('#moderationQueue()', () => {
it('should find an array of new comments to moderate when pre-moderation', () => {
return CommentsService
.moderationQueue('PREMOD')
.then((result) => {
expect(result).to.not.be.null;
expect(result).to.have.lengthOf(2);
});
});
});
describe('#removeAction', () => {
it('should remove an action', () => {
return CommentsService
.removeAction('3', '123', 'flag')
.then(() => {
return ActionsService.findByItemIdArray(['123']);
})
.then((actions) => {
expect(actions.length).to.equal(0);
});
});
});
describe('#findByUserId', () => {
it('should return all comments if admin', () => {
return CommentsService
.findByUserId('456', true)
.then(comments => {
expect(comments).to.have.length(4);
});
});
it('should not return premod and rejected comments if not admin', () => {
return CommentsService
.findByUserId('456')
.then(comments => {
expect(comments).to.have.length(1);
});
});
});
describe('#addTag', () => {
it('adds a tag', async () => {
const commentId = comments[0].id;
const tagName = 'BEST';
const userId = users[0].id;
await CommentsService.addTag(commentId, tagName, userId);
const updatedComment = await CommentsService.findById(commentId);
expect(updatedComment.tags.length).to.equal(1);
expect(updatedComment.tags[0].name).to.equal(tagName);
expect(updatedComment.tags[0].assigned_by).to.equal(userId);
expect(updatedComment.tags[0].created_at).to.be.an.instanceof(Date);
});
it('can\'t add a tag to comment id that doesn\'t exist', async () => {
const commentId = 'fakenews';
const tagName = 'BEST';
const userId = users[0].id;
await expect(CommentsService.addTag(commentId, tagName, userId)).to.be.rejected;
});
it('can\'t add same tag.name twice', async () => {
const commentId = comments[0].id;
const tagName = 'BEST';
const userId = users[0].id;
// first time
await CommentsService.addTag(commentId, tagName, userId);
// second time should fail
await expect(CommentsService.addTag(commentId, tagName, userId)).to.be.rejected;
});
});
describe('#removeTag', () => {
it('removes a tag', async () => {
const commentId = comments[0].id;
const tagName = 'BEST';
await CommentsService.addTag(commentId, tagName, users[0].id);
const updatedComment = await CommentsService.findById(commentId);
expect(updatedComment.tags.length).to.equal(1);
// ok now to remove it
await CommentsService.removeTag(commentId, tagName);
const updatedComment2 = await CommentsService.findById(commentId);
expect(updatedComment2.tags.length).to.equal(0);
});
it('throws if removing a tag that isn\'t there', async () => {
const commentId = comments[0].id;
// just make sure it has no tags to start
const updatedComment2 = await CommentsService.findById(commentId);
expect(updatedComment2.tags.length).to.equal(0);
const tagName = 'BEST';
// ok now to remove it
await expect(CommentsService.removeTag(commentId, tagName)).to.be.rejected;
});
});
describe('#changeStatus', () => {
it('should change the status of a comment from no status', () => {
let comment_id = comments[0].id;
return CommentsService.findById(comment_id)
.then((c) => {
expect(c.status).to.be.equal('NONE');
return CommentsService.pushStatus(comment_id, 'REJECTED', '123');
})
.then(() => CommentsService.findById(comment_id))
.then((c) => {
expect(c).to.have.property('status');
expect(c.status).to.equal('REJECTED');
expect(c.status_history).to.have.length(1);
expect(c.status_history[0]).to.have.property('type', 'REJECTED');
expect(c.status_history[0]).to.have.property('assigned_by', '123');
});
});
it('should change the status of a comment from accepted', () => {
return CommentsService.pushStatus(comments[1].id, 'REJECTED', '123')
.then(() => CommentsService.findById(comments[1].id))
.then((c) => {
expect(c).to.have.property('status_history');
expect(c).to.have.property('status');
expect(c.status).to.equal('REJECTED');
expect(c.status_history).to.have.length(2);
expect(c.status_history[0]).to.have.property('type', 'ACCEPTED');
expect(c.status_history[0]).to.have.property('assigned_by', null);
expect(c.status_history[1]).to.have.property('type', 'REJECTED');
expect(c.status_history[1]).to.have.property('assigned_by', '123');
});
});
});
});
+52
View File
@@ -0,0 +1,52 @@
const expect = require('chai').expect;
const Domainlist = require('../../../services/domainlist');
const SettingsService = require('../../../services/settings');
describe('services.Domainlist', () => {
const domainlists = {
whitelist: [
'nytimes.com',
'wapo.com'
]
};
let domainlist = new Domainlist();
const settings = {id: '1', moderation: 'PRE', domainlist: {whitelist: ['nytimes.com', 'wapo.com']}};
beforeEach(() => SettingsService.init(settings));
describe('#init', () => {
before(() => domainlist.upsert(domainlists));
it('has entries', () => {
expect(domainlist.lists.whitelist).to.not.be.empty;
});
});
describe('#match', () => {
const whiteList = Domainlist.parseList(domainlists['whitelist']);
it('does match on an included domain', () => {
[
'wapo.com',
'nytimes.com'
].forEach((domain) => {
expect(domainlist.match(whiteList, domain)).to.be.true;
});
});
it('does not match on a not included domain', () => {
[
'badsite.com',
'www.badsite.com',
'otherexample.com'
].forEach((domain) => {
expect(domainlist.match(whiteList, domain)).to.be.false;
});
});
});
});
+22
View File
@@ -0,0 +1,22 @@
describe('services.scraper', () => {
describe('#create', () => {
it('should create a new kue job');
});
describe('#scrape', () => {
it('should scrape complete information');
it('should scrape what it can');
});
describe('#update', () => {
it('should update the database record entries from the meta');
});
describe('#process', () => {
it('should start the processor to scrape assets');
});
describe('#shutdown', () => {
it('should shutdown the job processor');
});
});
+56
View File
@@ -0,0 +1,56 @@
const SettingsService = require('../../../services/settings');
const expect = require('chai').expect;
describe('services.SettingsService', () => {
beforeEach(() => SettingsService.init({moderation: 'PRE', wordlist: ['donut']}));
describe('#retrieve()', () => {
it('should have a moderation field defined', () => {
return SettingsService.retrieve().then(settings => {
expect(settings).to.have.property('moderation').and.to.equal('PRE');
});
});
it('should have two infoBox fields defined', () => {
return SettingsService.retrieve().then(settings => {
expect(settings).to.have.property('infoBoxEnable').and.to.equal(false);
expect(settings).to.have.property('infoBoxContent').and.to.equal('');
});
});
});
describe('#update()', () => {
it('should update the settings with a passed object', () => {
const mockSettings = {moderation: 'POST', infoBoxEnable: true, infoBoxContent: 'yeah'};
return SettingsService.update(mockSettings).then(updatedSettings => {
expect(updatedSettings).to.be.an('object');
expect(updatedSettings).to.have.property('moderation').and.to.equal('POST');
expect(updatedSettings).to.have.property('infoBoxEnable', true);
expect(updatedSettings).to.have.property('infoBoxContent', 'yeah');
});
});
});
describe('#get', () => {
it('should return the moderation settings', () => {
return SettingsService.retrieve().then(({moderation}) => {
expect(moderation).not.to.be.null;
});
});
});
describe('#merge', () => {
it('should merge a settings object and its overrides', () => {
return SettingsService
.retrieve()
.then((settings) => {
let ovrSett = {moderation: 'POST'};
settings.merge(ovrSett);
expect(settings).to.have.property('moderation', 'POST');
});
});
});
});
+254
View File
@@ -0,0 +1,254 @@
const UsersService = require('../../../services/users');
const SettingsService = require('../../../services/settings');
const expect = require('chai').expect;
describe('services.UsersService', () => {
let mockUsers;
beforeEach(() => {
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
return SettingsService.init(settings).then(() => {
return 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'
}]).then((users) => {
mockUsers = users;
});
});
});
describe('#findById()', () => {
it('should find a user by id', () => {
return UsersService
.findById(mockUsers[0].id)
.then((user) => {
expect(user).to.have.property('username', 'Stampi');
});
});
});
describe('#findByIdArray()', () => {
it('should find an array of users from an array of ids', () => {
const ids = mockUsers.map((user) => user.id);
return UsersService.findByIdArray(ids).then((result) => {
expect(result).to.have.length(3);
});
});
});
describe('#findPublicByIdArray()', () => {
it('should find an array of users from an array of ids', () => {
const ids = mockUsers.map((user) => user.id);
return UsersService.findPublicByIdArray(ids).then((result) => {
expect(result).to.have.length(3);
const sorted = result.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', () => {
return UsersService
.createEmailConfirmToken(mockUsers[0].id, mockUsers[0].profiles[0].id)
.then((token) => {
expect(token).to.not.be.null;
});
});
it('should not create a token for a user already verified', () => {
return UsersService
.createEmailConfirmToken(mockUsers[0].id, mockUsers[0].profiles[0].id)
.then((token) => {
expect(token).to.not.be.null;
return UsersService.verifyEmailConfirmation(token);
})
.then(() => {
return UsersService.createEmailConfirmToken(mockUsers[0].id, mockUsers[0].profiles[0].id);
})
.catch((err) => {
expect(err).to.have.property('message', 'email address already confirmed');
});
});
});
describe('#verifyEmailConfirmation', () => {
it('should correctly validate a valid token', () => {
return UsersService
.createEmailConfirmToken(mockUsers[0].id, mockUsers[0].profiles[0].id)
.then((token) => {
expect(token).to.not.be.null;
return UsersService.verifyEmailConfirmation(token);
});
});
it('should correctly reject an invalid token', () => {
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].id, 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');
});
});
});
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');
});
});
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('#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 return an error if canEditName is false', (done) => {
UsersService
.editName(mockUsers[0].id, 'Jojo')
.then(() => UsersService.findById(mockUsers[0].id))
.then(() => {
done(new Error('Error expected'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
it('should return an error if the username is already taken', (done) => {
UsersService
.toggleNameEdit(mockUsers[0].id, true)
.then(() => UsersService.editName(mockUsers[0].id, 'Marvel'))
.then(() => UsersService.findById(mockUsers[0].id))
.then(() => {
done(new Error('Error expected'));
})
.catch((err) => {
expect(err).to.be.truthy;
done();
});
});
});
});
+96
View File
@@ -0,0 +1,96 @@
const expect = require('chai').expect;
const Errors = require('../../../errors');
const Wordlist = require('../../../services/wordlist');
const SettingsService = require('../../../services/settings');
describe('services.Wordlist', () => {
const wordlists = {
banned: [
'cookies',
'how to do bad things',
'how to do really bad things'
],
suspect: [
'do bad things'
]
};
let wordlist = new Wordlist();
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
beforeEach(() => SettingsService.init(settings));
describe('#init', () => {
before(() => wordlist.upsert(wordlists));
it('has entries', () => {
expect(wordlist.lists.banned).to.not.be.empty;
expect(wordlist.lists.suspect).to.not.be.empty;
});
});
describe('#match', () => {
const bannedList = Wordlist.parseList(wordlists.banned);
it('does match on a bad word', () => {
[
'how to do really bad things',
'what is cookies',
'cookies',
'COOKIES.',
'how to do bad things',
'How To do bad things!'
].forEach((word) => {
expect(wordlist.match(bannedList, word)).to.be.true;
});
});
it('does not match on a good word', () => {
[
'how to',
'cookie',
'how to be a great person?',
'how to not do really bad things?'
].forEach((word) => {
expect(wordlist.match(bannedList, word)).to.be.false;
});
});
});
describe('#filter', () => {
before(() => wordlist.upsert(wordlists));
it('matches on bodies containing bad words', () => {
let errors = wordlist.filter({
content: 'how to do really bad things?'
}, 'content');
expect(errors).to.have.property('banned', Errors.ErrContainsProfanity);
});
it('does not match on bodies not containing bad words', () => {
let errors = wordlist.filter({
content: 'how to not do really bad things?'
}, 'content');
expect(errors).to.not.have.property('banned');
});
it('does not match on bodies not containing the bad word field', () => {
let errors = wordlist.filter({
author: 'how to do really bad things?',
content: 'how to be a great person?'
}, 'content');
expect(errors).to.not.have.property('banned');
});
});
});