Merge pull request #249 from coralproject/e2e-env-fix

E2E environment fix
This commit is contained in:
David Erwin
2017-01-30 12:14:50 -05:00
committed by GitHub
20 changed files with 169 additions and 74 deletions
+18
View File
@@ -7,6 +7,7 @@
const program = require('commander');
const pkg = require('../package.json');
const dotenv = require('dotenv');
const util = require('../util');
//==============================================================================
// Setting up the program command line arguments.
@@ -15,6 +16,7 @@ const dotenv = require('dotenv');
program
.version(pkg.version)
.option('-c, --config [path]', 'Specify the configuration file to load')
.option('--pid [path]', 'Specify a path to output the current PID to')
.parse(process.argv);
if (program.config) {
@@ -27,6 +29,11 @@ if (program.config) {
}
}
// If the `--pid` flag is used, put the current pid there.
if (program.pid) {
util.pid(program.pid);
}
// Perform rewrites to the runtime environment variables based on the contents
// of the process.env.REWRITE_ENV if it exists. This is done here as it is the
// entrypoint for the entire application.
@@ -43,4 +50,15 @@ program
// If there is no command listed, output help.
if (!process.argv.slice(2).length) {
program.outputHelp();
return;
}
// The ensures that the child process that is created here is always cleaned up
// properly when the parent process dies.
util.onshutdown([
(signal) => {
if ((program.runningCommand.killed === false) && (program.runningCommand.exitCode === null)) {
program.runningCommand.kill(signal);
}
}
]);
+2
View File
@@ -21,6 +21,8 @@ test:
override:
# Run the tests using the junit reporter.
- MOCHA_FILE=$CIRCLE_TEST_REPORTS/junit/test-results.xml NPM_PACKAGE_CONFIG_MOCHA_REPORTER=mocha-junit-reporter npm run test
# Run the e2e test suite
- E2E_REPORT_PATH=$CIRCLE_TEST_REPORTS/e2e npm run e2e
deployment:
release:
@@ -8,10 +8,10 @@ import SuspendUserModal from './SuspendUserModal';
// Each action has different meaning and configuration
const menuOptionsMap = {
'reject': {status: 'rejected', icon: 'close', key: 'r'},
'approve': {status: 'accepted', icon: 'done', key: 't'},
'flag': {status: 'flagged', icon: 'flag', filter: 'Untouched'},
'ban': {status: 'banned', icon: 'not interested'}
'reject': {status: 'REJECTED', icon: 'close', key: 'r'},
'approve': {status: 'ACCEPTED', icon: 'done', key: 't'},
'flag': {status: 'FLAGGED', icon: 'flag', filter: 'Untouched'},
'ban': {status: 'BANNED', icon: 'not interested'}
};
// Renders a comment list and allow performing actions
@@ -135,9 +135,9 @@ export default class ModerationList extends React.Component {
} else if (action.item_type === 'USERS') {
// If a user bio or name is rejected, bring up a dialog before suspending them.
if (menuOption === 'rejected') {
if (menuOption === 'REJECTED') {
this.setState({suspendUserModal: action});
} else if (menuOption === 'accepted') {
} else if (menuOption === 'ACCEPTED') {
this.props.userStatusUpdate('ACTIVE', action.item_id);
}
}
+1 -1
View File
@@ -87,7 +87,7 @@ class Comment extends React.Component {
return (
<div
className="comment"
className={parentId ? 'reply' : 'comment'}
id={`c_${comment.id}`}
style={{marginLeft: depth * 30}}>
<hr aria-hidden={true} />
@@ -2,6 +2,7 @@ fragment commentView on Comment {
id
body
created_at
status
user {
id
name: displayName
@@ -75,8 +75,6 @@ class CommentBox extends Component {
} else if (postedComment.status === 'PREMOD') {
addNotification('success', lang.t('comment-post-notif-premod'));
} else {
// appendItemArray(parent_id || id, related, commentId, !parent_id, parent_type);
addNotification('success', 'Your comment has been posted.');
}
@@ -1,5 +1,5 @@
import React from 'react';
const name = 'coral-plugin-replies';
const name = 'coral-plugin-content';
const Content = ({body, styles}) => {
const textbreaks = body.split('\n');
+11 -10
View File
@@ -1,16 +1,21 @@
require('babel-core/register');
let E2E_REPORT_PATH = './test/e2e/reports';
if (process.env.E2E_REPORT_PATH && process.env.E2E_REPORT_PATH.length > 0) {
E2E_REPORT_PATH = process.env.E2E_REPORT_PATH;
}
module.exports = {
'src_folders': './tests/e2e/tests',
'output_folder': './tests/e2e/reports',
'page_objects_path': './tests/e2e/pages',
'globals_path': './tests/e2e/globals',
'src_folders': './test/e2e/tests',
'output_folder': E2E_REPORT_PATH,
'page_objects_path': './test/e2e/pages',
'globals_path': './test/e2e/globals',
'custom_commands_path' : '',
'custom_assertions_path' : '',
'selenium': {
'start_process': true,
'server_path': 'node_modules/selenium-standalone/.selenium/selenium-server/2.53.1-server.jar',
'log_path': './tests/e2e/reports',
'log_path': E2E_REPORT_PATH,
'host': '127.0.0.1',
'port': 6666,
'cli_args': {
@@ -36,7 +41,7 @@ module.exports = {
'enabled': true,
'on_failure': true,
'on_error': true,
'path': './tests/e2e/reports'
'path': E2E_REPORT_PATH
},
'exclude': [
'./tests/e2e/tests/EmbedStreamTests.js'
@@ -47,7 +52,3 @@ module.exports = {
}
}
};
// "chromeOptions" : {
// "args" : ["start-fullscreen"]
// }
+2 -1
View File
@@ -14,6 +14,7 @@
"test-cover": "TEST_MODE=unit NODE_ENV=test istanbul cover _mocha --report text --check-coverage -- -R spec",
"pree2e": "NODE_ENV=test scripts/pree2e.sh",
"e2e": "NODE_ENV=test nightwatch",
"poste2e": "NODE_ENV=test scripts/poste2e.sh",
"embed-start": "NODE_ENV=development npm run build && ./bin/cli serve --jobs",
"postinstall": "npm run build"
},
@@ -153,7 +154,7 @@
"redux-mock-store": "^1.2.1",
"redux-thunk": "^2.1.0",
"regenerator": "^0.8.46",
"selenium-standalone": "latest",
"selenium-standalone": "^5.11.2",
"style-loader": "^0.13.1",
"supertest": "^2.0.1",
"timeago.js": "^2.0.3",
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
# If there is a PID file from the e2e tests...
if [ -e /tmp/talk-e2e.pid ]
then
# Then kill the running talk server.
kill $(cat /tmp/talk-e2e.pid)
fi
+9 -5
View File
@@ -1,15 +1,19 @@
#!/bin/bash
# install selenium
selenium-standalone install
selenium-standalone install --config=./selenium.config.js
#Init settings
./bin/cli settings init
# Creating Admin Test User
./bin/cli-users create --flag_mode --email "admin@test.com" --password "test" --name "Admin Test User" --role "admin"
./bin/cli users create --flag_mode --email "admin@test.com" --password "testtest" --name "AdminTestUser" --role "ADMIN"
# Creating Moderator Test User
./bin/cli-users create --flag_mode --email "moderator@test.com" --password "test" --name "Moderator Test User" --role "moderator"
./bin/cli users create --flag_mode --email "moderator@test.com" --password "testtest" --name "ModeratorTestUser" --role "MODERATOR"
# Creating Commenter Test User
./bin/cli-users create --flag_mode --email "commenter@test.com" --password "test" --name "commenter@test.com"
./bin/cli users create --flag_mode --email "commenter@test.com" --password "testtest" --name "CommenterTestUser"
npm start &
# Start the server and write the PID to a file to be killed later.
./bin/cli --pid /tmp/talk-e2e.pid serve --jobs &
+9
View File
@@ -0,0 +1,9 @@
module.exports = {
drivers: {
chrome: {
version: '2.25',
arch: process.arch,
baseURL: 'https://chromedriver.storage.googleapis.com'
},
},
};
+3 -3
View File
@@ -4,15 +4,15 @@ module.exports = {
users: {
admin: {
email: 'admin@test.com',
pass: 'test'
pass: 'testtest'
},
moderator: {
email: 'moderator@test.com',
pass: 'test'
pass: 'testtest'
},
commenter: {
email: 'commenter@test.com',
pass: 'test'
pass: 'testtest'
}
},
};
+7 -6
View File
@@ -1,8 +1,8 @@
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 Comments = require('../../services/comments');
const Users = require('../../services/users');
const Actions = require('../../services/actions');
const Assets = require('../../services/assets');
const Settings = require('../../services/settings');
const globals = require('./globals');
/* Create an array of comments */
@@ -22,4 +22,5 @@ module.exports.users = (users) => Users.createLocalUsers(users);
module.exports.actions = (actions) => Actions.create(actions);
/* Update a setting */
module.exports.settings = (setting) => Settings.init().then(() => Settings.updateSettings(setting));
module.exports.settings = (setting) => Settings.init().then(() =>
Settings.update(setting));
+2 -1
View File
@@ -10,7 +10,8 @@ const embedStreamCommands = {
return this
.waitForElementVisible('@moderationList')
.waitForElementVisible('@approveButton')
.click('@approveButton');
.click('@approveButton')
.waitForElementNotPresent('@approveButton');
}
};
+2 -2
View File
@@ -127,10 +127,10 @@ module.exports = {
selector: '.comment .coral-plugin-flags-popup'
},
flagCommentOption: {
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-radio-label[for="comments"]'
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"]'
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-radio-label[for="USERS"]'
},
flagOtherOption: {
selector: '.comment .coral-plugin-flags-popup .coral-plugin-flags-popup-radio-label[for="other"]'
+12 -4
View File
@@ -1,10 +1,18 @@
const mocks = require('../mocks');
module.exports = {
'@tags': ['embedStream'],
before: client => {
const embedStreamPage = client.page.embedStreamPage();
embedStreamPage
.navigate()
.ready();
client.perform((client, done) => {
mocks.settings({moderation: 'PRE'})
.then(() => {
const embedStreamPage = client.page.embedStreamPage();
embedStreamPage
.navigate()
.ready();
done();
});
});
},
'Login as commenter': client => {
const embedStreamPage = client.page.embedStreamPage();
+18 -23
View File
@@ -1,12 +1,12 @@
const mongoose = require('../../helpers/mongoose');
const mocks = require('../mocks');
const mockComment = 'This is a test comment.';
const mockComment = 'I read the comments';
const mockReply = 'This is a test reply';
const mockUser = {
email: `${new Date().getTime()}@test.com`,
name: 'Test User',
pw: 'testtesttest'
name: 'testuser',
pw: 'testtest'
};
module.exports = {
@@ -29,7 +29,6 @@ module.exports = {
.frame('coralStreamIframe')
// Register and Log In
.waitForElementVisible('#commentBox', 1000)
.waitForElementVisible('#coralSignInButton', 2000)
.click('#coralSignInButton')
.waitForElementVisible('#coralRegister', 1000)
@@ -47,10 +46,10 @@ module.exports = {
// Post a comment
.setValue('.coral-plugin-commentbox-textarea', mockComment)
.click('.coral-plugin-commentbox-button')
.waitForElementVisible('.comment', 1000)
.waitForElementVisible('.coral-plugin-content-text', 1000)
// Verify that it appears
.assert.containsText('.comment', mockComment);
.assert.containsText('.coral-plugin-content-text', mockComment);
done();
})
.catch((err) => {
@@ -104,8 +103,8 @@ module.exports = {
.click('.coral-plugin-replies-reply-button')
.waitForElementVisible('#replyText')
.setValue('#replyText', mockReply)
.click('.coral-plugin-replies-textarea button')
.waitForElementVisible('.reply', 2000)
.click('.coral-plugin-replies-textarea .coral-plugin-commentbox-button')
.waitForElementVisible('.reply', 20000)
// Verify that it appears
.assert.containsText('.reply', mockReply);
@@ -122,22 +121,18 @@ module.exports = {
mocks.settings({moderation: 'PRE'})
// Add a mock user
.then(() => {
return mocks.users([{
displayName: 'Baby Blue',
email: 'whale@tale.sea',
password: 'krill'
}]);
})
.then(() => 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((user) => mocks.comments([{
body: 'Whales are not fish.',
status: 'accepted',
author_id: user.id
}]))
.then(() => {
// Load Page
@@ -170,7 +165,7 @@ module.exports = {
// Verify that comment count is correct
client.waitForElementVisible('.coral-plugin-comment-count-text', 2000)
.assert.containsText('.coral-plugin-comment-count-text', '1 Comment');
.assert.containsText('.coral-plugin-comment-count-text', '4 Comments');
done();
});
},
+2 -4
View File
@@ -1,5 +1,3 @@
const uuid = require('uuid');
module.exports = {
'@tags': ['signup', 'visitor'],
before: client => {
@@ -14,8 +12,8 @@ module.exports = {
embedStreamPage
.signUp({
email: `visitor_${uuid.v4()}@test.com`,
displayName: 'Visitor',
email: `visitor_${Date.now()}@test.com`,
displayName: `visitor${Date.now()}`,
pass: 'testtest'
});
},
+53 -5
View File
@@ -1,3 +1,6 @@
const debug = require('debug')('talk:util');
const fs = require('fs');
const util = module.exports = {};
/**
@@ -11,10 +14,16 @@ util.toshutdown = [];
* Calls all the shutdown functions and then ends the process.
* @param {Number} [defaultCode=0] default return code upon sucesfull shutdown.
*/
util.shutdown = (defaultCode = 0) => {
util.shutdown = (defaultCode = 0, signal = null) => {
if (signal) {
debug(`Reached ${signal} signal`);
}
Promise
.all(util.toshutdown.map((func) => func ? func() : null).filter((func) => func))
.all(util.toshutdown.map((func) => func ? func(signal) : null).filter((func) => func))
.then(() => {
debug('Shutdown complete, now exiting');
process.exit(defaultCode);
})
.catch((err) => {
@@ -32,13 +41,52 @@ util.shutdown = (defaultCode = 0) => {
*/
util.onshutdown = (jobs) => {
debug(`${jobs.length} jobs registered`);
// Add the new jobs to shutdown to the object reference.
util.toshutdown = util.toshutdown.concat(jobs);
};
/**
* Register a PID file to be maintained for the lifespan of the process.
* @param {String} path path to the PID file to create
*/
util.pid = (path) => {
if (!/\//.test(path)) {
if (!/\.pid/.test(path)) {
path += '.pid';
}
path = `/tmp/${path}`;
}
const pid = `${process.pid.toString()}\n`;
fs.writeFile(path, pid, (err) => {
if (err) {
console.error(`Can't write PID file: ${err}`);
throw err;
}
// Add the cleanup for the fs onto the shutdown.
util.onshutdown([
() => new Promise((resolve, reject) => {
// Remove the pid file.
fs.unlink(path, (err) => {
if (err) {
return reject(err);
}
return resolve();
});
})
]);
});
};
// Attach to the SIGTERM + SIGINT handles to ensure a clean shutdown in the
// event that we have an external event. SIGUSR2 is called when the app is asked
// to be 'killed', same procedure here.
process.on('SIGTERM', () => util.shutdown());
process.on('SIGINT', () => util.shutdown());
process.once('SIGUSR2', () => util.shutdown());
process.on('SIGTERM', () => util.shutdown(0, 'SIGTERM'));
process.on('SIGINT', () => util.shutdown(0, 'SIGINT'));
process.once('SIGUSR2', () => util.shutdown(0, 'SIGUSR2'));