Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC: browser restart #133

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions conf/integration.profile.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ exports.config = {
/* used to overcome issues due to pending async work that was started before the waitForUI5 was injected */
wait: '3000'
},


// // after suite, not like protractor's after test
// restartBrowserBetweenSuites: true,

takeScreenshot: {
onExpectFailure: true,
onExpectSuccess: true,
Expand Down
2 changes: 1 addition & 1 deletion driverVersions.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"chrome": {
"latest": 76
"latest": 78
}
}
2 changes: 1 addition & 1 deletion spec/directConnectionProvider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('DirectConnectionProvider', function() {
it('Should not download chromedriver if already available', function (done) {
var version = directConnectionProvider._downloadBinary(testBinaries.chromedriverExisting);
version.then(function (result) {
expect(result).toBe(__dirname + '/directConnectionProvider/mockChromeDriver.js');
expect(result).toBe(path.join(__dirname, '/directConnectionProvider/mockChromeDriver.js'));
done();
})
});
Expand Down
102 changes: 102 additions & 0 deletions src/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// testrunner
// navigation
var _ = require('lodash');
var clientsidescripts = require('./scripts/clientsidescripts');
var ClassicalWaitForUI5 = require('./scripts/classicalWaitForUI5');
var AUTH_CONFIG_NAME = 'auth';

module.exports = function (browser, config, logger) {

// attach new function to the global browser object, or override existing ones
function augmentBrowser() {
// used in protractor for many scripts and notably for waitForAngular
// override with added logging
browser.executeAsyncScript_ = executeAsyncScript_(browser.executeAsyncScript_);

browser.executeAsyncScriptHandleErrors = executeAsyncScriptHandleErrors;

browser.get = function (sUrl, vOptions) {
return browser.testrunner.navigation.to(sUrl, _.pick(vOptions, AUTH_CONFIG_NAME));
};

browser.setViewportSize = setViewportSize;

browser.loadUI5Dependencies = function () {
return browser._loadUI5Dependencies().then(function () {
return browser.waitForAngular();
});
};

var waitForUI5Timeout = getWaitForUI5Timeout(config);

browser._loadUI5Dependencies = function () {
return browser.executeAsyncScriptHandleErrors('loadUI5Dependencies', {
waitForUI5Timeout: waitForUI5Timeout,
waitForUI5PollingInterval: config.timeouts.waitForUI5PollingInterval,
ClassicalWaitForUI5: ClassicalWaitForUI5,
useClassicalWaitForUI5: config.useClassicalWaitForUI5
});
};
}

/*
* (internal) definitions
*/

function executeAsyncScript_(originalExecuteAsyncScript_) {
return function () {
var code = arguments[0];
var scriptName = arguments[1];
var params = arguments[2];
// log script execution
logger.trace('Execute async script: ' + scriptName + ' with params: ' + JSON.stringify(params) + ' with code: \n' + JSON.stringify(code));
//call original function in its context
return originalExecuteAsyncScript_.apply(browser, arguments)
.then(function(res) {
logger.trace('Async script: ' + scriptName + ' result: ' + JSON.stringify(res));
return res;
},function(error) {
logger.trace('Async script: ' + scriptName + ' error: ' + JSON.stringify(error));
throw error;
});
};
}

function getWaitForUI5Timeout (config) {
var ui5SyncDelta = config.timeouts && config.timeouts.waitForUI5Delta;
return ui5SyncDelta > 0 ? (config.timeouts.allScriptsTimeout - ui5SyncDelta) : 0;
}

function executeAsyncScriptHandleErrors(scriptName, params) {
var code = clientsidescripts[scriptName];
logger.debug('Execute async script: ' + scriptName + ' with params: ' + JSON.stringify(params));
logger.trace('Execute async script code: \n' + JSON.stringify(code));
params = params || {};
return browser.executeAsyncScript(code,params)
.then(function (res) {
if (res.log) {
logger.debug('Async script: ' + scriptName + ' logs: \n' + res.log);
}
if (res.error) {
logger.debug('Async script: ' + scriptName + ' error: ' + JSON.stringify(res.error));
throw new Error(scriptName + ': ' + res.error);
}
logger.debug('Async script: ' + scriptName + ' result: ' + JSON.stringify(res.value));
return res.value;
});
}

function setViewportSize(viewportSize) {
return browser.executeScriptWithDescription(clientsidescripts.getWindowToolbarSize, 'browser.setViewportSize').then(function (toolbarSize) {
browser.driver.manage().window().setSize(viewportSize.width * 1 + toolbarSize.width, viewportSize.height * 1 + toolbarSize.height); // convert to integer implicitly
});
}

/*
* expose public
*/

return {
augmentBrowser: augmentBrowser
};
};
55 changes: 55 additions & 0 deletions src/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
var plugins = [];

module.exports = function (moduleLoader) {
plugins = moduleLoader.loadModule('plugins');

function loadJasminePlugins() {
return {
suiteStarted: function(jasmineSuite){
callPlugins('suiteStarted', [{name:jasmineSuite.description}]);
},
specStarted: function(jasmineSpec){
callPlugins('specStarted', [{name:jasmineSpec.description}]);
},
specDone: function(jasmineSpec){
callPlugins('specDone', [{name:jasmineSpec.description}]);
},
suiteDone: function(jasmineSuite){
callPlugins('suiteDone', [{name:jasmineSuite.description}]);
}
};
}

function loadRunnerPlugins() {
return [{
inline: {
setup: function() {
callPlugins('setup');
},
onPrepare: function() {
callPlugins('onPrepare');
},
teardown: function() {
callPlugins('teardown');
}
}
}];
}

function callPlugins(method, pluginData) {
// call a method on every plugin, granted that it is defined
return Promise.all(
plugins.map(function (plugin) {
if (plugin[method]) {
return plugin[method].apply(plugin, pluginData);
}
})
);
}

return {
loadJasminePlugins: loadJasminePlugins,
loadRunnerPlugins: loadRunnerPlugins,
callPlugins: callPlugins
};
};
136 changes: 136 additions & 0 deletions src/testrunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
var _ = require('lodash');
var clientsidescripts = require('./scripts/clientsidescripts');
var AUTH_CONFIG_NAME = 'auth';

module.exports = function (browser, config, logger, moduleLoader, statisticCollector) {
// publish configs on protractor's browser object
browser.testrunner = {
config: config
};

// expose navigation helpers to tests
browser.testrunner.navigation = {
to: function (url, authConfig) {
var auth;
if (_.isPlainObject(_.get(authConfig, AUTH_CONFIG_NAME)) && !_.isEmpty(authConfig[AUTH_CONFIG_NAME])) {
// use configured authentication
auth = authConfig;
} else {
// use default plain authentication
auth = AUTH_CONFIG_NAME;
}

var authenticator = moduleLoader.loadNamedModule(auth, [statisticCollector]);

// open page and login
browser.controlFlow().execute(function () {
logger.info('Opening: ' + url);
});
authenticator.get(url);

// handle pageLoading options
if (config.pageLoading) {

// reload the page immediately if required
if (config.pageLoading.initialReload) {
browser.controlFlow().execute(function () {
logger.debug('Initial page reload requested');
});
browser.driver.navigate().refresh();
}

// wait some time after page is loaded
if (config.pageLoading.wait) {
var wait = config.pageLoading.wait;
if (_.isString(wait)) {
wait = parseInt(wait, 10);
}

browser.controlFlow().execute(function () {
logger.debug('Initial page load wait: ' + wait + 'ms');
});
browser.sleep(wait);
}
}

// load waitForUI5 logic on client and
// ensure app is fully loaded before starting the interactions
browser.loadUI5Dependencies();

// log UI5 version
return browser.executeScriptWithDescription(clientsidescripts.getUI5Version, 'browser.getUI5Version').then(function (versionInfo) {
logger.info('UI5 Version: ' + versionInfo.version);
logger.info('UI5 Timestamp: ' + versionInfo.buildTimestamp);
});
},

waitForRedirect: function(targetUrl){
// ensure page is fully loaded - wait for window.url to become the same as requested
return browser.driver.wait(function () {
return browser.driver.executeScript(function () {
return window.location.href;
}).then(function (currentUrl) {
logger.debug('Waiting for redirect to complete, current url: ' + currentUrl);

// match only host/port/path as app could manipulate request args and fragment
var currentUrlMathes = currentUrl.match(/([^\?\#]+)/);
if (currentUrlMathes == null || !currentUrlMathes[1] || currentUrlMathes[1] == '') {
throw new Error('Could not parse current url: ' + currentUrl);
}
var currentUrlHost = currentUrlMathes[1];
// strip trailing slashe
if(currentUrlHost.charAt(currentUrlHost.length - 1) == '/') {
currentUrlHost = currentUrlHost.slice(0, -1);
}
// handle string and regexps
if (_.isString(targetUrl)) {
var targetUrlMatches = targetUrl.match(/([^\?\#]+)/);
if (targetUrlMatches == null || !targetUrlMatches[1] || targetUrlMatches[1] == '') {
throw new Error('Could not parse target url: ' + targetUrl);
}
var targetUrlHost = targetUrlMatches[1];
// strip trailing slash
if(targetUrlHost.charAt(targetUrlHost.length - 1) == '/') {
targetUrlHost = targetUrlHost.slice(0, -1);
}
return currentUrlHost === targetUrlHost;
} else if (_.isRegExp(targetUrl)) {
return targetUrl.test(currentUrlHost);
} else {
throw new Error('Could not match target url that is neither string nor regexp');
}
});
}, browser.getPageTimeout - 100,'Waiting for redirection to complete, target url: ' + targetUrl);
// 10ms delta is necessary or webdriver crashes and the process stops without exit status
}
};

// set meta data
browser.testrunner.currentSuite = {
set meta(value) {
beforeAll(function(){
browser.controlFlow().execute(function () {
browser.testrunner.currentSuite._meta = value;
});
});
},
get meta() {
return {
set controlName(value){
browser.testrunner.currentSuite.meta = {controlName: value};
}
};
}
};
browser.testrunner.currentSpec = {
set meta(value) {
browser.controlFlow().execute(function () {
browser.testrunner.currentSpec._meta = value;
});
},
get meta() {
return browser.testrunner.currentSpec._meta;
}
};

};
Loading