# builder.js

    1// Copyright 2011 Software Freedom Conservancy. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7//      http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.1415var base = require('./_base'),16    executors = require('./executors');1718// Use base.require to avoid circular references between index and this module.19var Browser = base.require('webdriver.Browser'),20    Capabilities = base.require('webdriver.Capabilities'),21    Capability = base.require('webdriver.Capability'),22    WebDriver = base.require('webdriver.WebDriver'),23    promise = base.require('webdriver.promise');24252627/**28 * Creates new {@link webdriver.WebDriver WebDriver} instances. The environment29 * variables listed below may be used to override a builder's configuration,30 * allowing quick runtime changes.31 * <ul>32 * <li>{@code SELENIUM_REMOTE_URL}: defines the remote URL for all builder33 *   instances. This environment variable should be set to a fully qualified34 *   URL for a WebDriver server (e.g. http://localhost:4444/wd/hub).35 *36 * <li>{@code SELENIUM_BROWSER}: defines the target browser in the form37 *   {@code browser[:version][:platform]}.38 * </ul>39 *40 * <p>Suppose you had mytest.js that created WebDriver with41 *     {@code var driver = new webdriver.Builder().build();}.42 *43 * This test could be made to use Firefox on the local machine by running with44 * {@code SELENIUM_BROWSER=firefox node mytest.js}.45 *46 * <p>Alternatively, you could request Chrome 36 on Linux from a remote47 * server with {@code48 *     SELENIUM_BROWSER=chrome:36:LINUX49 *     SELENIUM_REMOTE_URL=http://www.example.com:4444/wd/hub50 *     node mytest.js}.51 *52 * @constructor53 */54var Builder = function() {5556  /** @private {webdriver.promise.ControlFlow} */57  this.flow_ = null;5859  /** @private {string} */60  this.url_ = '';6162  /** @private {!webdriver.Capabilities} */63  this.capabilities_ = new Capabilities();6465  /** @private {chrome.Options} */66  this.chromeOptions_ = null;6768  /** @private {firefox.Options} */69  this.firefoxOptions_ = null;70};717273/**74 * Sets the URL of a remote WebDriver server to use. Once a remote URL has been75 * specified, the builder direct all new clients to that server. If this method76 * is never called, the Builder will attempt to create all clients locally.77 *78 * <p>As an alternative to this method, you may also set the79 * {@code SELENIUM_REMOTE_URL} environment variable.80 *81 * @param {string} url The URL of a remote server to use.82 * @return {!Builder} A self reference.83 */84Builder.prototype.usingServer = function(url) {85  this.url_ = url;86  return this;87};888990/**91 * @return {string} The URL of the WebDriver server this instance is configured92 *     to use.93 */94Builder.prototype.getServerUrl = function() {95  return this.url_;96};979899/**100 * Sets the desired capabilities when requesting a new session. This will101 * overwrite any previously set capabilities.102 * @param {!(Object|webdriver.Capabilities)} capabilities The desired103 *     capabilities for a new session.104 * @return {!Builder} A self reference.105 */106Builder.prototype.withCapabilities = function(capabilities) {107  this.capabilities_ = new Capabilities(capabilities);108  return this;109};110111112/**113 * Returns the base set of capabilities this instance is currently configured114 * to use.115 * @return {!webdriver.Capabilities} The current capabilities for this builder.116 */117Builder.prototype.getCapabilities = function() {118  return this.capabilities_;119};120121122/**123 * Configures the target browser for clients created by this instance.124 * Any calls to {@link #withCapabilities} after this function will125 * overwrite these settings.126 *127 * <p>You may also define the target browser using the {@code SELENIUM_BROWSER}128 * environment variable. If set, this environment variable should be of the129 * form {@code browser[:[version][:platform]]}.130 *131 * @param {(string|webdriver.Browser)} name The name of the target browser;132 *     common defaults are available on the {@link webdriver.Browser} enum.133 * @param {string=} opt_version A desired version; may be omitted if any134 *     version should be used.135 * @param {string=} opt_platform The desired platform; may be omitted if any136 *     version may be used.137 * @return {!Builder} A self reference.138 */139Builder.prototype.forBrowser = function(name, opt_version, opt_platform) {140  this.capabilities_.set(Capability.BROWSER_NAME, name);141  this.capabilities_.set(Capability.VERSION, opt_version || null);142  this.capabilities_.set(Capability.PLATFORM, opt_platform || null);143  return this;144};145146147/**148 * Sets the proxy configuration to use for WebDriver clients created by this149 * builder. Any calls to {@link #withCapabilities} after this function will150 * overwrite these settings.151 * @param {!webdriver.ProxyConfig} config The configuration to use.152 * @return {!Builder} A self reference.153 */154Builder.prototype.setProxy = function(config) {155  this.capabilities_.setProxy(config);156  return this;157};158159160/**161 * Sets the logging preferences for the created session. Preferences may be162 * changed by repeated calls, or by calling {@link #withCapabilities}.163 * @param {!(webdriver.logging.Preferences|Object.<string, string>)} prefs The164 *     desired logging preferences.165 * @return {!Builder} A self reference.166 */167Builder.prototype.setLoggingPrefs = function(prefs) {168  this.capabilities_.setLoggingPrefs(prefs);169  return this;170};171172173/**174 * Sets whether native events should be used.175 * @param {boolean} enabled Whether to enable native events.176 * @return {!Builder} A self reference.177 */178Builder.prototype.setEnableNativeEvents = function(enabled) {179  this.capabilities_.setEnableNativeEvents(enabled);180  return this;181};182183184/**185 * Sets how elements should be scrolled into view for interaction.186 * @param {number} behavior The desired scroll behavior: either 0 to align with187 *     the top of the viewport or 1 to align with the bottom.188 * @return {!Builder} A self reference.189 */190Builder.prototype.setScrollBehavior = function(behavior) {191  this.capabilities_.setScrollBehavior(behavior);192  return this;193};194195196/**197 * Sets the default action to take with an unexpected alert before returning198 * an error.199 * @param {string} beahvior The desired behavior; should be "accept", "dismiss",200 *     or "ignore". Defaults to "dismiss".201 * @return {!Builder} A self reference.202 */203Builder.prototype.setAlertBehavior = function(behavior) {204  this.capabilities_.setAlertBehavior(behavior);205  return this;206};207208209/**210 * Sets Chrome-specific options for drivers created by this builder. Any211 * logging or proxy settings defined on the given options will take precedence212 * over those set through {@link #setLoggingPrefs} and {@link #setProxy},213 * respectively.214 *215 * @param {!chrome.Options} options The ChromeDriver options to use.216 * @return {!Builder} A self reference.217 */218Builder.prototype.setChromeOptions = function(options) {219  this.chromeOptions_ = options;220  return this;221};222223224/**225 * Sets Firefox-specific options for drivers created by this builder. Any226 * logging or proxy settings defined on the given options will take precedence227 * over those set through {@link #setLoggingPrefs} and {@link #setProxy},228 * respectively.229 *230 * @param {!firefox.Options} options The FirefoxDriver options to use.231 * @return {!Builder} A self reference.232 */233Builder.prototype.setFirefoxOptions = function(options) {234  this.firefoxOptions_ = options;235  return this;236};237238239/**240 * Sets the control flow that created drivers should execute actions in. If241 * the flow is never set, or is set to {@code null}, it will use the active242 * flow at the time {@link #build()} is called.243 * @param {webdriver.promise.ControlFlow} flow The control flow to use, or244 *     {@code null} to245 * @return {!Builder} A self reference.246 */247Builder.prototype.setControlFlow = function(flow) {248  this.flow_ = flow;249  return this;250};251252253/**254 * Creates a new WebDriver client based on this builder's current255 * configuration.256 *257 * @return {!webdriver.WebDriver} A new WebDriver instance.258 * @throws {Error} If the current configuration is invalid.259 */260Builder.prototype.build = function() {261  // Create a copy for any changes we may need to make based on the current262  // environment.263  var capabilities = new Capabilities(this.capabilities_);264265  var browser = process.env.SELENIUM_BROWSER;266  if (browser) {267    browser = browser.split(/:/, 3);268    capabilities.set(Capability.BROWSER_NAME, browser[0]);269    capabilities.set(Capability.VERSION, browser[1] || null);270    capabilities.set(Capability.PLATFORM, browser[2] || null);271  }272273  browser = capabilities.get(Capability.BROWSER_NAME);274275  if (typeof browser !== 'string') {276    throw TypeError(277        'Target browser must be a string, but is <' + (typeof browser) + '>;' +278        ' did you forget to call forBrowser()?');279  }280281  // Apply browser specific overrides.282  if (browser === Browser.CHROME && this.chromeOptions_) {283    capabilities.merge(this.chromeOptions_.toCapabilities());284  }285286  if (browser === Browser.FIREFOX && this.firefoxOptions_) {287    capabilities.merge(this.firefoxOptions_.toCapabilities());288  }289290  // Check for a remote browser.291  var url = process.env.SELENIUM_REMOTE_URL || this.url_;292  if (url) {293    var executor = executors.createExecutor(url);294    return WebDriver.createSession(executor, capabilities, this.flow_);295  }296297  // Check for a native browser.298  switch (browser) {299    case Browser.CHROME:300      // Requiring 'chrome' above would create a cycle:301      // index -> builder -> chrome -> index302      var chrome = require('./chrome');303      return new chrome.Driver(capabilities, null, this.flow_);304305    case Browser.FIREFOX:306      // Requiring 'firefox' above would create a cycle:307      // index -> builder -> firefox -> index308      var firefox = require('./firefox');309      return new firefox.Driver(capabilities, this.flow_);310311    case Browser.PHANTOM_JS:312      // Requiring 'phantomjs' would create a cycle:313      // index -> builder -> phantomjs -> index314      var phantomjs = require('./phantomjs');315      return new phantomjs.Driver(capabilities, this.flow_);316317    default:318      throw new Error('Do not know how to build driver: ' + browser319          + '; did you forget to call usingServer(url)?');320  }321};322323324// PUBLIC API325326327exports.Builder = Builder;