WWW-Mechanize-PhantomJS
view release on metacpan or search on metacpan
lib/WWW/Mechanize/PhantomJS/ghostdriver/session.js view on Meta::CPAN
"platform" : ghostdriver.system.os.name + '-' + ghostdriver.system.os.version + '-' + ghostdriver.system.os.architecture,
"javascriptEnabled" : true,
"takesScreenshot" : true,
"handlesAlerts" : false, //< TODO
"databaseEnabled" : false, //< TODO
"locationContextEnabled" : false, //< TODO Target is 1.1
"applicationCacheEnabled" : false, //< TODO Support for AppCache (?)
"browserConnectionEnabled" : false, //< TODO
"cssSelectorsEnabled" : true,
"webStorageEnabled" : false, //< TODO support for LocalStorage/SessionStorage
"rotatable" : false, //< TODO Target is 1.1
"acceptSslCerts" : false, //< TODO
"nativeEvents" : true, //< TODO Only some commands are Native Events currently
"unhandledPromptBehavior" : null,
"proxy" : { //< TODO Support more proxy options - PhantomJS does allow setting from command line
"proxyType" : _const.PROXY_TYPES.DIRECT
},
"webSecurityEnabled" : true
},
_negotiatedCapabilities = {
"browserName" : _defaultCapabilities.browserName,
"version" : _defaultCapabilities.version,
"driverName" : _defaultCapabilities.driverName,
"driverVersion" : _defaultCapabilities.driverVersion,
"platform" : _defaultCapabilities.platform,
"javascriptEnabled" : _defaultCapabilities.javascriptEnabled,
"takesScreenshot" : typeof(desiredCapabilities.takesScreenshot) === "undefined" ?
_defaultCapabilities.takesScreenshot :
desiredCapabilities.takesScreenshot,
"handlesAlerts" : _defaultCapabilities.handlesAlerts,
"databaseEnabled" : _defaultCapabilities.databaseEnabled,
"locationContextEnabled" : _defaultCapabilities.locationContextEnabled,
"applicationCacheEnabled" : _defaultCapabilities.applicationCacheEnabled,
"browserConnectionEnabled" : _defaultCapabilities.browserConnectionEnabled,
"cssSelectorsEnabled" : _defaultCapabilities.cssSelectorsEnabled,
"webStorageEnabled" : _defaultCapabilities.webStorageEnabled,
"rotatable" : _defaultCapabilities.rotatable,
"acceptSslCerts" : _defaultCapabilities.acceptSslCerts,
"nativeEvents" : _defaultCapabilities.nativeEvents,
"unhandledPromptBehavior" : typeof(desiredCapabilities.unhandledPromptBehavior) === "undefined" ?
_defaultCapabilities.unhandledPromptBehavior :
desiredCapabilities.unhandledPromptBehavior,
"proxy" : typeof(desiredCapabilities.proxy) === "undefined" ?
_defaultCapabilities.proxy :
desiredCapabilities.proxy,
"webSecurityEnabled" : typeof(desiredCapabilities.webSecurityEnabled) === "undefined" ?
_defaultCapabilities.webSecurityEnabled :
desiredCapabilities.webSecurityEnabled
},
// NOTE: This value is needed for Timeouts Upper-bound limit.
// "setTimeout/setInterval" accept only 32 bit integers, even though Number are all Doubles (go figure!)
// Interesting details here: {@link http://stackoverflow.com/a/4995054}.
_max32bitInt = Math.pow(2, 31) -1, //< Max 32bit Int
_timeouts = {
"script" : 30000,
"implicit" : 0,
"page load" : 300000,
},
_windows = {}, //< NOTE: windows are "webpage" in Phantom-dialect
_currentWindowHandle = null,
_cookieJar = require('cookiejar').create(),
_id = require("./third_party/uuid.js").v1(),
_inputs = ghostdriver.Inputs(),
_capsPageSettingsPref = "phantomjs.page.settings.",
_capsPageCustomHeadersPref = "phantomjs.page.customHeaders.",
_capsPageZoomFactor = "phantomjs.page.zoomFactor",
_capsPageBlacklistPref = "phantomjs.page.blacklist",
_capsPageWhitelistPref = "phantomjs.page.whitelist",
_capsUnhandledPromptBehavior = "unhandledPromptBehavior",
_capsLoggingPref = "loggingPrefs",
_capsBrowserLoggerPref = "OFF",
_capsHarLoggerPref = "OFF",
_pageBlacklistFilter,
_pageWhitelistFilter,
_capsPageSettingsProxyPref = "proxy",
_pageSettings = {},
_pageZoomFactor = 1,
_additionalPageSettings = {
resourceTimeout: null,
userName: null,
password: null
},
_pageCustomHeaders = {},
_log = ghostdriver.logger.create("Session [" + _id + "]"),
k, settingKey, headerKey, proxySettings;
var
/**
* Parses proxy JSON object and return proxy settings for phantom
*
* @param proxyCapability proxy JSON Object: @see https://code.google.com/p/selenium/wiki/DesiredCapabilities
*/
_getProxySettingsFromCapabilities = function(proxyCapability) {
var proxySettings = {};
if (proxyCapability["proxyType"].toLowerCase() == _const.PROXY_TYPES.MANUAL) { //< TODO: support other options
if (proxyCapability["httpProxy"] !== "null") { //< TODO: support other proxy types
var urlParts = proxyCapability["httpProxy"].split(':');
proxySettings["ip"] = urlParts[0];
proxySettings["port"] = urlParts[1];
proxySettings["proxyType"] = "http";
proxySettings["user"] = "";
proxySettings["password"] = "";
return proxySettings;
}
}
return proxySettings;
};
// Searching for `phantomjs.settings.* and phantomjs.customHeaders.* phantomjs.page.zoomFactor` in the Desired Capabilities and merging with the Negotiated Capabilities
// Possible values for settings: @see http://phantomjs.org/api/webpage/property/settings.html.
// Possible values for customHeaders: @see http://phantomjs.org/api/webpage/property/custom-headers.html.
for (k in desiredCapabilities) {
if (k.indexOf(_capsPageSettingsPref) === 0) {
settingKey = k.substring(_capsPageSettingsPref.length);
if (settingKey.length > 0) {
_negotiatedCapabilities[k] = desiredCapabilities[k];
_pageSettings[settingKey] = desiredCapabilities[k];
}
}
if (k.indexOf(_capsPageCustomHeadersPref) === 0) {
headerKey = k.substring(_capsPageCustomHeadersPref.length);
lib/WWW/Mechanize/PhantomJS/ghostdriver/session.js view on Meta::CPAN
var _unhandledPromptBehavior = _negotiatedCapabilities["unhandledPromptBehavior"],
confirmValue;
if (_unhandledPromptBehavior !== "accept" && _unhandledPromptBehavior !== "dismiss") {
return;
}
_log.info("_decoratePromptBehavior");
newPage.onAlert = function(msg) {
_log.debug("ALERT: " + msg);
}
newPage.onPrompt = function(msg, val) {
_log.debug("PROMPT: " + msg);
return val;
}
if (_unhandledPromptBehavior === "accept") {
confirmValue = true;
} else {
confirmValue = false;
}
newPage.onConfirm = function(msg) {
_log.debug("CONFIRM: " + msg);
return confirmValue;
}
},
// Add any new page to the "_windows" container of this session
_addNewPage = function(newPage) {
_log.debug("_addNewPage");
// decorate the new Window/Page
newPage = _decorateNewWindow(newPage);
// set session-specific CookieJar
newPage.cookieJar = _cookieJar;
// store the Window/Page by WindowHandle
_windows[newPage.windowHandle] = newPage;
},
// Delete any closing page from the "_windows" container of this session
_deleteClosingPage = function(closingPage) {
_log.debug("_deleteClosingPage");
// Need to be defensive, as the "closing" can be cause by Client Commands
if (_windows.hasOwnProperty(closingPage.windowHandle)) {
delete _windows[closingPage.windowHandle];
}
},
_decorateNewWindow = function(page) {
var k;
// Decorating:
// 0. Pages lifetime will be managed by Driver, not the pages
page.ownsPages = false;
// 1. Random Window Handle
page.windowHandle = require("./third_party/uuid.js").v1();
// 2. Initialize the One-Shot Callbacks
page["onUrlChanged"] = _oneShotCallbackFactory(page, "onUrlChanged");
page["onFilePicker"] = _oneShotCallbackFactory(page, "onFilePicker");
page["onCallback"] = _oneShotCallbackFactory(page, "onCallback");
// 3. Utility methods
page.execFuncAndWaitForLoad = _execFuncAndWaitForLoadDecorator;
page.setOneShotCallback = _setOneShotCallbackDecorator;
page.waitIfLoading = _waitIfLoadingDecorator;
// 4. Store every newly created page
page.onPageCreated = _addNewPage;
// 5. Remove every closing page
page.onClosing = _deleteClosingPage;
// 6. Applying Page settings received via capabilities
for (k in _pageSettings) {
// Apply setting only if really supported by PhantomJS
if (page.settings.hasOwnProperty(k) || _additionalPageSettings.hasOwnProperty(k)) {
page.settings[k] = _pageSettings[k];
}
}
// 7. Applying Page custom headers received via capabilities
// fix custom headers per ariya/phantomjs#13621 and detro/ghostdriver#489
if ("Accept-Encoding" in _pageCustomHeaders) {
_log.warn("Custom header \"Accept-Encoding\" is not supported. see ariya/phantomjs#13621");
delete _pageCustomHeaders["Accept-Encoding"]
}
page.customHeaders = _pageCustomHeaders;
// 8. Applying Page zoomFactor
page.zoomFactor = _pageZoomFactor;
// 9. Log Page internal errors
page.browserLog = ghostdriver.webdriver_logger.create(_capsBrowserLoggerPref);
page.onError = function(errorMsg, errorStack) {
var stack = '';
// Prep the "stack" part of the message
errorStack.forEach(function (stackEntry, idx, arr) {
stack += " " //< a bit of indentation
+ (stackEntry.function || "(anonymous function)")
+ " (" + stackEntry.file + ":" + stackEntry.line + ")";
stack += idx < arr.length - 1 ? "\n" : "";
});
// Log as error
_log.error("page.onError", "msg: " + errorMsg);
_log.error("page.onError", "stack:\n" + stack);
// Register as part of the "browser" log
page.browserLog.push(_createLogEntry("WARNING", errorMsg + "\n" + stack));
};
// 10. Log Page console messages
page.onConsoleMessage = function(msg, lineNum, sourceId) {
// Log as debug
lib/WWW/Mechanize/PhantomJS/ghostdriver/session.js view on Meta::CPAN
"level" : level,
"message" : message,
"timestamp" : (new Date()).getTime()
};
},
/**
* Is any window in this Session Loading?
* @returns "true" if at least 1 window is loading.
*/
_isLoading = function() {
var wHandle, _window;
for (wHandle in _windows) {
_window = _windows[wHandle];
if (_window._onLoadLatch || (_window.loadingProgress > 0 && _window.loadingProgress < 100)) {
return true;
}
}
return false;
},
/**
* According to log method specification we have to clear log after each page refresh.
* https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/log
* @param {Object} page
* @private
*/
_clearPageLog = function (page) {
page.resources.log = [];
page.browserLog.log = [];
},
_getWindow = function(handleOrName) {
var page = null,
k;
if (_isValidWindowHandle(handleOrName)) {
// Search by "handle"
page = _windows[handleOrName];
} else {
// Search by "name"
for (k in _windows) {
if (_windows[k].windowName === handleOrName) {
page = _windows[k];
break;
}
}
}
return page;
},
_init = function() {
var page;
// Ensure a Current Window is available, if it's found to be `null`
if (_currentWindowHandle === null) {
// Create the first Window/Page
page = require("webpage").create();
// Decorate it with listeners and helpers
page = _decorateNewWindow(page);
// set session-specific CookieJar
page.cookieJar = _cookieJar;
// Make the new Window, the Current Window
_currentWindowHandle = page.windowHandle;
// Store by WindowHandle
_windows[_currentWindowHandle] = page;
}
},
_getCurrentWindow = function() {
var page = null;
if (_windows.hasOwnProperty(_currentWindowHandle)) {
page = _windows[_currentWindowHandle];
}
// TODO Handle "null" cases throwing a "no such window" error
return page;
},
_switchToWindow = function(handleOrName) {
var page = _getWindow(handleOrName);
if (page !== null) {
// Switch current window and return "true"
_currentWindowHandle = page.windowHandle;
// Switch to the Main Frame of that window
page.switchToMainFrame();
return true;
}
// Couldn't find the window, so return "false"
return false;
},
_closeCurrentWindow = function() {
if (_currentWindowHandle !== null) {
return _closeWindow(_currentWindowHandle);
}
return false;
},
_closeWindow = function(handleOrName) {
var page = _getWindow(handleOrName),
handle;
if (page !== null) {
handle = page.windowHandle;
_windows[handle].close();
delete _windows[handle];
return true;
}
return false;
},
_getWindowsCount = function() {
return Object.keys(_windows).length;
lib/WWW/Mechanize/PhantomJS/ghostdriver/session.js view on Meta::CPAN
},
_getTimeout = function(type) {
return _timeouts[type];
},
_getScriptTimeout = function() {
return _getTimeout(_const.TIMEOUT_NAMES.SCRIPT);
},
_getImplicitTimeout = function() {
return _getTimeout(_const.TIMEOUT_NAMES.IMPLICIT);
},
_getPageLoadTimeout = function() {
return _getTimeout(_const.TIMEOUT_NAMES.PAGE_LOAD);
},
_setScriptTimeout = function(ms) {
_setTimeout(_const.TIMEOUT_NAMES.SCRIPT, ms);
},
_setImplicitTimeout = function(ms) {
_setTimeout(_const.TIMEOUT_NAMES.IMPLICIT, ms);
},
_setPageLoadTimeout = function(ms) {
_setTimeout(_const.TIMEOUT_NAMES.PAGE_LOAD, ms);
},
_executePhantomJS = function(page, script, args) {
try {
var code = new Function(script);
return code.apply(page, args);
} catch (e) {
return e;
}
},
_aboutToDelete = function() {
var k;
// Close current window first
_closeCurrentWindow();
// Releasing page resources and deleting the objects
for (k in _windows) {
_closeWindow(k);
}
// Release CookieJar resources
_cookieJar.close();
},
_getLog = function (type) {
var har, i, entry, attrName,
page, tmp, tmpResMap;
// Return "HAR" as Log Type "har"
if (type === _const.LOG_TYPES.HAR) {
har = require('./third_party/har.js');
page = _getCurrentWindow();
tmpResMap = {};
for (i = 0; i < page.resources.log.length; i++) {
entry = page.resources.log[i];
if (!tmpResMap[entry.id]) {
tmpResMap[entry.id] = {
id: entry.id,
request: null,
startReply: null,
endReply: null,
error: null
}
}
for (attrName in entry) {
tmpResMap[entry.id][attrName] = entry[attrName];
}
}
page.resources.log = [];
tmp = Object.keys(tmpResMap).sort();
for (i in tmp) {
page.resources.push(tmpResMap[tmp[i]]);
}
tmp = [];
tmp.push(_createLogEntry(
"INFO",
JSON.stringify(har.createHar(page, page.resources.log))));
page.resources.log = [];
return tmp;
}
// Return Browser Console Log
if (type === _const.LOG_TYPES.BROWSER) {
page = _getCurrentWindow();
tmp = page.browserLog.log;
page.browserLog.log = [];
return tmp;
}
// Return empty Log
return [];
},
_getLogTypes = function () {
var logTypes = [], k;
for (k in _const.LOG_TYPES) {
logTypes.push(_const.LOG_TYPES[k]);
}
return logTypes;
},
_getFrameOffset = function(page) {
return page.evaluate(function() {
var win = window,
offset = {top: 0, left: 0},
style,
rect;
( run in 0.735 second using v1.01-cache-2.11-cpan-39bf76dae61 )