diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-11-16 01:59:39 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-11-16 02:00:31 +0100 |
commit | bd65bb67e25a79b019d745b7262b2008ce2adb15 (patch) | |
tree | 89e1b032103a63737f1a703e6a943832ef261704 /node_modules/selenium-webdriver/safari.js | |
parent | f91466595b651721690133f58ab37f977539e95b (diff) |
incrementally verify denoms
The denominations are not stored in a separate object store.
Diffstat (limited to 'node_modules/selenium-webdriver/safari.js')
-rw-r--r-- | node_modules/selenium-webdriver/safari.js | 499 |
1 files changed, 12 insertions, 487 deletions
diff --git a/node_modules/selenium-webdriver/safari.js b/node_modules/selenium-webdriver/safari.js index bbfff06e8..97d512bc7 100644 --- a/node_modules/selenium-webdriver/safari.js +++ b/node_modules/selenium-webdriver/safari.js @@ -17,452 +17,21 @@ /** * @fileoverview Defines a WebDriver client for Safari. - * - * - * __Testing Older Versions of Safari__ - * - * To test versions of Safari prior to Safari 10.0, you must install the - * [latest version](http://selenium-release.storage.googleapis.com/index.html) - * of the SafariDriver browser extension; using Safari for normal browsing is - * not recommended once the extension has been installed. You can, and should, - * disable the extension when the browser is not being used with WebDriver. - * - * You must also enable the use of legacy driver using the {@link Options} class. - * - * let options = new safari.Options() - * .useLegacyDriver(true); - * - * let driver = new (require('selenium-webdriver')).Builder() - * .forBrowser('safari') - * .setSafariOptions(options) - * .build(); */ 'use strict'; -const events = require('events'); -const fs = require('fs'); -const http = require('http'); -const path = require('path'); -const url = require('url'); -const util = require('util'); -const ws = require('ws'); - +const http = require('./http'); const io = require('./io'); -const exec = require('./io/exec'); -const isDevMode = require('./lib/devmode'); -const Capabilities = require('./lib/capabilities').Capabilities; -const Capability = require('./lib/capabilities').Capability; +const {Capabilities, Capability} = require('./lib/capabilities'); const command = require('./lib/command'); const error = require('./lib/error'); const logging = require('./lib/logging'); const promise = require('./lib/promise'); -const Session = require('./lib/session').Session; const Symbols = require('./lib/symbols'); const webdriver = require('./lib/webdriver'); const portprober = require('./net/portprober'); const remote = require('./remote'); -const http_ = require('./http'); - - -/** @const */ -const CLIENT_PATH = isDevMode - ? path.join(__dirname, - '../../../buck-out/gen/javascript/safari-driver/client.js') - : path.join(__dirname, 'lib/safari/client.js'); - - -/** @const */ -const LIBRARY_DIR = (function() { - if (process.platform === 'darwin') { - return path.join('/Users', process.env['USER'], 'Library/Safari'); - } else if (process.platform === 'win32') { - return path.join(process.env['APPDATA'], 'Apple Computer', 'Safari'); - } else { - return '/dev/null'; - } -})(); - - -/** @const */ -const SESSION_DATA_FILES = (function() { - if (process.platform === 'darwin') { - var libraryDir = path.join('/Users', process.env['USER'], 'Library'); - return [ - path.join(libraryDir, 'Caches/com.apple.Safari/Cache.db'), - path.join(libraryDir, 'Cookies/Cookies.binarycookies'), - path.join(libraryDir, 'Cookies/Cookies.plist'), - path.join(libraryDir, 'Safari/History.plist'), - path.join(libraryDir, 'Safari/LastSession.plist'), - path.join(libraryDir, 'Safari/LocalStorage'), - path.join(libraryDir, 'Safari/Databases') - ]; - } else if (process.platform === 'win32') { - var appDataDir = path.join(process.env['APPDATA'], - 'Apple Computer', 'Safari'); - var localDataDir = path.join(process.env['LOCALAPPDATA'], - 'Apple Computer', 'Safari'); - return [ - path.join(appDataDir, 'History.plist'), - path.join(appDataDir, 'LastSession.plist'), - path.join(appDataDir, 'Cookies/Cookies.plist'), - path.join(appDataDir, 'Cookies/Cookies.binarycookies'), - path.join(localDataDir, 'Cache.db'), - path.join(localDataDir, 'Databases'), - path.join(localDataDir, 'LocalStorage') - ]; - } else { - return []; - } -})(); - - -/** @typedef {{port: number, address: string, family: string}} */ -var Host; - - -/** - * A basic HTTP/WebSocket server used to communicate with the legacy SafariDriver - * browser extension. - */ -class Server extends events.EventEmitter { - constructor() { - super(); - var server = http.createServer(function(req, res) { - if (req.url === '/favicon.ico') { - res.writeHead(204); - res.end(); - return; - } - - var query = url.parse(/** @type {string} */(req.url)).query || ''; - if (query.indexOf('url=') == -1) { - var address = server.address() - var host = address.address + ':' + address.port; - res.writeHead( - 302, {'Location': 'http://' + host + '?url=ws://' + host}); - res.end(); - } - - fs.readFile(CLIENT_PATH, 'utf8', function(err, data) { - if (err) { - res.writeHead(500, {'Content-Type': 'text/plain'}); - res.end(err.stack); - return; - } - var content = '<!DOCTYPE html><body><script>' + data + '</script>'; - res.writeHead(200, { - 'Content-Type': 'text/html; charset=utf-8', - 'Content-Length': Buffer.byteLength(content, 'utf8'), - }); - res.end(content); - }); - }); - - var wss = new ws.Server({server: server}); - wss.on('connection', this.emit.bind(this, 'connection')); - - /** - * Starts the server on a random port. - * @return {!Promise<Host>} A promise that will resolve with the server host - * when it has fully started. - */ - this.start = function() { - if (server.address()) { - return Promise.resolve(server.address()); - } - return portprober.findFreePort('localhost').then(function(port) { - return promise.checkedNodeCall( - server.listen.bind(server, port, 'localhost')); - }).then(function() { - return server.address(); - }); - }; - - /** - * Stops the server. - * @return {!Promise} A promise that will resolve when the server has closed - * all connections. - */ - this.stop = function() { - return new Promise(fulfill => server.close(fulfill)); - }; - - /** - * @return {Host} This server's host info. - * @throws {Error} If the server is not running. - */ - this.address = function() { - var addr = server.address(); - if (!addr) { - throw Error('There server is not running!'); - } - return addr; - }; - } -} - - -/** - * @return {!Promise<string>} A promise that will resolve with the path - * to Safari on the current system. - */ -function findSafariExecutable() { - switch (process.platform) { - case 'darwin': - return Promise.resolve('/Applications/Safari.app/Contents/MacOS/Safari'); - - case 'win32': - var files = [ - process.env['PROGRAMFILES'] || '\\Program Files', - process.env['PROGRAMFILES(X86)'] || '\\Program Files (x86)' - ].map(function(prefix) { - return path.join(prefix, 'Safari\\Safari.exe'); - }); - return io.exists(files[0]).then(function(exists) { - return exists ? files[0] : io.exists(files[1]).then(function(exists) { - if (exists) { - return files[1]; - } - throw Error('Unable to find Safari on the current system'); - }); - }); - - default: - return Promise.reject( - Error('Safari is not supported on the current platform: ' + - process.platform)); - } -} - - -/** - * @param {string} serverUrl The URL to connect to. - * @return {!Promise<string>} A promise for the path to a file that Safari can - * open on start-up to trigger a new connection to the WebSocket server. - */ -function createConnectFile(serverUrl) { - return io.tmpFile({postfix: '.html'}).then(function(f) { - let contents = - `<!DOCTYPE html><script>window.location = "${serverUrl}";</script>`; - return io.write(f, contents).then(() => f); - }); -} - - -/** - * Deletes all session data files if so desired. - * @param {!Object} desiredCapabilities . - * @return {!Array<!Promise>} A list of promises for the deleted files. - */ -function cleanSession(desiredCapabilities) { - if (!desiredCapabilities) { - return []; - } - var options = desiredCapabilities[OPTIONS_CAPABILITY_KEY]; - if (!options) { - return []; - } - if (!options['cleanSession']) { - return []; - } - return SESSION_DATA_FILES.map(function(file) { - return io.unlink(file); - }); -} - - -/** @return {string} . */ -function getRandomString() { - let seed = Date.now(); - return Math.floor(Math.random() * seed).toString(36) - + Math.abs(Math.floor(Math.random() * seed) ^ Date.now()).toString(36); -} - - -/** - * @implements {command.Executor} - */ -class CommandExecutor { - constructor() { - this.server_ = null; - - /** @private {ws.WebSocket} */ - this.socket_ = null; - - /** @private {?string} 8*/ - this.sessionId_ = null; - - /** @private {Promise<!exec.Command>} */ - this.safari_ = null; - - /** @private {!logging.Logger} */ - this.log_ = logging.getLogger('webdriver.safari'); - } - - /** @override */ - execute(cmd) { - var self = this; - return new promise.Promise(function(fulfill, reject) { - var safariCommand = JSON.stringify({ - 'origin': 'webdriver', - 'type': 'command', - 'command': { - 'id': getRandomString(), - 'name': cmd.getName(), - 'parameters': cmd.getParameters() - } - }); - - switch (cmd.getName()) { - case command.Name.NEW_SESSION: - self.startSafari_(cmd) - .then(() => self.sendCommand_(safariCommand)) - .then(caps => new Session(self.sessionId(), caps)) - .then(fulfill, reject); - break; - - case command.Name.DESCRIBE_SESSION: - self.sendCommand_(safariCommand) - .then(caps => new Session(self.sessionId(), caps)) - .then(fulfill, reject); - break; - - case command.Name.QUIT: - self.destroySession_().then(() => fulfill(null), reject); - break; - - default: - self.sendCommand_(safariCommand).then(fulfill, reject); - break; - } - }); - } - - /** - * @return {string} The static session ID for this executor's current - * connection. - */ - sessionId() { - if (!this.sessionId_) { - throw Error('not currently connected') - } - return this.sessionId_; - } - - /** - * @param {string} data . - * @return {!promise.Promise} . - * @private - */ - sendCommand_(data) { - let self = this; - return new promise.Promise(function(fulfill, reject) { - // TODO: support reconnecting with the extension. - if (!self.socket_) { - self.destroySession_().finally(function() { - reject(Error('The connection to the SafariDriver was closed')); - }); - return; - } - - self.log_.fine(() => '>>> ' + data); - self.socket_.send(data, function(err) { - if (err) { - reject(err); - return; - } - }); - - self.socket_.once('message', function(data) { - try { - self.log_.fine(() => '<<< ' + data); - data = JSON.parse(data); - } catch (ex) { - reject(Error('Failed to parse driver message: ' + data)); - return; - } - - try { - error.checkLegacyResponse(data['response']); - fulfill(data['response']['value']); - } catch (ex) { - reject(ex); - } - }); - }); - } - - /** - * @param {!command.Command} command . - * @private - */ - startSafari_(command) { - this.server_ = new Server(); - - this.safari_ = this.server_.start().then(function(address) { - var tasks = cleanSession( - /** @type {!Object} */( - command.getParameters()['desiredCapabilities'])); - tasks.push( - findSafariExecutable(), - createConnectFile( - 'http://' + address.address + ':' + address.port)); - - return Promise.all(tasks).then(function(/** !Array<string> */tasks) { - var exe = tasks[tasks.length - 2]; - var html = tasks[tasks.length - 1]; - return exec(exe, {args: [html]}); - }); - }); - - return new Promise((resolve, reject) => { - let start = Date.now(); - let timer = setTimeout(function() { - let elapsed = Date.now() - start; - reject(Error( - 'Failed to connect to the SafariDriver after ' + elapsed + - ' ms; Have you installed the latest extension from ' + - 'http://selenium-release.storage.googleapis.com/index.html?')); - }, 10 * 1000); - - this.server_.once('connection', socket => { - clearTimeout(timer); - this.socket_ = socket; - this.sessionId_ = getRandomString(); - socket.once('close', () => { - this.socket_ = null; - this.sessionId_ = null; - }); - resolve(); - }); - }); - } - - /** - * Destroys the active session by stopping the WebSocket server and killing the - * Safari subprocess. - * @private - */ - destroySession_() { - var tasks = []; - if (this.server_) { - tasks.push(this.server_.stop()); - } - if (this.safari_) { - tasks.push(this.safari_.then(function(safari) { - safari.kill(); - return safari.result(); - })); - } - var self = this; - return promise.all(tasks).finally(function() { - self.server_ = null; - self.socket_ = null; - self.safari_ = null; - }); - } -} /** @@ -498,10 +67,7 @@ class ServiceBuilder extends remote.DriverService.Builder { } -/** @const */ const OPTIONS_CAPABILITY_KEY = 'safari.options'; -const LEGACY_DRIVER_CAPABILITY_KEY = 'legacyDriver' - /** @@ -517,9 +83,6 @@ class Options { /** @private {?./lib/capabilities.ProxyConfig} */ this.proxy_ = null; - - /** @private {boolean} */ - this.legacyDriver_ = false; } /** @@ -546,10 +109,6 @@ class Options { options.setLoggingPrefs(capabilities.get(Capability.LOGGING_PREFS)); } - if (capabilities.has(LEGACY_DRIVER_CAPABILITY_KEY)) { - options.useLegacyDriver(capabilities.get(LEGACY_DRIVER_CAPABILITY_KEY)); - } - return options; } @@ -569,18 +128,6 @@ class Options { } /** - * Sets whether to use the legacy driver from the Selenium project. This option - * is disabled by default. - * - * @param {boolean} enable Whether to enable the legacy driver. - * @return {!Options} A self reference. - */ - useLegacyDriver(enable) { - this.legacyDriver_ = enable; - return this; - } - - /** * Sets the logging preferences for the new session. * @param {!./lib/logging.Preferences} prefs The logging preferences. * @return {!Options} A self reference. @@ -618,7 +165,6 @@ class Options { if (this.options_) { caps.set(OPTIONS_CAPABILITY_KEY, this); } - caps.set(LEGACY_DRIVER_CAPABILITY_KEY, this.legacyDriver_); return caps; } @@ -645,49 +191,28 @@ class Options { */ class Driver extends webdriver.WebDriver { /** + * Creates a new Safari session. + * * @param {(Options|Capabilities)=} opt_config The configuration * options for the new session. * @param {promise.ControlFlow=} opt_flow The control flow to create * the driver under. + * @return {!Driver} A new driver instance. */ - constructor(opt_config, opt_flow) { - let caps, - executor, - useLegacyDriver = false, - onQuit = () => {}; - + static createSession(opt_config, opt_flow) { + let caps; if (opt_config instanceof Options) { caps = opt_config.toCapabilities(); } else { caps = opt_config || Capabilities.safari() } - if (caps.has(LEGACY_DRIVER_CAPABILITY_KEY)) { - useLegacyDriver = caps.get(LEGACY_DRIVER_CAPABILITY_KEY); - caps.delete(LEGACY_DRIVER_CAPABILITY_KEY); - } - - if (useLegacyDriver) { - executor = new CommandExecutor(); - } else { - let service = new ServiceBuilder().build(); - - executor = new http_.Executor( - service.start() - .then(url => new http_.HttpClient(url)) - ); - - onQuit = () => service.kill(); - } - - let driver = webdriver.WebDriver.createSession(executor, caps, opt_flow); - - super(driver.getSession(), executor, driver.controlFlow()); + let service = new ServiceBuilder().build(); + let executor = new http.Executor( + service.start().then(url => new http.HttpClient(url))); - /** @override */ - this.quit = () => { - return super.quit().finally(onQuit); - }; + return /** @type {!Driver} */(webdriver.WebDriver.createSession( + executor, caps, opt_flow, this, () => service.kill())); } } |