# phantomjs.js

    1// Copyright 2013 Selenium committers2// Copyright 2013 Software Freedom Conservancy3//4// Licensed under the Apache License, Version 2.0 (the "License");5// you may not use this file except in compliance with the License.6//     You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing, software11// distributed under the License is distributed on an "AS IS" BASIS,12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13// See the License for the specific language governing permissions and14// limitations under the License.1516'use strict';1718var fs = require('fs'),19    util = require('util');2021var webdriver = require('./index'),22    executors = require('./executors'),23    io = require('./io'),24    portprober = require('./net/portprober'),25    remote = require('./remote');262728/**29 * Name of the PhantomJS executable.30 * @type {string}31 * @const32 */33var PHANTOMJS_EXE =34    process.platform === 'win32' ? 'phantomjs.exe' : 'phantomjs';353637/**38 * Capability that designates the location of the PhantomJS executable to use.39 * @type {string}40 * @const41 */42var BINARY_PATH_CAPABILITY = 'phantomjs.binary.path';434445/**46 * Capability that designates the CLI arguments to pass to PhantomJS.47 * @type {string}48 * @const49 */50var CLI_ARGS_CAPABILITY = 'phantomjs.cli.args';515253/**54 * Default log file to use if one is not specified through CLI args.55 * @type {string}56 * @const57 */58var DEFAULT_LOG_FILE = 'phantomjsdriver.log';596061/**62 * Finds the PhantomJS executable.63 * @param {string=} opt_exe Path to the executable to use.64 * @return {string} The located executable.65 * @throws {Error} If the executable cannot be found on the PATH, or if the66 *     provided executable path does not exist.67 */68function findExecutable(opt_exe) {69  var exe = opt_exe || io.findInPath(PHANTOMJS_EXE, true);70  if (!exe) {71    throw Error(72        'The PhantomJS executable could not be found on the current PATH. ' +73        'Please download the latest version from ' +74        'http://phantomjs.org/download.html and ensure it can be found on ' +75        'your PATH. For more information, see ' +76        'https://github.com/ariya/phantomjs/wiki');77  }78  if (!fs.existsSync(exe)) {79    throw Error('File does not exist: ' + exe);80  }81  return exe;82}838485/**86 * Maps WebDriver logging level name to those recognised by PhantomJS.87 * @type {!Object.<string, string>}88 * @const89 */90var WEBDRIVER_TO_PHANTOMJS_LEVEL = (function() {91  var map = {};92  map[webdriver.logging.Level.ALL.name] = 'DEBUG';93  map[webdriver.logging.Level.DEBUG.name] = 'DEBUG';94  map[webdriver.logging.Level.INFO.name] = 'INFO';95  map[webdriver.logging.Level.WARNING.name] = 'WARN';96  map[webdriver.logging.Level.SEVERE.name] = 'ERROR';97  return map;98})();99100101/**102 * Creates a new PhantomJS WebDriver client.103 * @param {webdriver.Capabilities=} opt_capabilities The desired capabilities.104 * @param {webdriver.promise.ControlFlow=} opt_flow The control flow to use, or105 *     {@code null} to use the currently active flow.106 * @return {!webdriver.WebDriver} A new WebDriver instance.107 * @deprecated Use {@link Driver}.108 */109function createDriver(opt_capabilities, opt_flow) {110  return new Driver(opt_capabilities, opt_flow);111}112113114/**115 * Creates a new WebDriver client for PhantomJS.116 *117 * @param {webdriver.Capabilities=} opt_capabilities The desired capabilities.118 * @param {webdriver.promise.ControlFlow=} opt_flow The control flow to use, or119 *     {@code null} to use the currently active flow.120 * @constructor121 * @extends {webdriver.WebDriver}122 */123var Driver = function(opt_capabilities, opt_flow) {124  var capabilities = opt_capabilities || webdriver.Capabilities.phantomjs();125  var exe = findExecutable(capabilities.get(BINARY_PATH_CAPABILITY));126  var args = ['--webdriver-logfile=' + DEFAULT_LOG_FILE];127128  var logPrefs = capabilities.get(webdriver.Capability.LOGGING_PREFS);129  if (logPrefs instanceof webdriver.logging.Preferences) {130    logPrefs = logPrefs.toJSON();131  }132133  if (logPrefs && logPrefs[webdriver.logging.Type.DRIVER]) {134    var level = WEBDRIVER_TO_PHANTOMJS_LEVEL[135        logPrefs[webdriver.logging.Type.DRIVER]];136    if (level) {137      args.push('--webdriver-loglevel=' + level);138    }139  }140141  var proxy = capabilities.get(webdriver.Capability.PROXY);142  if (proxy) {143    switch (proxy.proxyType) {144      case 'manual':145        if (proxy.httpProxy) {146          args.push(147              '--proxy-type=http',148              '--proxy=http://' + proxy.httpProxy);149        }150        break;151      case 'pac':152        throw Error('PhantomJS does not support Proxy PAC files');153      case 'system':154        args.push('--proxy-type=system');155        break;156      case 'direct':157        args.push('--proxy-type=none');158        break;159    }160  }161  args = args.concat(capabilities.get(CLI_ARGS_CAPABILITY) || []);162163  var port = portprober.findFreePort();164  var service = new remote.DriverService(exe, {165    port: port,166    args: webdriver.promise.when(port, function(port) {167      args.push('--webdriver=' + port);168      return args;169    })170  });171172  var executor = executors.createExecutor(service.start());173  var driver = webdriver.WebDriver.createSession(174      executor, capabilities, opt_flow);175176  webdriver.WebDriver.call(177      this, driver.getSession(), executor, driver.controlFlow());178179  var boundQuit = this.quit.bind(this);180181  /** @override */182  this.quit = function() {183    return boundQuit().thenFinally(service.kill.bind(service));184  };185  return driver;186};187util.inherits(Driver, webdriver.WebDriver);188189190// PUBLIC API191192exports.Driver = Driver;193exports.createDriver = createDriver;