First isolated e2e

This commit is contained in:
Chi Vinh Le
2017-10-16 22:27:49 +07:00
parent 606871e4b7
commit f38e718373
12 changed files with 306 additions and 114 deletions
+8 -7
View File
@@ -119,7 +119,7 @@ const CONFIG = {
//------------------------------------------------------------------------------
// Port to bind to.
PORT: process.env.TALK_PORT || process.env.PORT || '3000',
PORT: process.env.TALK_PORT || process.env.PORT || process.env.NODE_ENV === 'test' ? '3001' : '3000',
// The URL for this Talk Instance as viewable from the outside.
ROOT_URL: process.env.TALK_ROOT_URL || null,
@@ -182,12 +182,13 @@ const CONFIG = {
// CONFIG VALIDATION
//==============================================================================
if (CONFIG.ROOT_URL_MOUNT_PATH && !CONFIG.ROOT_URL) {
throw new Error('TALK_ROOT_URL must be specified if TALK_ROOT_URL_MOUNT_PATH is set to TRUE');
}
if (process.env.NODE_ENV === 'test' && !CONFIG.ROOT_URL) {
CONFIG.ROOT_URL = 'http://localhost:3000';
if (process.env.NODE_ENV === 'test') {
if (!CONFIG.ROOT_URL) {
CONFIG.ROOT_URL = 'http://localhost:3001';
}
if (!CONFIG.STATIC_URL) {
CONFIG.STATIC_URI = 'http://localhost:3001';
}
} else if (!CONFIG.ROOT_URL) {
throw new Error('TALK_ROOT_URL must be provided');
}
+36 -32
View File
@@ -1,42 +1,46 @@
const {
ROOT_URL
} = require('./config');
module.exports = {
'src_folders': './test/e2e/specs/',
'output_folder': './test/e2e/tests_output',
'page_objects_path': './test/e2e/page_objects',
'globals_path': './test/e2e/globals',
'selenium': {
'start_process': true,
'server_path': 'node_modules/selenium-standalone/.selenium/selenium-server/3.5.3-server.jar',
'log_path': './test/e2e/reports',
'host': '127.0.0.1',
'port': 6666,
'cli_args': {
src_folders: './test/e2e/specs/',
output_folder: './test/e2e/tests_output',
page_objects_path: './test/e2e/page_objects',
globals_path: './test/e2e/globals',
selenium: {
start_process: true,
server_path: 'node_modules/selenium-standalone/.selenium/selenium-server/3.5.3-server.jar',
log_path: './test/e2e/reports',
host: '127.0.0.1',
port: 6666,
cli_args: {
'webdriver.chrome.driver': 'node_modules/selenium-standalone/.selenium/chromedriver/2.32-x64-chromedriver'
}
},
'test_settings': {
'default': {
'launch_url' : 'http://localhost:3000',
'selenium_port': 6666,
'selenium_host': 'localhost',
'silent': true,
'desiredCapabilities': {
'browserName': 'chrome',
'javascriptEnabled': true,
'acceptSslCerts': true,
'webStorageEnabled': true,
'databaseEnabled': true,
'applicationCacheEnabled': false,
'nativeEvents': true
test_settings: {
default: {
launch_url: ROOT_URL,
selenium_port: 6666,
selenium_host: 'localhost',
silent: true,
desiredCapabilities: {
browserName: 'chrome',
javascriptEnabled: true,
acceptSslCerts: true,
webStorageEnabled: true,
databaseEnabled: true,
applicationCacheEnabled: false,
nativeEvents: true
},
'screenshots' : {
'enabled': true,
'on_failure': true,
'on_error': true,
'path': './test/e2e/tests_output'
screenshots : {
enabled: true,
on_failure: true,
on_error: true,
path: './test/e2e/tests_output'
},
},
'integration': {
'launch_url': 'http://localhost:3000'
integration: {
launch_url: 'http://localhost:3000'
}
}
};
+10 -8
View File
@@ -1,27 +1,29 @@
const {
ROOT_URL
} = require('./config');
const nightwatch_config = {
src_folders: './test/e2e/specs/',
output_folder: './test/e2e/tests_output',
page_objects_path: './test/e2e/page_objects',
globals_path: './test/e2e/globals',
selenium : {
'start_process': false,
'host': 'hub-cloud.browserstack.com',
'port': 80
start_process: false,
host: 'hub-cloud.browserstack.com',
port: 80
},
test_settings: {
default: {
globals: {
waitForConditionTimeout: 5000,
},
launch_url: process.env.TALK_ROOT_URL || 'http://localhost:3000',
launch_url: ROOT_URL,
desiredCapabilities: {
'browserstack.user': process.env.BROWSERSTACK_USER || 'coralproject2',
'browserstack.key': process.env.BROWSERSTACK_KEY,
'browserstack.local': true,
'browser': 'chrome',
'browserstack.debug': true,
'browserstack.networkLogs': true,
'browser': 'chrome',
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@
"lint": "yamllint locales/*.yml && eslint --ext=.js --ext=.json bin/* .",
"lint-fix": "yarn lint --fix",
"jest-watch": "TEST_MODE=unit NODE_ENV=test jest --watch",
"e2e": "./scripts/e2e.js",
"e2e": "NODE_ENV=test ./scripts/e2e.js",
"pree2e-local": "./scripts/e2e-local.sh",
"e2e-local": "nightwatch --config nightwatch-local.conf.js",
"test": "TEST_MODE=unit NODE_ENV=test jest && TEST_MODE=unit NODE_ENV=test mocha -R ${MOCHA_REPORTER:-spec}",
+169
View File
@@ -0,0 +1,169 @@
#!/usr/bin/env node
const debug = require('debug')('talk:e2e:serve');
const app = require('../app');
const errors = require('../errors');
const {createServer} = require('http');
const scraper = require('../services/scraper');
const mailer = require('../services/mailer');
const SetupService = require('../services/setup');
const kue = require('../services/kue');
const mongoose = require('../services/mongoose');
const util = require('../bin/util');
const cache = require('../services/cache');
const MigrationService = require('../services/migration');
const {createSubscriptionManager} = require('../graph/subscriptions');
const {
PORT
} = require('../config');
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(PORT);
app.set('port', port);
/**
* Create HTTP server.
*/
const server = createServer(app);
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
let bind = typeof port === 'string'
? `Pipe ${port}`
: `Port ${port}`;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(`${bind} requires elevated privileges`);
break;
case 'EADDRINUSE':
console.error(`${bind} is already in use`);
break;
}
throw error;
}
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
let port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "listening" event.
*/
async function onListening() {
// Start the cache instance.
await cache.init();
let addr = server.address();
let bind = typeof addr === 'string'
? `pipe ${addr}`
: `port ${addr.port}`;
debug(`API Server Listening on ${bind}`);
}
/**
* Start the app.
*/
async function serve() {
try {
// Check to see if the application is installed. If the application
// has been installed, then it will throw errors.ErrSettingsNotInit, this
// just means we don't have to check that the migrations have run.
await SetupService.isAvailable();
debug('setup is currently available, migrations not being checked');
} catch (e) {
// Check the error.
switch (e) {
case errors.ErrInstallLock, errors.ErrSettingsInit:
debug('setup is not currently available, migrations now being checked');
// The error was expected, just continue.
break;
default:
// The error was not expected, throw the error!
throw e;
}
// Now try and check the migration status.
try {
// Verify that the minimum migration version is met.
await MigrationService.verify();
} catch (e) {
console.error(e);
process.exit(1);
}
}
/**
* Listen on provided port, on all network interfaces.
*/
server.on('error', onError);
server.on('listening', onListening);
server.on('listening', () => {
});
server.listen(port, () => {
// Mount the websocket server if requested.
debug(`Websocket Server Listening on ${port}`);
// Mount the subscriptions server on the application server.
createSubscriptionManager(server);
});
// Start the scraper processor.
scraper.process();
// Start the mail processor.
mailer.process();
// Define a safe shutdown function to call in the event we need to shutdown
// because the node hooks are below which will interrupt the shutdown process.
// Shutdown the mongoose connection, the app server, and the scraper.
util.onshutdown([
() => kue.Task.shutdown(),
() => mongoose.disconnect(),
() => server.close()
]);
}
module.exports = serve;
+40 -30
View File
@@ -2,40 +2,50 @@
const Nightwatch = require('nightwatch');
const browserstack = require('browserstack-local');
const {onshutdown} = require('../bin/util');
try {
const bs_local = new browserstack.Local();
process.mainModule.filename = './node_modules/.bin/nightwatch';
async function start() {
try {
const bs_local = new browserstack.Local();
process.mainModule.filename = './node_modules/.bin/nightwatch';
// Code to start browserstack local before start of test
console.log('Connecting local');
Nightwatch.bs_local = bs_local;
bs_local.start({
'key': process.env.BROWSERSTACK_KEY,
'logFile': './test/e2e/bslocal.log'
}, function(error) {
if (error) {
console.error(error);
throw error;
}
// Code to start browserstack local before start of test
console.log('Connecting local');
Nightwatch.bs_local = bs_local;
console.log('Connected. Now testing...');
Nightwatch.cli(function(argv) {
Nightwatch.CliRunner(argv)
.setup(null, function(){
bs_local.start({
'key': process.env.BROWSERSTACK_KEY,
'logFile': './test/e2e/bslocal.log'
}, function(error) {
if (error) {
console.error(error);
throw error;
}
// Code to stop browserstack local after end of parallel test
bs_local.stop(function(){});
})
.runTests(function(){
console.log('Connected. Now testing...');
Nightwatch.cli(function(argv) {
Nightwatch.CliRunner(argv)
.setup(null, function(){
// Code to stop browserstack local after end of single test
bs_local.stop(function(){});
});
// Code to stop browserstack local after end of parallel test
bs_local.stop(function(){});
})
.runTests(function(){
// Code to stop browserstack local after end of single test
bs_local.stop(function(){});
});
});
});
});
} catch (ex) {
console.log('There was an error while starting the test runner:\n\n');
process.stderr.write(`${ex.stack}\n`);
process.exit(2);
onshutdown([
() => bs_local.stop(function(){}),
]);
} catch (ex) {
console.log('There was an error while starting the test runner:\n\n');
process.stderr.write(`${ex.stack}\n`);
process.exit(2);
}
}
start();
+17 -7
View File
@@ -1,14 +1,24 @@
const uuid = require('uuid');
const {murmur3} = require('murmurhash-js');
const rHash = murmur3(uuid.v4());
const serve = require('../../scripts/e2e-serve');
const mongoose = require('../../services/mongoose');
const {shutdown} = require('../../bin/util');
module.exports = {
before: async (done) => {
await mongoose.connection.dropDatabase();
await serve();
done();
},
after: (done) => {
shutdown();
done();
},
waitForConditionTimeout: 5000,
testData: {
admin: {
email: 'admin@test.com',
username: 'admin',
password: 'testtest',
},
organizationName: 'Coral',
email: `test_${rHash}@test.test`,
username: `test${rHash}`,
password: `testpassword${rHash}`,
domain: 'http://localhost:3000'
}
};
+1 -1
View File
@@ -5,7 +5,7 @@ module.exports = {
},
ready() {
return this
.waitForElementVisible('body', 2000);
.waitForElementVisible('body');
},
}],
elements: {
+2 -2
View File
@@ -5,7 +5,7 @@ module.exports = {
},
ready() {
return this
.waitForElementVisible('body', 2000);
.waitForElementVisible('body');
}
}],
elements: {
@@ -20,7 +20,7 @@ module.exports = {
'step3ConfirmPasswordInput': '.talk-install-step-3 #confirmPassword',
'step3saveButton': '.talk-install-step-3-save-button',
'step4': '.talk-install-step-4',
'step4DomainInput': '.talk-install-step-4-permited-domains-input',
'step4DomainInput': '.talk-install-step-4-permited-domains-input input',
'step4saveButton': '.talk-install-step-4-save-button',
}
};
+12 -13
View File
@@ -2,7 +2,7 @@ module.exports = {
'@tags': ['install'],
'User goes to install': (client) => {
const installPage = client.page.installPage();
installPage
.navigate()
.ready();
@@ -10,14 +10,14 @@ module.exports = {
},
'User clicks get started button': (client) => {
const installPage = client.page.installPage();
installPage
.waitForElementVisible('@getStartedButton')
.click('@getStartedButton');
},
'User should see step 2 - Add Organization Name': (client) => {
const installPage = client.page.installPage();
installPage
.waitForElementVisible('@step2');
},
@@ -33,38 +33,37 @@ module.exports = {
},
'User should see step 3 - Create your account': (client) => {
const installPage = client.page.installPage();
installPage
.waitForElementVisible('@step3');
},
'User fills step 3': (client) => {
const installPage = client.page.installPage();
const {testData} = client.globals;
const {testData: {admin}} = client.globals;
installPage
.setValue('@step3EmailInput', testData.email)
.setValue('@step3UsernameInput', testData.username)
.setValue('@step3PasswordInput', testData.password)
.setValue('@step3ConfirmPasswordInput', testData.password)
.setValue('@step3EmailInput', admin.email)
.setValue('@step3UsernameInput', admin.username)
.setValue('@step3PasswordInput', admin.password)
.setValue('@step3ConfirmPasswordInput', admin.password)
.waitForElementVisible('@step3saveButton')
.click('@step3saveButton');
},
'User should see step 4 - Domain Whitelist': (client) => {
const installPage = client.page.installPage();
installPage
.waitForElementVisible('@step4');
},
'User fills step 4': (client) => {
const installPage = client.page.installPage();
const testData = client.page.getTestData();
installPage
.waitForElementVisible('@step4DomainInput')
.setValue('@step4DomainInput', testData.domain);
.setValue('@step4DomainInput', client.launchUrl);
client.keys(client.Keys.ENTER);
installPage
.waitForElementVisible('@step4saveButton')
.click('@step4saveButton');
+5 -4
View File
@@ -2,13 +2,14 @@ module.exports = {
'@tags': ['admin', 'login'],
'Admin logs in': (client) => {
const adminPage = client.page.adminPage();
const {testData} = client.globals;
const {testData: {admin}} = client.globals;
adminPage
.navigate()
.waitForElementVisible('@loginLayout')
.waitForElementVisible('@signInForm')
.setValue('@emailInput', testData.email)
.setValue('@passwordInput', testData.password)
.setValue('@emailInput', admin.email)
.setValue('@passwordInput', admin.password)
.waitForElementVisible('@signInButton')
.click('@signInButton');
@@ -1,18 +1,13 @@
const uuid = require('uuid');
const {murmur3} = require('murmurhash-js');
module.exports = {
'Creates a new asset': (client) => {
const asset = `test@${murmur3(uuid.v4())}`;
const asset = 'newAssetTest';
const embedStream = client.page.embedStream();
embedStream
.navigateToAsset(asset)
.assert.title(asset)
.getEmbedSection();
client
.end();
},
'not logged in user clicks my profile tab': (client) => {
@@ -27,8 +22,9 @@ module.exports = {
profile
.assert.visible('@notLoggedIn');
client
.end();
},
after: (client) => {
client.end();
}
};