src/lib/chimp-helper.js
var chai = require('chai'),
chaiAsPromised = require('chai-as-promised'),
log = require('./log'),
DDP = require('./ddp'),
request = require('request'),
Promise = require('bluebird'),
_ = require('underscore'),
wrapAsync = require('xolvio-sync-webdriverio').wrapAsync,
wrapAsyncObject = require('xolvio-sync-webdriverio').wrapAsyncObject,
SessionFactory = require('./session-factory'),
path = require('path'),
colors = require('colors'),
fs = require('fs-extra'),
exit = require('exit'),
booleanHelper = require('./boolean-helper');
import merge from 'deep-extend';
import {
parseNullableString,
parseNullableInteger,
parseBoolean } from './environment-variable-parsers';
var chimpHelper = {
loadAssertionLibrary: function () {
if (booleanHelper.isTruthy(process.env['chimp.chai'])) {
log.debug('[chimp][helper] Using the chai-expect assertion library');
chai.use(chaiAsPromised);
chai.should();
// give users access to the chai instance
global.chai = chai;
global.expect = chai.expect;
global.assert = chai.assert;
} else {
log.debug('[chimp][helper] Using the jasmine-expect assertion library');
global.expect = require('xolvio-jasmine-expect').expect;
}
},
setupGlobals: function () {
global.wrapAsync = wrapAsync;
global.wrapAsyncObject = wrapAsyncObject;
// give users access the request module
global.request = request;
_.extend(global, wrapAsyncObject(global, ['request'], {
syncByDefault: booleanHelper.isTruthy(process.env['chimp.sync'])
}));
// Give the user access to Promise functions. E.g. Promise.all.
global.Promise = Promise;
if (booleanHelper.isTruthy(process.env['chimp.ddp0'])) {
// add .instances[] property onto the DDP object. this way
// global.server is usable, but so is server.instances[0] as an alias for when using multiple ddp servers
global.ddp = new DDP(process.env['chimp.ddp0']).connect();
// add on instances t
global.ddp.instances = [];
for(let key in process.env) {
if(key.indexOf('chimp.ddp') !== -1 ) {
var index = key.match(/chimp.ddp(.*)/)[1];
if (index) {
global.ddp.instances.push(new DDP(process.env['chimp.ddp' + index]).connect());
}
}
}
}
},
createGlobalAliases: function () {
global.driver = global.browser;
global.client = global.browser;
global.mirror = global.ddp;
global.server = global.ddp;
},
setupBrowserAndDDP: function () {
var setupBrowser = function () {
log.debug('[chimp][helper] getting browser');
const webdriverioConfigOptions = JSON.parse(process.env['chimp.webdriverio']);
const webdriverioOptions = merge(
webdriverioConfigOptions,
{
desiredCapabilities: {
browserName: parseNullableString(process.env['chimp.browser']),
platform: parseNullableString(process.env['chimp.platform']),
name: parseNullableString(process.env['chimp.name']),
version: parseNullableString(process.env['chimp.browserVersion']),
deviceName: parseNullableString(process.env['chimp.deviceName']),
},
user: parseNullableString(process.env['chimp.user'] || process.env.SAUCE_USERNAME),
key: parseNullableString(process.env['chimp.key'] || process.env.SAUCE_ACCESS_KEY),
host: parseNullableString(process.env['chimp.host']),
port: parseNullableInteger(process.env['chimp.port']),
logLevel: booleanHelper.isTruthy(process.env['chimp.debug']) ?
'verbose' : webdriverioConfigOptions.logLevel,
sync: parseBoolean(process.env['chimp.sync']),
}
);
global.sessionManager = new SessionFactory(Object.assign(
_.pick(webdriverioOptions, 'host', 'port', 'user', 'key'),
{
browser: webdriverioOptions.desiredCapabilities.browserName,
deviceName: webdriverioOptions.desiredCapabilities.deviceName,
}
));
if (booleanHelper.isTruthy(process.env['chimp.watch'])) {
webdriverioOptions.desiredCapabilities.applicationCacheEnabled = false;
}
log.debug('[chimp][helper] webdriverioOptions are ', JSON.stringify(webdriverioOptions));
let remoteSession;
if (parseNullableInteger(process.env['CUCUMBER_BROWSERS'])) {
var options = _.clone(webdriverioOptions);
options.multiBrowser = true;
const multiremoteWebdriverIoOptions = {};
var _browsersTotal = parseNullableInteger(process.env['CUCUMBER_BROWSERS']);
for (var _browserIndex = 0; _browserIndex < _browsersTotal; _browserIndex++) {
multiremoteWebdriverIoOptions['browser' + _browserIndex] = _.clone(options);
}
remoteSession = wrapAsync(global.sessionManager.multiremote, global.sessionManager);
global.browser = remoteSession(multiremoteWebdriverIoOptions);
}
else {
remoteSession = wrapAsync(global.sessionManager.remote, global.sessionManager);
global.browser = remoteSession(webdriverioOptions);
}
global.browser.options = webdriverioOptions;
chaiAsPromised.transferPromiseness = global.browser.transferPromiseness;
};
var initSingleBrowser = function (browser) {
log.debug('[chimp][helper] init browser');
log.debug('[chimp][helper] init browser callback');
browser.screenshotsCount = 0;
browser.addCommand('capture', function (name, screenshotsPathPrefix) {
const screenshotsCountForFileName = `${(browser.screenshotsCount++)}_`;
let fileName = name.replace(/[ \\~#%&*{}/:<>?|"-]/g, '_');
const fileExtension = '.png';
const suggestedFileNameLength = screenshotsCountForFileName.length + fileName.length + fileExtension.length;
if (suggestedFileNameLength > 255) {
const numberOfCharactersToLeave = (fileName.length - (suggestedFileNameLength - 255));
fileName = fileName.substr(0, numberOfCharactersToLeave);
}
const fullFileName = `${screenshotsCountForFileName}${fileName}${fileExtension}`;
let screenshotsPath = process.env['chimp.screenshotsPath'];
if (screenshotsPathPrefix) {
screenshotsPath = path.join(screenshotsPathPrefix, screenshotsPath);
}
fs.mkdirsSync(screenshotsPath);
var ssPath = path.join(screenshotsPath, fullFileName);
log.debug('[chimp][helper] saving screenshot to', ssPath);
this.saveScreenshot(ssPath, false);
log.debug('[chimp][helper] saved screenshot to', ssPath);
});
if (process.env['chimp.browser'] === 'phantomjs') {
browser.setViewportSizeSync({
width: process.env['chimp.phantom_w'] ? parseInt(process.env['chimp.phantom_w']):1280,
height: process.env['chimp.phantom_h'] ? parseInt(process.env['chimp.phantom_h']):1024
});
}
};
var initBrowser = function () {
log.debug('[chimp][hooks] init browser');
var browser = global.browser;
log.debug('[chimp][hooks] init browser callback');
if (browser.instances) {
browser.instances.forEach(function (singleBrowser) {
const desiredCapabilities = singleBrowser.initSync();
singleBrowser.desiredCapabilities = desiredCapabilities;
initSingleBrowser(singleBrowser);
});
}
else {
const desiredCapabilities = browser.initSync();
browser.desiredCapabilities = desiredCapabilities;
initSingleBrowser(browser);
}
};
var addServerExecute = function (ddpInstance) {
ddpInstance.execute = function (func) {
var args = Array.prototype.slice.call(arguments, 1);
var result;
var timeout = parseInt(process.env['chimp.serverExecuteTimeout']) || 10000;
setTimeout(function() {
if (!result) {
throw new Error('[chimp] server.execute timeout after ' + timeout + 'ms');
}
}, timeout);
try {
result = ddpInstance.call('xolvio/backdoor', func.toString(), args);
} catch (exception) {
if (exception.error === 404) {
throw new Error('[chimp] You need to install xolvio:backdoor in your meteor app before you can use server.execute()');
} else {
throw exception;
}
}
if (result.error) {
var error = new Error('Error in server.execute' + result.error.message);
error.stack += '\n' + result.error.stack.replace(/ {4}at/g, ' @');
throw error;
} else {
return result.value;
}
};
};
var setupDdp = function () {
log.debug('[chimp][helper] setup DDP');
if (process.env['chimp.ddp0']) {
try {
log.debug('[chimp][helper] connecting via DDP to', process.env['chimp.ddp0']);
global.ddp.connectSync();
addServerExecute(global.ddp);
for(let i = 0; i < global.ddp.instances.length; i++) {
log.debug('[chimp][helper] connecting via DDP to ' + global.ddp.instances[i]._original.host + ':' + global.ddp.instances[i]._original.port);
global.ddp.instances[i].connectSync();
addServerExecute(global.ddp.instances[i]);
}
log.debug('[chimp][helper] connecting via DDP had no error');
} catch (error) {
let errorMessage = error;
if (_.isObject(error)) {
if (error.code === 'ECONNREFUSED') {
log.error('[chimp][helper] Cannot connect to Meteor. Please check if your application is up and running on ' + error.address + ' port ' + error.port);
}
errorMessage = error.code;
}
log.error('[chimp][helper] connecting via DDP error', errorMessage);
global.browser.endSync();
process.exit(1);
}
} else {
var noDdp = function () {
expect('DDP Not Connected').to.equal('', 'You tried to use a DDP connection but it' +
' has not been configured. Be sure to pass --ddp=<host>');
};
global.ddp0 = {
call: noDdp,
apply: noDdp,
execute: noDdp
};
log.debug('[chimp][helper] DDP not required');
}
};
try {
setupBrowser();
initBrowser();
if (booleanHelper.isTruthy(process.env['chimp.ddp0'])) {
setupDdp();
}
} catch (error) {
log.error('[chimp][helper] setupBrowserAndDDP had error');
log.error(error);
log.error(error.stack);
exit(2);
}
},
init: function () {
this.setupGlobals();
this.createGlobalAliases();
}
};
global.chimpHelper = chimpHelper;
module.exports = chimpHelper;