config/Config.js

const DO = require('deepobject')

/**
 * A class that represents a Webdriver configuration
 */
class Config {
  /**
   * The main aim of Config class is to provide a configuration object that
   * will be used when creating a new session with the webdriver
   *
   *  A basic (empty) session configuration object looks like this:
   *
   *        {
   *          capabilities: {
   *            alwaysMatch: {
   *              'goog:chromeOptions': { w3c: true }
   *            },
   *            firstMatch: []
   *          }
   *        }
   *
   * Note that `goog:chromeOptions` is set as this option is necessary to make the
   * Chrome webdriver work with this API.
   *
   * Configuration options are set with the methods {@link Config#setAlwaysMatch},
   * {@link Config#addFirstMatch}, {@link Config#set} and {@link Config#setSpecific}
   *
   */
  constructor () {
    this.sessionParameters = {
      capabilities: {
        alwaysMatch: {
          'goog:chromeOptions': { w3c: true }
        },
        firstMatch: []
      }
    }
  }

  /**
   * Method to set the `alwaysMatch` property in the browser's capabilities
   *
   * @param {string} path The name of the property to set. It can be a path; if path is has a `.` (e.g.
   *                      `something.other`), the property
   *                      `sessionParameters.capabilities.alwaysMatch.something.other` will be set
   * @param {string} path.browserName The user agent
   * @param {string} path.browserVersion Identifies the version of the user agent
   * @param {string} path.platformName Identifies the operating system of the endpoint node
   * @param {boolean} path.acceptInsecureCerts Indicates whether untrusted and self-signed TLS certificates are implicitly trusted on navigation for the duration of the session
   * @param {string} path.pageLoadStrategy Defines the current session’s page load strategy. It can be `none`, `eager` or `normal`
   * @param {object} path.proxy Defines the current session’s proxy configuration. See the
                     {@link https://w3c.github.io/webdriver/webdriver-spec.html#dfn-proxy-configuration spec's
                     proxy options}
   * @param {boolean} path.setWindowRect Indicates whether the remote end supports all of the commands in Resizing and Positioning Windows
   * @param {object} path.timeouts Describes the timeouts imposed on certain session operations. Can have keys `implicit`, `pageLoad` or `script`
   * @param {string} path.unhandledPromptBehavior Describes the current session’s user prompt handler. It
   *                 can be: `dismiss`, `accept`, `dismiss and notify`, `accept and notify`, `ignore`
   * @param {*} value The value to assign to the property
   * @param {boolean} force It will overwrite keys if already present.
   *
   * @example
   * this.setAlwaysMatch('platformName', 'linux')
   * this.setAlwaysMatch('timeouts.implicit', 10000)
   */
  setAlwaysMatch (path, value, force = false) {
    var alwaysMatch = this.sessionParameters.capabilities.alwaysMatch
    if (force || typeof DO.get(alwaysMatch, path) === 'undefined') {
      DO.set(alwaysMatch, path, value)
    }
    return this
  }

  /**
   * Adds a property to the `firstMatch` array in the browser's capabilities.
   *
   * @param {string} key The name of the property to set
   * @param {*} value The value to assign
   * @param {boolean} force It will overwrite keys if needed
   *
   * @example
   * this.addFirstMatch({browserName: 'chrome'})
   * this.addFirstMatch({browserName: 'firefox'})
   * NOTE: WAS:
   * this.addFirstMatch({'browserName', 'chrome')
   * this.addFirstMatch('browserName', 'firefox')
   */
  // addFirstMatch (key, value, force = false) {
  //  if (force || !this.sessionParameters.capabilities.firstMatch.indexOf(key) === -1) {
  //    this.sessionParameters.capabilities.firstMatch.push({ [key]: value })
  //  }
  //  return this
  //}
  addFirstMatch (obj) {
    this.sessionParameters.capabilities.firstMatch.push(obj)

    return this
  }

  /**
   * Sets a key (or a path) on the object which will be sent to the webdriver when
   * creating a session
   *
   * @param {string} path The name of the property to set. It can be a path; if path is has a `.` (e.g.
   *                      `something.other`), the property
   *                      `sessionParameters.something.other` will be set
   * @param {*} value The value to assign
   * @param {boolean} force It will overwrite keys if needed
   *
   * @example
   * this.set('login', 'blah')
   * this.set('pass', 'blah')
   */
  set (path, value, force = true) {
    if (force || typeof DO.get(this.sessionParameters, path) === 'undefined') {
      DO.set(this.sessionParameters, path, value)
    }
    return this
  }

  /**
   * Sets a configuration option for the specific browser.
   *
   * @param {browserName} name The name of the browser to set. It can be
   *                       `chrome`, `firefox`, `safari` or `edge`
   * @param {string} path The name of the property to set. It can be a path; if path is has a `.` (e.g.
   *                      `something.other`), the property
   *                      `sessionParameters.something.other` will be set
   * @param {*} value The value to assign
   * @param {boolean} force It will overwrite keys if needed
   *
   * @example
   * this.setSpecific('chrome', 'FIXME1', 'blah')
   * this.setSpecific('safari', 'FIXME2', 'blah')
   */
  setSpecific (browserName, path, value, force = true) {
    var specificKey
    switch (browserName) {
      case 'chrome': specificKey = 'goog:chromeOptions'; break
      case 'edge': specificKey = 'edgeOptions'; break
      case 'firefox': specificKey = 'moz:firefoxOptions'; break
      case 'safari': specificKey = 'safari.options'; break
    }

    if (!specificKey) {
      throw new Error('setSpecificKey called for a browser that doesn\'t support them')
    }
    if (force || typeof DO.get(this.sessionParameters, specificKey + '.' + path) === 'undefined') {
      DO.set(this.sessionParameters, `capabilities.alwaysMatch.${specificKey}.${path}`, value)
    }
    return this
  }

  /**
   * Return the current session parameters. This is used by the {@link Driver#newSession} call
   * to get the parameters to be sent over
   *
   * @return {Object} The full session parameters
   *
   */
  getSessionParameters () {
    return this.sessionParameters
  }
}
exports = module.exports = Config