siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
333 lines (239 loc) • 12.4 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Class('Siesta.Launcher.Runner.WebDriverNodeJS', {
isa : Siesta.Launcher.Runner.BaseRunner,
does : [
Siesta.Launcher.Runner.WebDriverNodeJS.CanLockXvfbDisplayFile
],
has : {
pagePollInterval : 1000,
resolutionCapName : 'resolution',
maxWorkers : 1,
capabilities : {
lazy : 'this.buildCapabilities'
}
},
methods : {
// this the proxy to be used by the browser
getBrowserProxyStr : function () {
var options = this.dispatcher.options
if (options.coverage && (options.sl || options.bs)) {
// for cloud setup with coverage enabled proxy configuration is passed as tunnel binary
// options, not set in Selenium
return null
} else {
return options.coverage ? '127.0.0.1:' + this.dispatcher.instrumentationProxyPort : this.launcher.optionsWrapper.getProxyHostPort()
}
},
buildWebDriverBuilder : function (xvfbLockResult) {
var launcher = this.launcher
var builder = new selenium.Builder().withCapabilities(this.getCapabilities())
var options = this.dispatcher.options
var displayNum = xvfbLockResult && xvfbLockResult.displayNum
var isHeadless = options.headless && options.headless != 'false'
if (options[ 'host' ]) {
// prepend potentially missing "http://" prefix in "constructURL"
var url = this.launcher.constructUrl(options[ 'host' ])
if (!/\/wd\/hub\s*$/i.test(url)) url += ':' + (options[ 'port' ] || 4444) + '/wd/hub'
builder.usingServer(url)
}
var browserArgs = options[ 'browser-arg' ]
if (options.browser == 'chrome') {
var chrome = require('selenium-webdriver/chrome')
var chromeOptions = new chrome.Options()
if (options.xvfb && launcher.isLinux) {
chromeOptions.setChromeBinaryPath(launcher.binDir + 'xvfb/chrome')
chromeOptions.addArguments('DISPLAY_NUM=' + displayNum)
}
if (options[ 'touch-events' ]) chromeOptions.addArguments('touch-events')
// chromeOptions.addArguments('disable-dev-shm-usage')
// chromeOptions.addArguments('no-sandbox')
if (isHeadless) chromeOptions.headless()
if (this.launcher.isWindows) chromeOptions.addArguments('disable-gpu')
for (var i = 0; i < browserArgs.length; i++) {
chromeOptions.addArguments(browserArgs[ i ])
}
var proxyStr = this.getBrowserProxyStr()
if (proxyStr) {
// proxy settings on the capabilities object are ignored by Chrome driver,
// should be set on ChromeOptions instead
chromeOptions.setProxy({
proxyType : 'manual',
ftpProxy : proxyStr,
httpProxy : proxyStr,
sslProxy : proxyStr,
noProxy : ''
});
}
builder.setChromeOptions(chromeOptions)
}
if (options.browser == 'firefox') {
var firefox = require('selenium-webdriver/firefox')
var firefoxOptions = new firefox.Options()
if (options.xvfb && launcher.isLinux) {
firefoxOptions.addArguments('DISPLAY_NUM=' + displayNum)
firefoxOptions.setBinary(launcher.binDir + 'xvfb/firefox')
}
for (i = 0; i < browserArgs.length; i++) {
firefoxOptions.addArguments(browserArgs[ i ])
}
if (isHeadless) firefoxOptions.headless()
if (options[ 'firefox-profile' ]) firefoxOptions.setProfile(options[ 'firefox-profile' ])
var prefs = options[ 'ff-pref'] || []
for (i = 0; i < prefs.length; i++) {
var match = /(.*?)=(.*)/.exec(prefs[ i ])
if (match) {
var value
try {
value = JSON.parse(match[ 2 ])
} catch (e) {
value = match[ 2 ]
}
firefoxOptions.setPreference(match[ 1 ], value)
}
}
firefoxOptions.setPreference('security.insecure_password.ui.enabled', false)
firefoxOptions.setPreference('security.insecure_field_warning.contextual.enabled', false)
builder.setFirefoxOptions(firefoxOptions)
}
if (options.browser == 'internet explorer') {
// the call to "setIeOptions" changes the "platform" capability to "WINDOWS"
// (as implemented in the "selenium-webdriver")
// this breaks the SL testing (which requires "platform" to be set to "WINDOWS 7")
// only supporting for local testing for now, until someone complains
if (!options.host && browserArgs.length) {
var ie = require('selenium-webdriver/ie')
var ieOptions = new ie.Options()
if (browserArgs.length) ieOptions.forceCreateProcessApi(true)
for (i = 0; i < browserArgs.length; i++) {
ieOptions.addArguments(browserArgs[ i ])
}
// this call changes the "platform" capability to "WINDOWS" (as implemented in the "selenium-webdriver")
builder.setIeOptions(ieOptions)
}
}
if (options.browser == 'MicrosoftEdge') {
// var edge = require('selenium-webdriver/edge')
// var edgeOptions = new edge.Options()
//
// edgeOptions.setPageLoadStrategy('normal')
//
// // this call changes the "platform" capability to "WINDOWS" (as implemented in the "selenium-webdriver")
// builder.setEdgeOptions(edgeOptions)
}
var proxyStr = this.launcher.optionsWrapper.getProxyHostPort()
if (proxyStr) {
// this is a proxy to use for connection to the remote WebDriver instance,
// NOT the proxy, which will be used by the browser
builder.usingWebDriverProxy('http://' + proxyStr)
}
return builder
},
buildCapabilities : function () {
var options = this.dispatcher.options
var capabilities = new selenium.Capabilities()
var width = options.width || Siesta.Launcher.Page.WebDriverNodeJS.prototype.width
var height = options.height || Siesta.Launcher.Page.WebDriverNodeJS.prototype.height
capabilities.set(this.resolutionCapName, width + 'x' + height)
// MS Edge driver chokes on the `acceptInsecureCerts` capability
if (options.browser != 'MicrosoftEdge' && options.browser != 'internet explorer' && options.browser != 'safari') {
// accept invalid /untrusted certificates, which is common thing during development
capabilities.set(selenium.Capability.ACCEPT_INSECURE_TLS_CERTS, true) // generic webdriver
// some backward-compat name? required for browserstack
capabilities.set('acceptSslCerts', true)
}
var caps = options.cap
for (var i = 0; i < caps.length; i++) {
var match = /(.*?)=(.*)/.exec(caps[ i ])
if (match) {
var value
var valueStr = match[ 2 ] || ''
try {
value = valueStr == '' ? '' : JSON.parse(valueStr)
} catch (e) {
value = valueStr
}
capabilities.set(match[ 1 ] || '', value)
}
}
// intentially overwrite any user-provided "browserName" which has been normalized
capabilities.set('browserName', options.browser)
var proxyStr = this.getBrowserProxyStr()
if (proxyStr) {
// oddly enough this setting is ignored by Chrome driver, instead the one from the ChromeOptions is used
capabilities.setProxy({
proxyType : 'manual',
ftpProxy : proxyStr,
httpProxy : proxyStr,
sslProxy : proxyStr
});
}
return capabilities
},
// promised method
createDriverInstance : function (builder, capabilities, xvfbLockResult, level) {
level = level || 0
var options = this.dispatcher.options
var me = this
this.debug("Trying to create a WebDriver instance for browser: " + options.browser)
var driver = builder.build()
return driver.getSession().then(function () {
me.debug("WebDriver instantiated successfully")
var config = {
runner : me,
launcher : me.launcher,
dispatcher : me.dispatcher,
pollInterval : me.pagePollInterval,
driver : driver,
xvfbLockResult : xvfbLockResult
}
if (options.width) config.width = options.width
if (options.height) config.height = options.height
return new Siesta.Launcher.Page.WebDriverNodeJS(config)
}, function (e) {
me.debug("WebDriver instantiation failed: " + options.browser + ", level : " + level)
me.debug("Failed with: " + e)
var canTryToRepeat = me.onWebDriverInstatiationException(e, builder, capabilities)
// try to instantiate the driver 3 times, then throw exception
if (level < 2 && canTryToRepeat) {
me.debug("Trying again")
return me.createDriverInstance(builder, capabilities, xvfbLockResult, level + 1)
} else {
xvfbLockResult && xvfbLockResult.release()
throw e
}
})
},
onWebDriverInstatiationException : function (e, builder, capabilities) {
if (/required parameter 'capabilities'/.test(e)) {
const safari = require('selenium-webdriver/safari')
builder.usingServer(new safari.ServiceBuilder().addArguments('--legacy').build().start())
}
return true
},
createPage : function (callback) {
var me = this
var options = this.dispatcher.options
var cont
if (options.xvfb) {
cont = this.lockXvfbFile()
} else
cont = Promise.resolve()
cont.then(function (xvfbLockResult) {
var capabilities = me.getCapabilities()
var builder = me.buildWebDriverBuilder(xvfbLockResult)
me.createDriverInstance(builder, capabilities, xvfbLockResult).then(function (page) {
callback(null, page)
}, function (e) {
callback(e, null)
})
}, function (e) {
callback(e, null)
})
}
}
})