mirror of
https://github.com/wassname/talk.git
synced 2026-08-16 11:29:31 +08:00
Merge branch 'master' of github.com:coralproject/talk into e2e-env-fix
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"plugins": [
|
||||
"mocha"
|
||||
],
|
||||
"extends": "../.eslintrc.json",
|
||||
"rules": {
|
||||
"mocha/no-exclusive-tests": "warn"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"mocha": true
|
||||
},
|
||||
"extends": "../.eslintrc.json",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
},
|
||||
"sourceType": "module"
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"rules": {
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import 'react';
|
||||
import 'redux';
|
||||
import {expect} from 'chai';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import * as actions from '../../../../client/coral-admin/src/actions/assets';
|
||||
import {Map} from 'immutable';
|
||||
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
const mockStore = configureStore();
|
||||
|
||||
describe('Asset actions', () => {
|
||||
let store;
|
||||
|
||||
const assets = [
|
||||
{
|
||||
url: 'http://test.com',
|
||||
id: '123',
|
||||
status: 'closed'
|
||||
},
|
||||
{
|
||||
url: 'http://test.org',
|
||||
id: '456',
|
||||
status: 'open'
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore(new Map({}));
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
describe('FETCH_ASSETS_REQUEST', () => {
|
||||
|
||||
it('should fetch a list of assets', () => {
|
||||
|
||||
fetchMock.get('*', JSON.stringify({
|
||||
result: assets,
|
||||
count: 2
|
||||
}));
|
||||
|
||||
return actions.fetchAssets(2, 20)(store.dispatch)
|
||||
.then(() => {
|
||||
expect(store.getActions()[0]).to.have.property('type', 'FETCH_ASSETS_REQUEST');
|
||||
expect(store.getActions()[1]).to.have.property('type', 'FETCH_ASSETS_SUCCESS');
|
||||
expect(store.getActions()[1]).to.have.property('count', 2);
|
||||
expect(store.getActions()[1]).to.have.property('assets').
|
||||
and.to.deep.equal(assets);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an error appropriatly', () => {
|
||||
|
||||
fetchMock.get('*', 404);
|
||||
|
||||
return actions.fetchAssets(2, 20)(store.dispatch)
|
||||
.then(() => {
|
||||
expect(store.getActions()[0]).to.have.property('type', 'FETCH_ASSETS_REQUEST');
|
||||
expect(store.getActions()[1]).to.have.property('type', 'FETCH_ASSETS_FAILURE');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UPDATE_ASSET_STATE_REQUEST', () => {
|
||||
|
||||
it('should update an asset', () => {
|
||||
|
||||
fetchMock.put('*', JSON.stringify(assets[0]));
|
||||
|
||||
return actions.updateAssetState('123', 'status', 'open')(store.dispatch)
|
||||
.then(() => {
|
||||
expect(store.getActions()[0]).to.have.property('type', 'UPDATE_ASSET_STATE_REQUEST');
|
||||
expect(store.getActions()[1]).to.have.property('type', 'UPDATE_ASSET_STATE_SUCCESS');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should return an error appropriately', () => {
|
||||
|
||||
fetchMock.put('*', 404);
|
||||
|
||||
return actions.updateAssetState('123', 'status', 'open')(store.dispatch)
|
||||
.then(() => {
|
||||
expect(store.getActions()[0]).to.have.property('type', 'UPDATE_ASSET_STATE_REQUEST');
|
||||
expect(store.getActions()[1]).to.have.property('type', 'UPDATE_ASSET_STATE_FAILURE');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import {Map, fromJS} from 'immutable';
|
||||
import {expect} from 'chai';
|
||||
import assetsReducer from '../../../../client/coral-admin/src/reducers/assets';
|
||||
|
||||
describe ('assetsReducer', () => {
|
||||
describe('FETCH_ASSETS_SUCCESS', () => {
|
||||
it('should replace the existing assets', () => {
|
||||
const action = {
|
||||
type: 'FETCH_ASSETS_SUCCESS',
|
||||
count: 200,
|
||||
assets: [
|
||||
{
|
||||
id: '123',
|
||||
url: 'http://test.com',
|
||||
closedAt: 'tomorrow'
|
||||
},
|
||||
{
|
||||
id: '456',
|
||||
url: 'http://test2.com',
|
||||
closedAt: 'thursday'
|
||||
},
|
||||
]
|
||||
};
|
||||
const store = new Map({});
|
||||
const result = assetsReducer(store, action);
|
||||
expect(result.getIn(['byId', '123']).toJS()).to.deep.equal({
|
||||
url: 'http://test.com',
|
||||
closedAt: 'tomorrow',
|
||||
id: '123'
|
||||
});
|
||||
expect(result.getIn(['ids']).toJS()).to.deep.equal([
|
||||
'123',
|
||||
'456'
|
||||
]);
|
||||
expect(result.getIn(['count'])).to.equal(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UPDATE_ASSET_STATE_REQUEST', () => {
|
||||
it('should update the state of a particular asset', () => {
|
||||
const action = {
|
||||
type: 'UPDATE_ASSET_STATE_REQUEST',
|
||||
id: '123',
|
||||
closedAt: null
|
||||
};
|
||||
const store = new fromJS({
|
||||
byId: {
|
||||
'123': {
|
||||
id: '123',
|
||||
url: 'http://test.com',
|
||||
closedAt: Date.now()
|
||||
},
|
||||
'456': {
|
||||
id: '456',
|
||||
url: 'http://test2.com',
|
||||
closedAt: 'thursday'
|
||||
}
|
||||
}
|
||||
});
|
||||
const result = assetsReducer(store, action);
|
||||
expect(result.getIn(['byId', '123', 'closedAt'])).to.equal.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,198 @@
|
||||
import 'react';
|
||||
import 'redux';
|
||||
import {expect} from 'chai';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import * as actions from '../../../../client/coral-framework/actions/items';
|
||||
import {Map} from 'immutable';
|
||||
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
const mockStore = configureStore();
|
||||
|
||||
describe('itemActions', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore(new Map({}));
|
||||
fetchMock.restore();
|
||||
|
||||
});
|
||||
|
||||
describe('getStream', () => {
|
||||
const assetUrl = 'http://www.test.com';
|
||||
const response = {
|
||||
assets: [{
|
||||
id: '1234', url: assetUrl
|
||||
}],
|
||||
comments: [
|
||||
{body: 'stuff', id: '123'},
|
||||
{body: 'morestuff', id: '456'}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
action_type: 'like',
|
||||
item_id: '123',
|
||||
count: 1,
|
||||
id: 'like_123',
|
||||
current_user: false
|
||||
},
|
||||
{
|
||||
action_type: 'flag',
|
||||
item_id: '456',
|
||||
count: 5,
|
||||
id: 'flag_456',
|
||||
current_user: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
it('should get an stream from an asset_url and send the appropriate dispatches', () => {
|
||||
fetchMock.get('*', JSON.stringify(response));
|
||||
return actions.getStream(assetUrl)(store.dispatch)
|
||||
.then((res) => {
|
||||
expect(fetchMock.calls().matched[0][0]).to.equal('/api/v1/stream?asset_url=http%3A%2F%2Fwww.test.com');
|
||||
expect(res).to.deep.equal(response);
|
||||
expect(store.getActions()[1]).to.deep.equal({
|
||||
type: actions.ADD_ITEM,
|
||||
item: response.comments[0],
|
||||
item_type: 'comments',
|
||||
id: '123'
|
||||
});
|
||||
expect(store.getActions()[2]).to.deep.equal({
|
||||
type: actions.ADD_ITEM,
|
||||
item: response.comments[1],
|
||||
item_type: 'comments',
|
||||
id: '456'
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should handle an error', () => {
|
||||
fetchMock.get('*', 404);
|
||||
return actions.getStream(assetUrl)(store.dispatch)
|
||||
.catch((err) => {
|
||||
expect(err).to.be.truthy;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Disabling tests for this function until is is used again.
|
||||
xdescribe('getItemsArray', () => {
|
||||
const response = {items: [{type: 'comment', id: '123'}, {type: 'comment', id: '456'}]};
|
||||
const ids = [1, 2];
|
||||
|
||||
it('should get an item from an array of ids and send the appropriate dispatches', () => {
|
||||
fetchMock.get('*', JSON.stringify(response));
|
||||
return actions.getItemsArray(ids)(store.dispatch)
|
||||
.then((res) => {
|
||||
expect(res).to.deep.equal(response.items);
|
||||
expect(store.getActions()[0]).to.deep.equal({
|
||||
type: actions.ADD_ITEM,
|
||||
item: {
|
||||
type: 'comment',
|
||||
id: '123'
|
||||
},
|
||||
id: '123'
|
||||
});
|
||||
expect(store.getActions()[1]).to.deep.equal({
|
||||
type: actions.ADD_ITEM,
|
||||
item: {
|
||||
type: 'comment', id: '456'
|
||||
},
|
||||
id: '456'
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should handle an error', () => {
|
||||
fetchMock.get('*', 404);
|
||||
return actions.getItemsArray(ids)(store.dispatch)
|
||||
.catch((err) => {
|
||||
expect(err).to.be.truthy;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// NEED TO FIGURE OUT HOW TO TEST WITH CSRF TOKEN IN.
|
||||
xdescribe('postItem', () => {
|
||||
const item = {
|
||||
type: 'comments',
|
||||
data: {body: 'stuff'}
|
||||
};
|
||||
|
||||
it ('should post an item, return an id, then dispatch that item to the store', () => {
|
||||
fetchMock.post('*', {id: '123'});
|
||||
return actions.postItem(item.data, item.type, undefined)(store.dispatch, store.getState)
|
||||
.then((id) => {
|
||||
expect(fetchMock.calls().matched[0][1]).to.deep.equal(
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type':'application/json'
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify(item.data)
|
||||
}
|
||||
);
|
||||
expect(id).to.deep.equal({id: '123'});
|
||||
expect(store.getActions()[0]).to.deep.equal({
|
||||
type: actions.ADD_ITEM,
|
||||
item: {
|
||||
body: 'stuff',
|
||||
id: '123'
|
||||
},
|
||||
item_type: 'comments',
|
||||
id: '123'
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should handle an error', () => {
|
||||
fetchMock.post('*', 404);
|
||||
return actions.postItem(item)(store.dispatch, store.getState)
|
||||
.catch((err) => {
|
||||
expect(err).to.be.truthy;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
xdescribe('postAction', () => {
|
||||
it ('should post an action', () => {
|
||||
fetchMock.post('*', {id: '456'});
|
||||
const action = {
|
||||
action_type: 'flag',
|
||||
detail: 'Comment smells funny'
|
||||
};
|
||||
return actions.postAction('abc', 'comments', action)(store.dispatch, store.getState)
|
||||
.then(response => {
|
||||
expect(fetchMock.calls().matched[0][0]).to.equal('/api/v1/comments/abc/actions');
|
||||
expect(response).to.deep.equal({id:'456'});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle an error', () => {
|
||||
fetchMock.post('*', 404);
|
||||
return actions.postAction('abc', 'flag', '123')(store.dispatch, store.getState)
|
||||
.catch((err) => {
|
||||
expect(err).to.be.truthy;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteAction', () => {
|
||||
it ('should remove an action', () => {
|
||||
fetchMock.delete('*', {});
|
||||
return actions.deleteAction('abc', 'flag', '123', 'comments')(store.dispatch)
|
||||
.then(response => {
|
||||
expect(fetchMock.calls().matched[0][0]).to.equal('/api/v1/actions/abc');
|
||||
expect(response).to.deep.equal({});
|
||||
});
|
||||
});
|
||||
|
||||
xit('should handle an error', () => {
|
||||
fetchMock.post('*', 404);
|
||||
return actions.postAction('abc', 'flag', '123')(store.dispatch, store.getState)
|
||||
.catch((err) => {
|
||||
expect(err).to.be.truthy;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
import {Map, fromJS} from 'immutable';
|
||||
import {expect} from 'chai';
|
||||
import itemsReducer from '../../../../client/coral-framework/reducers/items';
|
||||
|
||||
describe ('itemsReducer', () => {
|
||||
describe('ADD_ITEM', () => {
|
||||
it('should add an item', () => {
|
||||
const action = {
|
||||
type: 'ADD_ITEM',
|
||||
item: {
|
||||
body: 'stuff',
|
||||
id: '123'
|
||||
},
|
||||
item_type: 'comments',
|
||||
id: '123'
|
||||
};
|
||||
const store = new Map({});
|
||||
const result = itemsReducer(store, action);
|
||||
expect(result.getIn(['comments', '123']).toJS()).to.deep.equal({
|
||||
body: 'stuff',
|
||||
id: '123'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe ('UPDATE_ITEM', () => {
|
||||
it ('should update an item', () => {
|
||||
const action = {
|
||||
type: 'UPDATE_ITEM',
|
||||
property: 'stuff',
|
||||
value: 'things',
|
||||
item_type: 'comments',
|
||||
id: '123'
|
||||
};
|
||||
const store = fromJS({
|
||||
'comments': {
|
||||
'123': {
|
||||
id: '123',
|
||||
stuff: 'morestuff'
|
||||
}
|
||||
}
|
||||
});
|
||||
const result = itemsReducer(store, action);
|
||||
expect(result.getIn(['comments', '123']).toJS()).to.deep.equal({
|
||||
id: '123',
|
||||
stuff: 'things'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('APPEND_ITEM_ARRAY', () => {
|
||||
let action;
|
||||
let store;
|
||||
|
||||
beforeEach (() => {
|
||||
action = {
|
||||
type: 'APPEND_ITEM_ARRAY',
|
||||
property: 'stuff',
|
||||
value: 'things',
|
||||
id: '123',
|
||||
item_type: 'comments'
|
||||
};
|
||||
store = fromJS({
|
||||
'comments': {
|
||||
'123': {
|
||||
id: '123',
|
||||
stuff: ['morestuff']
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
it ('should append to an existing array', () => {
|
||||
const result = itemsReducer(store, action);
|
||||
expect(result.getIn(['comments', '123']).toJS()).to.deep.equal({
|
||||
id: '123',
|
||||
stuff: ['morestuff', 'things']
|
||||
});
|
||||
});
|
||||
it ('should create a new array', () => {
|
||||
store = fromJS({
|
||||
'comments': {
|
||||
'123': {
|
||||
id: '123'
|
||||
}
|
||||
}
|
||||
});
|
||||
const result = itemsReducer(store, action);
|
||||
expect(result.getIn(['comments', '123']).toJS()).to.deep.equal({
|
||||
id: '123',
|
||||
stuff: ['things']
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import {Map} from 'immutable';
|
||||
import {expect} from 'chai';
|
||||
import notificationReducer from '../../../../client/coral-framework/reducers/notification';
|
||||
import * as actions from '../../../../client/coral-framework/actions/notification';
|
||||
|
||||
describe ('notificationsReducer', () => {
|
||||
describe('ADD_NOTIFICATION', () => {
|
||||
it('should add a notification', () => {
|
||||
const action = {
|
||||
type: actions.ADD_NOTIFICATION,
|
||||
text: 'Test notification',
|
||||
notifType: 'test'
|
||||
};
|
||||
const store = new Map({});
|
||||
const result = notificationReducer(store, action);
|
||||
expect(result.get('text')).to.equal(action.text);
|
||||
expect(result.get('type')).to.equal(action.notifType);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CLEAR_NOTIFICATION', () => {
|
||||
it('should clear a notification', () => {
|
||||
const action = {
|
||||
type: actions.CLEAR_NOTIFICATION
|
||||
};
|
||||
const store = new Map({
|
||||
text: 'Test notification',
|
||||
type: 'test'
|
||||
});
|
||||
const result = notificationReducer(store, action);
|
||||
expect(result.get('text')).to.equal(undefined);
|
||||
expect(result.get('type')).to.equal(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import {shallow, mount} from 'enzyme';
|
||||
import {expect} from 'chai';
|
||||
import Comment from '../../../client/coral-plugin-history/Comment';
|
||||
|
||||
describe('coral-plugin-history/Comment', () => {
|
||||
let render;
|
||||
const comment = {body: 'this is a comment', id: '123'};
|
||||
const asset = {url: 'https://google.com'};
|
||||
|
||||
beforeEach(() => {
|
||||
render = shallow(<Comment asset={asset} comment={comment} link={()=>{}}/>);
|
||||
});
|
||||
|
||||
it('should render the provided comment body', () => {
|
||||
const wrapper = mount(<Comment asset={asset} comment={comment} link={()=>{}}/>);
|
||||
expect(wrapper.find('.myCommentBody')).to.have.length(1);
|
||||
expect(wrapper.find('.myCommentBody').text()).to.equal('this is a comment');
|
||||
});
|
||||
|
||||
it('should render the asset url as a link', () => {
|
||||
const wrapper = mount(<Comment asset={asset} comment={comment} link={()=>{}}/>);
|
||||
expect(wrapper.find('.myCommentAnchor')).to.have.length(1);
|
||||
expect(wrapper.find('.myCommentAnchor').text()).to.equal('https://google.com');
|
||||
});
|
||||
|
||||
it('should render the comment with styles', () => {
|
||||
expect(render.props().style).to.be.defined;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import {shallow, mount} from 'enzyme';
|
||||
import {expect} from 'chai';
|
||||
import CommentHistory from '../../../client/coral-plugin-history/CommentHistory';
|
||||
|
||||
describe('coral-plugin-history/CommentHistory', () => {
|
||||
let render;
|
||||
const comments = [{body: 'a comment or something', 'status_history':[{'type':'premod', 'created_at':'2016-12-09T01:40:53.327Z', 'assigned_by':null}, {'created_at':'2016-12-09T22:52:44.888Z', 'type':'accepted', 'assigned_by':'92256159-1164-4f66-9970-c7f23de7e461'}], 'asset_id':'96fddf96-7c83-4008-80ad-50091997d006', 'created_at':'2016-12-09T01:40:53.360Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':'accepted', '__v':0, 'updated_at':'2016-12-09T22:52:44.893Z', 'id':'3962c2ea-4ec4-42e4-b9bd-c571ff30f56b'}, {'body':'another comment', 'status_history':[{'type':'premod', 'created_at':'2016-12-09T22:53:43.148Z', 'assigned_by':null}], 'asset_id':'96fddf96-7c83-4008-80ad-50091997d006', 'created_at':'2016-12-09T22:53:43.158Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':'premod', '__v':0, 'updated_at':'2016-12-09T22:53:43.158Z', 'id':'b51e27af-bcfd-4932-91be-e3f01a4802e6'}, {'body':'can I comment?', 'status_history':[{'type':'premod', 'created_at':'2016-12-13T23:23:47.123Z', 'assigned_by':null}, {'created_at':'2016-12-13T23:23:58.487Z', 'type':'accepted', 'assigned_by':'92256159-1164-4f66-9970-c7f23de7e461'}], 'asset_id':'cef81015-1b53-4d70-b9af-6eca680f22fc', 'created_at':'2016-12-13T23:23:47.131Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':'accepted', '__v':0, 'updated_at':'2016-12-13T23:23:58.493Z', 'id':'dc9d7be1-b911-4dc3-8e1e-400e8b8d110e'}, {'body':'pre-mod comment', 'status_history':[{'type':'premod', 'created_at':'2016-12-08T21:34:56.994Z', 'assigned_by':null}, {'created_at':'2016-12-08T21:38:04.961Z', 'type':'rejected', 'assigned_by':'92256159-1164-4f66-9970-c7f23de7e461'}], 'asset_id':'96fddf96-7c83-4008-80ad-50091997d006', 'created_at':'2016-12-08T21:34:56.997Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':'rejected', '__v':0, 'updated_at':'2016-12-08T21:38:04.965Z', 'id':'6f02af16-a8f8-4ead-80ea-0d48824eb74d'}, {'body':'a flagged commetn', 'status_history':[{'type':'premod', 'created_at':'2016-12-08T21:38:26.342Z', 'assigned_by':null}, {'created_at':'2016-12-09T23:47:27.009Z', 'type':'accepted', 'assigned_by':'92256159-1164-4f66-9970-c7f23de7e461'}], 'asset_id':'96fddf96-7c83-4008-80ad-50091997d006', 'created_at':'2016-12-08T21:38:26.344Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':'accepted', '__v':0, 'updated_at':'2016-12-09T23:47:27.018Z', 'id':'784c5f91-36b9-4bda-b4ca-a114cef2c9f0'}, {'body':'a post mod comment', 'status_history':[{'type':'premod', 'created_at':'2016-12-08T22:19:05.870Z', 'assigned_by':null}, {'created_at':'2016-12-09T23:26:41.427Z', 'type':'accepted', 'assigned_by':'92256159-1164-4f66-9970-c7f23de7e461'}], 'asset_id':'96fddf96-7c83-4008-80ad-50091997d006', 'created_at':'2016-12-08T22:19:05.874Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':'accepted', '__v':0, 'updated_at':'2016-12-09T23:26:41.450Z', 'id':'e8b86039-f850-4e53-bd9d-f8c9186a9637'}, {'body':'an actual post-mod comment here', 'status_history':[], 'asset_id':'96fddf96-7c83-4008-80ad-50091997d006', 'created_at':'2016-12-08T22:20:11.147Z', 'author_id':'92256159-1164-4f66-9970-c7f23de7e461', 'status':null, '__v':0, 'updated_at':'2016-12-08T22:20:11.147Z', 'id':'cff1a318-50c6-431e-9a63-de7a7b7136bf'}];
|
||||
const assets = [{'settings': null, 'created_at':'2016-12-06T21:36:09.302Z', 'url':'localhost:3000/', 'scraped':null, 'status':'open', 'updated_at':'2016-12-08T02:11:15.943Z', '_id':'58472f499e775a38f23d5da0', 'type':'article', 'closedMessage':null, 'id':'7302e637-f884-47c0-9723-02cc10a18617', 'closedAt':null}, {'settings':null, 'created_at':'2016-12-07T02:25:31.983Z', 'url':'http://localhost:3000/', 'scraped':null, 'status':'open', 'updated_at':'2016-12-13T22:58:36.061Z', '_id':'5847731b9e775a38f23d5da1', 'type':'article', 'closedMessage':null, 'id':'96fddf96-7c83-4008-80ad-50091997d006', 'closedAt':null}, {'settings':null, 'created_at':'2016-12-12T19:04:05.770Z', 'url':'http://localhost:3000/embed/stream', 'scraped':null, 'updated_at':'2016-12-14T20:13:21.934Z', '_id':'584ef4a59e775a38f23d5e86', 'type':'article', 'closedMessage':null, 'id':'cef81015-1b53-4d70-b9af-6eca680f22fc', 'closedAt':null}];
|
||||
|
||||
beforeEach(() => {
|
||||
render = shallow(<CommentHistory comments={comments} assets={assets} link={()=>{}}/>);
|
||||
});
|
||||
|
||||
it('should render Comments as children when given comments and assets', () => {
|
||||
const wrapper = mount(<CommentHistory comments={comments} assets={assets} link={()=>{}}/>);
|
||||
expect(wrapper.find('.commentHistory__list').children()).to.have.length(7);
|
||||
});
|
||||
|
||||
it('should render with styles', () => {
|
||||
expect(render.props().style).to.be.defined;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
waitForConditionTimeout: 8000,
|
||||
baseUrl: 'http://localhost:3000',
|
||||
users: {
|
||||
admin: {
|
||||
email: 'admin@test.com',
|
||||
pass: 'testtest'
|
||||
},
|
||||
moderator: {
|
||||
email: 'moderator@test.com',
|
||||
pass: 'testtest'
|
||||
},
|
||||
commenter: {
|
||||
email: 'commenter@test.com',
|
||||
pass: 'testtest'
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
const Comments = require('../../models/comment');
|
||||
const Users = require('../../models/user');
|
||||
const Actions = require('../../models/action');
|
||||
const Assets = require('../../models/asset');
|
||||
const Settings = require('../../models/setting');
|
||||
const globals = require('./globals');
|
||||
|
||||
/* Create an array of comments */
|
||||
module.exports.comments = (comments) => Assets.findOrCreateByUrl(globals.baseUrl)
|
||||
.then((asset) => {
|
||||
comments = comments.map((comment) => {
|
||||
comment.asset_id = asset.id;
|
||||
return comment;
|
||||
});
|
||||
return Comments.create(comments);
|
||||
});
|
||||
|
||||
/* Create an array of users */
|
||||
module.exports.users = (users) => Users.createLocalUsers(users);
|
||||
|
||||
/* Create an array of actions */
|
||||
module.exports.actions = (actions) => Actions.create(actions);
|
||||
|
||||
/* Update a setting */
|
||||
module.exports.settings = (setting) => Settings.init().then(() => Settings.updateSettings(setting));
|
||||
@@ -0,0 +1,33 @@
|
||||
const embedStreamCommands = {
|
||||
url: function () {
|
||||
return `${this.api.launchUrl}/admin`;
|
||||
},
|
||||
ready() {
|
||||
return this
|
||||
.waitForElementVisible('body', 2000);
|
||||
},
|
||||
approveComment() {
|
||||
return this
|
||||
.waitForElementVisible('@commentList')
|
||||
.waitForElementVisible('@approveButton')
|
||||
.click('@approveButton');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
commands: [embedStreamCommands],
|
||||
elements: {
|
||||
commentList: {
|
||||
selector: '#commentList'
|
||||
},
|
||||
banButton: {
|
||||
selector: '#commentList .actions:first-child .ban'
|
||||
},
|
||||
rejectButton: {
|
||||
selector: '#commentList .actions:first-child .reject'
|
||||
},
|
||||
approveButton: {
|
||||
selector: '#commentList .actions:first-child .approve'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
const embedStreamCommands = {
|
||||
url: function () {
|
||||
return this
|
||||
.api.launchUrl;
|
||||
},
|
||||
ready() {
|
||||
return this
|
||||
.waitForElementVisible('body', 4000)
|
||||
.waitForElementVisible('iframe#coralStreamIframe')
|
||||
.api.frame('coralStreamIframe');
|
||||
},
|
||||
signUp(user) {
|
||||
return this
|
||||
.waitForElementVisible('@signInButton', 2000)
|
||||
.click('@signInButton')
|
||||
.waitForElementVisible('@signInDialog')
|
||||
.waitForElementVisible('@registerButton')
|
||||
.click('@registerButton')
|
||||
.setValue('@signInDialogEmail', user.email)
|
||||
.setValue('@signInDialogPassword', user.pass)
|
||||
.setValue('@signUpDialogConfirmPassword', user.pass)
|
||||
.setValue('@signUpDialogDisplayName', user.displayName)
|
||||
.waitForElementVisible('@signUpButton')
|
||||
.click('@signUpButton')
|
||||
.waitForElementVisible('@logInButton')
|
||||
.click('@logInButton')
|
||||
.waitForElementVisible('@logoutButton', 5000);
|
||||
},
|
||||
login(user) {
|
||||
return this
|
||||
.waitForElementVisible('@signInButton', 2000)
|
||||
.click('@signInButton')
|
||||
.waitForElementVisible('@signInDialog')
|
||||
.waitForElementVisible('@signInDialogEmail')
|
||||
.waitForElementVisible('@signInDialogPassword')
|
||||
.setValue('@signInDialogEmail', user.email)
|
||||
.setValue('@signInDialogPassword', user.pass)
|
||||
.waitForElementVisible('@logInButton')
|
||||
.click('@logInButton')
|
||||
.waitForElementVisible('@logoutButton', 5000);
|
||||
},
|
||||
logout() {
|
||||
return this
|
||||
.waitForElementVisible('@logoutButton')
|
||||
.click('@logoutButton')
|
||||
.waitForElementVisible('@signInButton', 2000);
|
||||
},
|
||||
postComment(comment = 'Test Comment') {
|
||||
return this
|
||||
.waitForElementVisible('@commentBox', 2000)
|
||||
.setValue('@commentBox', comment)
|
||||
.click('@postButton');
|
||||
},
|
||||
likeComment() {
|
||||
return this
|
||||
.waitForElementVisible('@likeButton')
|
||||
.click('@likeButton');
|
||||
},
|
||||
flagComment() {
|
||||
return this
|
||||
.waitForElementVisible('@flagButton')
|
||||
.click('@flagButton');
|
||||
},
|
||||
flagUsername() {
|
||||
return this
|
||||
.waitForElementVisible('@flagButton')
|
||||
.click('@flagButton');
|
||||
},
|
||||
getPermalink(fn) {
|
||||
return this
|
||||
.waitForElementVisible('@permalinkButton')
|
||||
.click('@permalinkButton')
|
||||
.waitForElementVisible('@permalinkPopUp')
|
||||
.getValue('@permalinkInput', result => fn(result.value));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
commands: [embedStreamCommands],
|
||||
elements: {
|
||||
signInButton: {
|
||||
selector: '#coralSignInButton'
|
||||
},
|
||||
signInDialog:{
|
||||
selector: '#signInDialog'
|
||||
},
|
||||
signInDialogEmail: {
|
||||
selector: '#signInDialog #email'
|
||||
},
|
||||
signInDialogPassword: {
|
||||
selector: '#signInDialog #password'
|
||||
},
|
||||
signUpDialogConfirmPassword: {
|
||||
selector: '#signInDialog #confirmPassword'
|
||||
},
|
||||
signUpDialogDisplayName: {
|
||||
selector: '#signInDialog #displayName'
|
||||
},
|
||||
logInButton: {
|
||||
selector: '#coralLogInButton'
|
||||
},
|
||||
signUpButton: {
|
||||
selector: '#coralSignUpButton'
|
||||
},
|
||||
logoutButton: {
|
||||
selector: '.commentStream #logout'
|
||||
},
|
||||
commentBox: {
|
||||
selector: '.coral-plugin-commentbox-textarea'
|
||||
},
|
||||
postButton: {
|
||||
selector: '#commentBox .coral-plugin-commentbox-button'
|
||||
},
|
||||
likeButton: {
|
||||
selector: '.comment .coral-plugin-likes-container .coral-plugin-likes-button'
|
||||
},
|
||||
likeText: {
|
||||
selector: '.comment .coral-plugin-likes-container .coral-plugin-likes-button .coral-plugin-likes-button-text'
|
||||
},
|
||||
likesCount: {
|
||||
selector: '.comment .coral-plugin-likes-container .coral-plugin-likes-button .coral-plugin-likes-like-count'
|
||||
},
|
||||
flagButton: {
|
||||
selector: '.comment .coral-plugin-flags-container .coral-plugin-flags-button'
|
||||
},
|
||||
flagPopUp: {
|
||||
selector: '.comment .coral-plugin-flags-popup'
|
||||
},
|
||||
flagCommentOption: {
|
||||
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-radio-label[for="comments"]'
|
||||
},
|
||||
flagUsernameOption: {
|
||||
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-radio-label[for="user"]'
|
||||
},
|
||||
flagOtherOption: {
|
||||
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-radio-label[for="other"]'
|
||||
},
|
||||
flagHeaderMessage: {
|
||||
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-header'
|
||||
},
|
||||
flagButtonText: {
|
||||
selector: '.comment .coral-plugin-flags-button-text'
|
||||
},
|
||||
flagDoneButton: {
|
||||
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-button'
|
||||
},
|
||||
permalinkButton: {
|
||||
selector: '.comment .coral-plugin-permalinks-button'
|
||||
},
|
||||
permalinkPopUp: {
|
||||
selector: '.comment .coral-plugin-permalinks-popover.active'
|
||||
},
|
||||
permalinkInput: {
|
||||
selector: '.comment .coral-plugin-permalinks-popover.active input'
|
||||
},
|
||||
registerButton: {
|
||||
selector: '#signInDialog #coralRegister'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
'@tags': ['app'],
|
||||
'Base url and Hostname': browser => {
|
||||
const {baseUrl} = browser.globals;
|
||||
browser
|
||||
.url(baseUrl)
|
||||
.assert.title('Coral Talk')
|
||||
.waitForElementPresent('body', 1000);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
module.exports = {
|
||||
'@tags': ['embedStream'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
},
|
||||
'Login as commenter': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
'Add test comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
embedStreamPage
|
||||
.postComment('Test Comment');
|
||||
},
|
||||
'Logout': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
embedStreamPage
|
||||
.logout();
|
||||
},
|
||||
'Login as admin': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
embedStreamPage
|
||||
.login(users.admin);
|
||||
},
|
||||
'Approve test comment': client => {
|
||||
const adminPage = client.page.adminPage();
|
||||
|
||||
adminPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
adminPage
|
||||
.approveComment();
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
'@tags': ['login', 'ADMIN'],
|
||||
before(client) {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {launchUrl} = client;
|
||||
|
||||
client
|
||||
.url(launchUrl);
|
||||
|
||||
embedStreamPage
|
||||
.ready();
|
||||
},
|
||||
'Admin logs in': client => {
|
||||
const {users} = client.globals;
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.admin);
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
module.exports = {
|
||||
'@tags': ['flag', 'comments', 'commenter'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
'Commenter flags a comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.flagComment()
|
||||
.waitForElementVisible('@flagPopUp')
|
||||
.waitForElementVisible('@flagCommentOption')
|
||||
.click('@flagCommentOption')
|
||||
.waitForElementVisible('@flagDoneButton')
|
||||
.click('@flagDoneButton')
|
||||
.waitForElementVisible('@flagOtherOption')
|
||||
.click('@flagOtherOption')
|
||||
.waitForElementVisible('@flagDoneButton')
|
||||
.click('@flagDoneButton')
|
||||
.click('@flagDoneButton')
|
||||
.expect.element('@flagButtonText').text.to.equal('Reported');
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
module.exports = {
|
||||
'@tags': ['flag', 'commenter'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
'Commenter flags a username': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.flagUsername()
|
||||
.waitForElementVisible('@flagPopUp')
|
||||
.waitForElementVisible('@flagUsernameOption')
|
||||
.click('@flagUsernameOption')
|
||||
.waitForElementVisible('@flagDoneButton')
|
||||
.click('@flagDoneButton')
|
||||
.waitForElementVisible('@flagOtherOption')
|
||||
.click('@flagOtherOption')
|
||||
.waitForElementVisible('@flagDoneButton')
|
||||
.click('@flagDoneButton')
|
||||
.click('@flagDoneButton');
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
'@tags': ['like', 'comments', 'commenter'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
'Commenter likes a comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.likeComment()
|
||||
.waitForElementVisible('@likesCount', 2000)
|
||||
.expect.element('@likeText').text.to.equal('Liked');
|
||||
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
'@tags': ['login', 'commenter'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
},
|
||||
'Commenter logs in': client => {
|
||||
const {users} = client.globals;
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
let permalink = '';
|
||||
|
||||
module.exports = {
|
||||
'@tags': ['permalink', 'commenter'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
'Commenter gets the permalink of a comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
embedStreamPage
|
||||
.getPermalink(value => {
|
||||
permalink = value;
|
||||
});
|
||||
},
|
||||
'Commenter navigates to the permalink': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
embedStreamPage
|
||||
.navigate(permalink);
|
||||
|
||||
client.assert.urlContains(permalink);
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
module.exports = {
|
||||
'@tags': ['write', 'commenter'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.commenter);
|
||||
},
|
||||
'Commenter posts a comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.postComment('I read the comments');
|
||||
},
|
||||
after: client => {
|
||||
const adminPage = client.page.adminPage();
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {users} = client.globals;
|
||||
|
||||
embedStreamPage
|
||||
.logout()
|
||||
.login(users.admin);
|
||||
|
||||
adminPage
|
||||
.navigate()
|
||||
.ready();
|
||||
|
||||
adminPage
|
||||
.approveComment();
|
||||
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,185 @@
|
||||
const mongoose = require('../../helpers/mongoose');
|
||||
const mocks = require('../mocks');
|
||||
|
||||
const mockComment = 'This is a test comment.';
|
||||
const mockReply = 'This is a test reply';
|
||||
const mockUser = {
|
||||
email: `${new Date().getTime()}@test.com`,
|
||||
name: 'testuser',
|
||||
pw: 'testtest'
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
'@tags': ['embed-stream', 'comment', 'premodoff', 'premodon'],
|
||||
before: () => {
|
||||
mongoose.waitTillConnect(function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
},
|
||||
'User registers and posts a comment with premod off': client => {
|
||||
client.perform((client, done) => {
|
||||
mocks.settings({moderation: 'POST'})
|
||||
.then(() => {
|
||||
|
||||
// Load Page
|
||||
client.resizeWindow(1200, 800)
|
||||
.url(client.globals.baseUrl)
|
||||
.frame('coralStreamIframe')
|
||||
|
||||
// Register and Log In
|
||||
.waitForElementVisible('#commentBox', 1000)
|
||||
.waitForElementVisible('#coralSignInButton', 2000)
|
||||
.click('#coralSignInButton')
|
||||
.waitForElementVisible('#coralRegister', 1000)
|
||||
.click('#coralRegister')
|
||||
.waitForElementVisible('#email', 1000)
|
||||
.setValue('#email', mockUser.email)
|
||||
.setValue('#displayName', mockUser.name)
|
||||
.setValue('#password', mockUser.pw)
|
||||
.setValue('#confirmPassword', mockUser.pw)
|
||||
.click('#coralSignUpButton')
|
||||
.waitForElementVisible('#coralLogInButton', 10000)
|
||||
.click('#coralLogInButton')
|
||||
.waitForElementVisible('.coral-plugin-commentbox-button', 4000)
|
||||
|
||||
// Post a comment
|
||||
.setValue('.coral-plugin-commentbox-textarea', mockComment)
|
||||
.click('.coral-plugin-commentbox-button')
|
||||
.waitForElementVisible('.comment', 1000)
|
||||
|
||||
// Verify that it appears
|
||||
.assert.containsText('.comment', mockComment);
|
||||
done();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
'User posts a comment with premod on': client => {
|
||||
client.perform((client, done) => {
|
||||
mocks.settings({moderation: 'PRE'})
|
||||
.then(() => {
|
||||
|
||||
// Load Page
|
||||
client.url(client.globals.baseUrl)
|
||||
.frame('coralStreamIframe');
|
||||
|
||||
// Post a comment
|
||||
client.waitForElementVisible('.coral-plugin-commentbox-button', 2000)
|
||||
.setValue('.coral-plugin-commentbox-textarea', mockComment)
|
||||
.click('.coral-plugin-commentbox-button')
|
||||
.waitForElementVisible('#coral-notif', 1000)
|
||||
|
||||
// Verify that it appears
|
||||
.assert.containsText('#coral-notif', 'moderation team');
|
||||
done();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
'User replies to a comment with premod off': client => {
|
||||
client.perform((client, done) => {
|
||||
mocks.settings({moderation: 'POST'})
|
||||
.then(() => {
|
||||
|
||||
// Load Page
|
||||
client.resizeWindow(1200, 800)
|
||||
.url(client.globals.baseUrl)
|
||||
.frame('coralStreamIframe');
|
||||
|
||||
// Post a comment
|
||||
client.waitForElementVisible('.coral-plugin-commentbox-button', 2000)
|
||||
.setValue('.coral-plugin-commentbox-textarea', mockComment)
|
||||
.click('.coral-plugin-commentbox-button')
|
||||
|
||||
// Post a reply
|
||||
.waitForElementVisible('.coral-plugin-replies-reply-button', 5000)
|
||||
.click('.coral-plugin-replies-reply-button')
|
||||
.waitForElementVisible('#replyText')
|
||||
.setValue('#replyText', mockReply)
|
||||
.click('.coral-plugin-replies-textarea button')
|
||||
.waitForElementVisible('.reply', 2000)
|
||||
|
||||
// Verify that it appears
|
||||
.assert.containsText('.reply', mockReply);
|
||||
done();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
'User replies to a comment with premod on': client => {
|
||||
client.perform((client, done) => {
|
||||
mocks.settings({moderation: 'PRE'})
|
||||
|
||||
// Add a mock user
|
||||
.then(() => {
|
||||
return mocks.users([{
|
||||
displayName: 'Baby Blue',
|
||||
email: 'whale@tale.sea',
|
||||
password: 'krill'
|
||||
}]);
|
||||
})
|
||||
|
||||
// Add a mock preapproved comment by that user
|
||||
.then((user) => {
|
||||
return mocks.comments([{
|
||||
body: 'Whales are not fish.',
|
||||
status: 'accepted',
|
||||
author_id: user.id
|
||||
}]);
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
// Load Page
|
||||
client.resizeWindow(1200, 800)
|
||||
.url(client.globals.baseUrl)
|
||||
.frame('coralStreamIframe');
|
||||
|
||||
// Post a reply
|
||||
client.waitForElementVisible('.coral-plugin-replies-reply-button', 5000)
|
||||
.click('.coral-plugin-replies-reply-button')
|
||||
.waitForElementVisible('#replyText')
|
||||
.setValue('#replyText', mockReply)
|
||||
.click('.coral-plugin-replies-textarea button')
|
||||
.waitForElementVisible('#coral-notif', 1000)
|
||||
|
||||
// Verify that it appears
|
||||
.assert.containsText('#coral-notif', 'moderation team');
|
||||
done();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
'Total comment count premod on': client => {
|
||||
client.perform((client, done) => {
|
||||
client.url(client.globals.baseUrl)
|
||||
.frame('coralStreamIframe');
|
||||
|
||||
// Verify that comment count is correct
|
||||
client.waitForElementVisible('.coral-plugin-comment-count-text', 2000)
|
||||
.assert.containsText('.coral-plugin-comment-count-text', '1 Comment');
|
||||
done();
|
||||
});
|
||||
},
|
||||
after: client => {
|
||||
mongoose.disconnect(function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
'@tags': ['login', 'MODERATOR'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
const {launchUrl} = client;
|
||||
|
||||
client
|
||||
.url(launchUrl);
|
||||
|
||||
embedStreamPage
|
||||
.ready();
|
||||
},
|
||||
'Moderator logs in': client => {
|
||||
const {users} = client.globals;
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.login(users.moderator);
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
'@tags': ['flag', 'comments', 'visitor'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
},
|
||||
'Visitor tries to flag a comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.flagComment()
|
||||
.waitForElementVisible('@signInDialog', 2000);
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
'@tags': ['like', 'comments', 'visitor'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
},
|
||||
'Visitor tries to like a comment': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.likeComment()
|
||||
.waitForElementVisible('@signInDialog', 2000);
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
'@tags': ['signup', 'visitor'],
|
||||
before: client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.navigate()
|
||||
.ready();
|
||||
},
|
||||
'Visitor signs up': client => {
|
||||
const embedStreamPage = client.page.embedStreamPage();
|
||||
|
||||
embedStreamPage
|
||||
.signUp({
|
||||
email: `visitor_${Date.now()}@test.com`,
|
||||
displayName: 'visitor',
|
||||
pass: 'testtest'
|
||||
});
|
||||
},
|
||||
after: client => {
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/* eslint-env browser */
|
||||
|
||||
const jsdom = require('jsdom').jsdom;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Storage Mock
|
||||
function storageMock() {
|
||||
const storage = {};
|
||||
|
||||
return {
|
||||
setItem: function(key, value) {
|
||||
storage[key] = value || '';
|
||||
},
|
||||
getItem: function(key) {
|
||||
return storage[key] || null;
|
||||
},
|
||||
removeItem: function(key) {
|
||||
delete storage[key];
|
||||
},
|
||||
get length() {
|
||||
return Object.keys(storage).length;
|
||||
},
|
||||
key: function(i) {
|
||||
const keys = Object.keys(storage);
|
||||
return keys[i] || null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
global.document = jsdom(fs.readFileSync(path.resolve(__dirname, 'index.test.html')));
|
||||
global.window = document.defaultView;
|
||||
|
||||
// these lines are required for react-mdl
|
||||
global.window.CustomEvent = undefined;
|
||||
require('react-mdl/extra/material');
|
||||
|
||||
global.Element = global.window.Element;
|
||||
|
||||
global.navigator = {
|
||||
userAgent: 'node.js'
|
||||
};
|
||||
|
||||
global.documentRef = document;
|
||||
global.localStorage = {};
|
||||
global.sessionStorage = storageMock();
|
||||
global.XMLHttpRequest = storageMock();
|
||||
|
||||
global.Headers = function(headers) {
|
||||
return headers;
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,38 @@
|
||||
const mongoose = require('../../services/mongoose');
|
||||
|
||||
module.exports = {};
|
||||
|
||||
module.exports.waitTillConnect = function(done) {
|
||||
mongoose.connection.on('open', function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
return done();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.clearDB = function(done) {
|
||||
Promise.all(Object.keys(mongoose.connection.collections).map((collection) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
mongoose.connection.collections[collection].remove(function(err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}))
|
||||
.then(() => {
|
||||
done();
|
||||
})
|
||||
.catch((err) => {
|
||||
done(err);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.disconnect = function(done) {
|
||||
mongoose.disconnect();
|
||||
return done();
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
const kue = require('../services/kue');
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
// Empty the test tasks before finishing.
|
||||
kue.TestQueue.splice(0, kue.TestQueue.length);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
test/helpers/*.js
|
||||
test
|
||||
--compilers js:babel-core/register
|
||||
--require ignore-styles
|
||||
--recursive
|
||||
--colors
|
||||
--sort
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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;
|
||||
@@ -0,0 +1,148 @@
|
||||
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');
|
||||
|
||||
describe('/api/v1/assets', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
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('displayName', '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.init({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) => {
|
||||
err.response.should.have.status(401);
|
||||
|
||||
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('displayName', 'maria');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,345 @@
|
||||
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 CommentModel = require('../../../../models/comment');
|
||||
const ActionModel = require('../../../../models/action');
|
||||
|
||||
const CommentsService = require('../../../../services/comments');
|
||||
const UsersService = require('../../../../services/users');
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
|
||||
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
|
||||
|
||||
describe('/api/v1/comments', () => {
|
||||
|
||||
// Ensure that the settings are always available.
|
||||
beforeEach(() => SettingsService.init(settings));
|
||||
|
||||
describe('#get', () => {
|
||||
const comments = [{
|
||||
body: 'comment 10',
|
||||
asset_id: 'asset',
|
||||
author_id: '123'
|
||||
}, {
|
||||
body: 'comment 20',
|
||||
asset_id: 'asset',
|
||||
author_id: '456'
|
||||
}, {
|
||||
body: 'comment 20',
|
||||
asset_id: 'asset',
|
||||
author_id: '456',
|
||||
status: 'REJECTED',
|
||||
status_history: [{
|
||||
type: 'REJECTED'
|
||||
}]
|
||||
}, {
|
||||
body: 'comment 30',
|
||||
asset_id: '456',
|
||||
status: 'ACCEPTED',
|
||||
status_history: [{
|
||||
type: 'ACCEPTED'
|
||||
}]
|
||||
}];
|
||||
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
email: 'ana@gmail.com',
|
||||
password: '123456789'
|
||||
}, {
|
||||
displayName: 'Maria',
|
||||
email: 'maria@gmail.com',
|
||||
password: '123456789'
|
||||
}];
|
||||
|
||||
const actions = [{
|
||||
action_type: 'FLAG',
|
||||
item_id: 'abc',
|
||||
item_type: 'COMMENTS'
|
||||
}, {
|
||||
action_type: 'LIKE',
|
||||
item_id: 'hij',
|
||||
item_type: 'COMMENTS'
|
||||
}];
|
||||
|
||||
beforeEach(() => {
|
||||
return Promise.all([
|
||||
CommentModel.create(comments).then((newComments) => {
|
||||
newComments.forEach((comment, i) => {
|
||||
comments[i].id = comment.id;
|
||||
});
|
||||
|
||||
actions[0].item_id = comments[0].id;
|
||||
actions[1].item_id = comments[1].id;
|
||||
|
||||
return ActionModel.create(actions);
|
||||
}),
|
||||
UsersService.createLocalUsers(users)
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return only the owner’s published comments if the user is not an admin', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments?user_id=456')
|
||||
.set(passport.inject({id: '456', roles: []}))
|
||||
.then(res => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res.body.comments).to.have.length(1);
|
||||
expect(res.body.comments[0]).to.have.property('author_id', '456');
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail if a non-admin requests comments not owned by them', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments?user_id=456')
|
||||
.set(passport.inject({id: '123', roles: []}))
|
||||
.then((res) => {
|
||||
expect(res).to.be.empty;
|
||||
})
|
||||
.catch((err) => {
|
||||
expect(err).to.have.status(401);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return all the comments', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
|
||||
expect(res).to.have.status(200);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('should return all the rejected comments', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments?status=REJECTED')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res.body).to.have.property('comments');
|
||||
expect(res.body.comments).to.have.length(1);
|
||||
expect(res.body.comments[0]).to.have.property('id', comments[2].id);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return all the approved comments', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments?status=ACCEPTED')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res.body.comments).to.have.length(1);
|
||||
expect(res.body.comments[0]).to.have.property('id', comments[3].id);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return all the new comments', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments?status=NEW')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res.body.comments).to.have.length(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return all the flagged comments', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments?action_type=FLAG')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
|
||||
expect(res.body.comments).to.have.length(1);
|
||||
expect(res.body.comments[0]).to.have.property('id', comments[0].id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/api/v1/comments/:comment_id', () => {
|
||||
const comments = [{
|
||||
id: 'abc',
|
||||
body: 'comment 10',
|
||||
asset_id: 'asset',
|
||||
author_id: '123'
|
||||
}, {
|
||||
id: 'def',
|
||||
body: 'comment 20',
|
||||
asset_id: 'asset',
|
||||
author_id: '456'
|
||||
}, {
|
||||
id: 'hij',
|
||||
body: 'comment 30',
|
||||
asset_id: '456'
|
||||
}];
|
||||
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
email: 'ana@gmail.com',
|
||||
password: '123456789'
|
||||
}, {
|
||||
displayName: 'Maria',
|
||||
email: 'maria@gmail.com',
|
||||
password: '123456789'
|
||||
}];
|
||||
|
||||
const actions = [{
|
||||
action_type: 'FLAG',
|
||||
item_id: 'abc',
|
||||
item_type: 'COMMENTS'
|
||||
}, {
|
||||
action_type: 'LIKE',
|
||||
item_id: 'hij',
|
||||
item_type: 'COMMENTS'
|
||||
}];
|
||||
|
||||
beforeEach(() => {
|
||||
return SettingsService.init(settings).then(() => {
|
||||
return Promise.all([
|
||||
CommentModel.create(comments),
|
||||
UsersService.createLocalUsers(users),
|
||||
ActionModel.create(actions)
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#get', () => {
|
||||
|
||||
it('should return the right comment for the comment_id', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/comments/abc')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res).to.have.property('body');
|
||||
expect(res.body).to.have.property('body', 'comment 10');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#delete', () => {
|
||||
it('it should remove comment', () => {
|
||||
return chai.request(app)
|
||||
.delete('/api/v1/comments/abc')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
return CommentsService.findById('abc');
|
||||
})
|
||||
.then((comment) => {
|
||||
expect(comment).to.be.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#put', () => {
|
||||
it('it should update status', function() {
|
||||
return chai.request(app)
|
||||
.put('/api/v1/comments/abc/status')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.send({status: 'accepted'})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
expect(res.body).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
it('it should not allow a non-ADMIN to update status', () => {
|
||||
return chai.request(app)
|
||||
.put('/api/v1/comments/abc/status')
|
||||
.set(passport.inject({roles: []}))
|
||||
.send({status: 'accepted'})
|
||||
.then((res) => {
|
||||
expect(res).to.be.empty;
|
||||
})
|
||||
.catch((err) => {
|
||||
expect(err).to.have.property('status', 401);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/api/v1/comments/:comment_id/actions', () => {
|
||||
|
||||
const comments = [{
|
||||
id: 'abc',
|
||||
body: 'comment 10',
|
||||
asset_id: 'asset',
|
||||
author_id: '123',
|
||||
status_history: []
|
||||
}, {
|
||||
id: 'def',
|
||||
body: 'comment 20',
|
||||
asset_id: 'asset',
|
||||
author_id: '456',
|
||||
status: 'REJECTED',
|
||||
status_history: [{
|
||||
type: 'REJECTED'
|
||||
}]
|
||||
}, {
|
||||
id: 'hij',
|
||||
body: 'comment 30',
|
||||
asset_id: '456',
|
||||
status: 'ACCEPTED',
|
||||
status_history: [{
|
||||
type: 'ACCEPTED'
|
||||
}]
|
||||
}];
|
||||
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
email: 'ana@gmail.com',
|
||||
password: '123456789'
|
||||
}, {
|
||||
displayName: 'Maria',
|
||||
email: 'maria@gmail.com',
|
||||
password: '123456789'
|
||||
}];
|
||||
|
||||
const actions = [{
|
||||
action_type: 'FLAG',
|
||||
item_type: 'COMMENTS',
|
||||
item_id: 'abc'
|
||||
}, {
|
||||
action_type: 'LIKE',
|
||||
item_type: 'COMMENTS',
|
||||
item_id: 'hij'
|
||||
}];
|
||||
|
||||
beforeEach(() => {
|
||||
return SettingsService.init(settings).then(() => {
|
||||
return Promise.all([
|
||||
CommentModel.create(comments),
|
||||
UsersService.createLocalUsers(users),
|
||||
ActionModel.create(actions)
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#post', () => {
|
||||
it('it should create an action', () => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/comments/abc/actions')
|
||||
.set(passport.inject({id: '456', roles: ['ADMIN']}))
|
||||
.send({'action_type': 'flag', 'metadata': {'reason': 'Comment 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('metadata');
|
||||
expect(res.body.metadata).to.deep.equal({'reason': 'Comment is too awesome.'});
|
||||
expect(res.body).to.have.property('item_id', 'abc');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
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 Comment = require('../../../../models/comment');
|
||||
const Action = require('../../../../models/action');
|
||||
const UsersService = require('../../../../services/users');
|
||||
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['banned'], suspect: ['suspect']}};
|
||||
|
||||
describe('/api/v1/queue', () => {
|
||||
const comments = [{
|
||||
id: 'abc',
|
||||
body: 'comment 10',
|
||||
asset_id: 'asset',
|
||||
author_id: '123',
|
||||
status: 'REJECTED',
|
||||
status_history: [{
|
||||
type: 'REJECTED'
|
||||
}]
|
||||
}, {
|
||||
id: 'def',
|
||||
body: 'comment 20',
|
||||
asset_id: 'asset',
|
||||
author_id: '456',
|
||||
status: 'PREMOD',
|
||||
status_history: [{
|
||||
type: 'PREMOD'
|
||||
}]
|
||||
}, {
|
||||
id: 'hij',
|
||||
body: 'comment 30',
|
||||
asset_id: '456',
|
||||
status: 'ACCEPTED',
|
||||
status_history: [{
|
||||
type: 'ACCEPTED'
|
||||
}]
|
||||
}];
|
||||
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
email: 'ana@gmail.com',
|
||||
password: '123456789'
|
||||
}, {
|
||||
displayName: 'Maria',
|
||||
email: 'maria@gmail.com',
|
||||
password: '123456789'
|
||||
}];
|
||||
|
||||
const actions = [{
|
||||
action_type: 'FLAG',
|
||||
item_id: 'abc',
|
||||
item_type: 'COMMENTS'
|
||||
}, {
|
||||
action_type: 'LIKE',
|
||||
item_id: 'hij',
|
||||
item_type: 'COMMENTS'
|
||||
}];
|
||||
|
||||
beforeEach(() => {
|
||||
return SettingsService.init(settings).then(() => {
|
||||
return UsersService.createLocalUsers(users)
|
||||
.then((u) => {
|
||||
comments[0].author_id = u[0].id;
|
||||
comments[1].author_id = u[1].id;
|
||||
comments[2].author_id = u[1].id;
|
||||
|
||||
return Comment.create(comments);
|
||||
})
|
||||
.then((c) => {
|
||||
actions[0].item_id = c[0].id;
|
||||
actions[1].item_id = c[1].id;
|
||||
|
||||
return Promise.all([
|
||||
Action.create(actions),
|
||||
SettingsService.init(settings)
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return all the pending comments, users and actions', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/queue/comments/pending')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res.body.comments).to.have.length(1);
|
||||
expect(res.body.comments[0]).to.have.property('body');
|
||||
expect(res.body.users[0]).to.have.property('displayName');
|
||||
expect(res.body.actions[0]).to.have.property('action_type');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
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', () => {
|
||||
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
email: 'ana@gmail.com',
|
||||
password: '123456789'
|
||||
}, {
|
||||
displayName: 'Maria',
|
||||
email: 'maria@gmail.com',
|
||||
password: '123456789'
|
||||
}];
|
||||
|
||||
beforeEach(() => {
|
||||
return SettingsService.init(settings).then(() => {
|
||||
return UsersService.createLocalUsers(users);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#post', () => {
|
||||
it('it should update actions', () => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/users/abc/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('metadata')
|
||||
.and.to.deep.equal({'reason': 'Bio is too awesome.'});
|
||||
expect(res.body).to.have.property('item_id', 'abc');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
const AssetModel = require('../../models/asset');
|
||||
const AssetsService = require('../../services/assets');
|
||||
|
||||
const chai = require('chai');
|
||||
const expect = chai.expect;
|
||||
|
||||
// Use the chai should.
|
||||
chai.should();
|
||||
|
||||
describe('services.AssetsService', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const defaults = {url:'http://test.com'};
|
||||
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', () => {
|
||||
return AssetsService
|
||||
.findOrCreateByUrl('http://new.test.com')
|
||||
.then((asset) => {
|
||||
expect(asset).to.have.property('id')
|
||||
.and.to.not.equal(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,259 @@
|
||||
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').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 = [{
|
||||
email: 'stampi@gmail.com',
|
||||
displayName: 'Stampi',
|
||||
password: '1Coral!!'
|
||||
}, {
|
||||
email: 'sockmonster@gmail.com',
|
||||
displayName: '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.null;
|
||||
|
||||
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('#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.null;
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,211 @@
|
||||
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',
|
||||
displayName: 'Stampi',
|
||||
password: '1Coral!-'
|
||||
}, {
|
||||
email: 'sockmonster@gmail.com',
|
||||
displayName: 'Sockmonster',
|
||||
password: '2Coral!2'
|
||||
}, {
|
||||
email: 'marvel@gmail.com',
|
||||
displayName: '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('displayName', '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.displayName < b.displayName) {return -1;}
|
||||
if(a.displayName > b.displayName) {return 1;}
|
||||
return 0;
|
||||
});
|
||||
expect(sorted[0]).to.have.property('displayName', 'marvel');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#findLocalUser', () => {
|
||||
|
||||
it('should find a user when we give the right credentials', () => {
|
||||
return UsersService
|
||||
.findLocalUser(mockUsers[0].profiles[0].id, '1Coral!-')
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('displayName')
|
||||
.and.to.equal(mockUsers[0].displayName.toLowerCase());
|
||||
});
|
||||
});
|
||||
|
||||
it('should not find the user when we give the wrong credentials', () => {
|
||||
return UsersService
|
||||
.findLocalUser(mockUsers[0].profiles[0].id, '1Coral!-<nope>')
|
||||
.then((user) => {
|
||||
expect(user).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#createLocalUser', () => {
|
||||
it('should not create a user with duplicate display name', () => {
|
||||
return UsersService.createLocalUsers([{
|
||||
email: 'otrostampi@gmail.com',
|
||||
displayName: '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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user