diff --git a/.gitignore b/.gitignore index 3c51c1db4..5a42acb67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ node_modules -npm-debug.log +npm-debug.log* dist !dist/coral-admin dist/coral-admin/bundle.js +tests/e2e/reports .DS_Store *.iml dump.rdb diff --git a/bin/cli-serve b/bin/cli-serve index 14c1261d7..a6790c6a0 100755 --- a/bin/cli-serve +++ b/bin/cli-serve @@ -17,7 +17,8 @@ const util = require('../util'); /** * Get port from environment and store in Express. */ -const port = normalizePort(process.env.TALK_PORT || '3000'); + +const port = normalizePort(process.env.TALK_PORT || (process.env.NODE_ENV === 'test' ? '3011' : '3000')); app.set('port', port); diff --git a/client/coral-embed-stream/src/CommentStream.js b/client/coral-embed-stream/src/CommentStream.js index 753455d8d..0fda9444d 100644 --- a/client/coral-embed-stream/src/CommentStream.js +++ b/client/coral-embed-stream/src/CommentStream.js @@ -65,27 +65,17 @@ class CommentStream extends Component { componentDidMount () { // Set up messaging between embedded Iframe an parent component - // Using recommended Pym init code which violates .eslint standards - const pym = new Pym.Child({polling: 100}); + this.pym = new Pym.Child({polling: 100}); - if (/https?\:\/\/([^?]+)/.test(pym.parentUrl)) { - this.props.getStream(pym.parentUrl); - } else { - this.props.getStream(window.location); - } + const path = /https?\:\/\/([^?#]+)/.exec(this.pym.parentUrl); + + this.props.getStream(path[1] || window.location); + this.path = path; + + this.pym.sendMessage('childReady'); } render () { - if (Object.keys(this.props.items).length === 0) { - // Loading mock asset - this.props.postItem({ - comments: [], - url: 'http://coralproject.net' - }, 'asset', 'assetTest'); - } - - // TODO: Replace teststream id with id from params - const rootItemId = this.props.items.assets && Object.keys(this.props.items.assets)[0]; const rootItem = this.props.items.assets && this.props.items.assets[rootItemId]; const {actions, users, comments} = this.props.items; diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index 9ae524652..5f9592cd5 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -78,6 +78,7 @@ class CommentBox extends Component { { author && ( diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js index 395800e6c..de5e77a49 100644 --- a/client/coral-sign-in/components/SignInContent.js +++ b/client/coral-sign-in/components/SignInContent.js @@ -44,7 +44,7 @@ const SignInContent = ({handleChange, formData, ...props}) => (
{ !props.auth.isLoading ? - : @@ -56,7 +56,7 @@ const SignInContent = ({handleChange, formData, ...props}) => ( props.changeView('FORGOT')}>{lang.t('signIn.forgotYourPass')} {lang.t('signIn.needAnAccount')} - props.changeView('SIGNUP')}> + props.changeView('SIGNUP')} id='coralRegister'> {lang.t('signIn.register')} diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index 38fa554fe..2f9e9afe1 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -69,7 +69,7 @@ const SignUpContent = ({handleChange, formData, ...props}) => ( />
{ !props.auth.isLoading && !props.auth.successSignUp && ( - )} diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js index c201a3863..28dc021d2 100644 --- a/client/coral-sign-in/containers/SignInContainer.js +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -132,7 +132,9 @@ class SignInContainer extends Component { const {auth, showSignInDialog, noButton} = this.props; return (
- {!noButton && } + {!noButton && } =7.0.0" diff --git a/pree2e.sh b/pree2e.sh new file mode 100755 index 000000000..8857e5745 --- /dev/null +++ b/pree2e.sh @@ -0,0 +1,2 @@ +node_modules/selenium-standalone/bin/selenium-standalone install +npm start & diff --git a/tests/e2e/globals.js b/tests/e2e/globals.js new file mode 100644 index 000000000..147af2663 --- /dev/null +++ b/tests/e2e/globals.js @@ -0,0 +1,4 @@ +module.exports = { + waitForConditionTimeout: 20000, + baseUrl: 'localhost:3011/' +}; diff --git a/tests/e2e/mocks.js b/tests/e2e/mocks.js new file mode 100644 index 000000000..a4f430cd5 --- /dev/null +++ b/tests/e2e/mocks.js @@ -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)); diff --git a/tests/e2e/pages/embedStream.js b/tests/e2e/pages/embedStream.js new file mode 100644 index 000000000..cc584a656 --- /dev/null +++ b/tests/e2e/pages/embedStream.js @@ -0,0 +1,45 @@ +const fetch = require('node-fetch'); + +const embedCommands = { + ready() { + return this.resizeWindow(1200, 800) + .url(client.globals.baseUrl) + .waitForElementVisible('body', 2000) + .frame('coralStreamIframe'); + }, + setConfig(config, baseUrl) { + return fetch(`${baseUrl}/api/v1/settings`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify(config) + }); + }, + enterComment() { + const comment = 'This is a test comment'; + return this + .waitForElementVisible('@commentBox') + .setValue('@commentBox', comment) + .click('@postButton') + .waitForElementVisible('.comment', 1000); + }, + validateComment(comment) { + return this + .assert.equal(comment, '.comment'); + } +}; + +module.exports = { + commands: [embedCommands], + elements: { + + commentBox: { + selector: '#commentBox' + }, + postButton: { + selector: '#commentBox .coral-plugin-commentbox-button' + } + } +}; diff --git a/tests/e2e/tests/AppTest.js b/tests/e2e/tests/AppTest.js new file mode 100644 index 000000000..36281ed3f --- /dev/null +++ b/tests/e2e/tests/AppTest.js @@ -0,0 +1,13 @@ +module.exports = { + '@tags': ['app'], + 'Base url and Hostname': browser => { + const {baseUrl} = browser.globals; + browser + .url(baseUrl) + .assert.title('Coral Talk') + .waitForElementPresent('body', 1000); + }, + after: client => { + client.end(); + } +}; diff --git a/tests/e2e/tests/EmbedStreamTests.js b/tests/e2e/tests/EmbedStreamTests.js new file mode 100644 index 000000000..65ea9fa76 --- /dev/null +++ b/tests/e2e/tests/EmbedStreamTests.js @@ -0,0 +1,173 @@ +const utils = require('../../utils/e2e-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: 'Test User', + pw: 'testtesttest' +}; + +module.exports = { + '@tags': ['embed-stream', 'comment', 'premodoff', 'premodon'], + before: () => { + utils.before(); + }, + '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 => { + utils.after(); + client.end(); + } +}; diff --git a/tests/utils/e2e-mongoose.js b/tests/utils/e2e-mongoose.js new file mode 100644 index 000000000..1bb7e695b --- /dev/null +++ b/tests/utils/e2e-mongoose.js @@ -0,0 +1,34 @@ +const mongoose = require('../../mongoose'); + +// Ensure the NODE_ENV is set to 'test', +// this is helpful when you would like to change behavior when testing. +function clearDB() { + // console.log('Clearing DB', mongoose.connection); + for (let i in mongoose.connection.collections) { + // console.log('Clearing', i); + mongoose.connection.collections[i].remove(function() {}); + } +} + +module.exports = { + before: () => { + clearDB(); + }, + beforeEach: () => { + if (mongoose.connection.readyState === 0) { + mongoose.on('open', function() { + if (err) { + throw err; + } + + return clearDB(); + }); + } else { + return clearDB(); + } + }, + after: () => { + clearDB(); + mongoose.disconnect(); + } +}; diff --git a/views/article.ejs b/views/article.ejs index 6fd420f82..f4d7ef910 100644 --- a/views/article.ejs +++ b/views/article.ejs @@ -15,6 +15,7 @@ width:500px; } + <%= title %>
@@ -35,7 +36,7 @@