phantomjs.js

1// Copyright 2013 Selenium committers
2// Copyright 2013 Software Freedom Conservancy
3//
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 at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// 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 and
14// limitations under the License.
15
16'use strict';
17
18var fs = require('fs'),
19 util = require('util');
20
21var webdriver = require('./index'),
22 LogLevel = webdriver.logging.LevelName,
23 executors = require('./executors'),
24 io = require('./io'),
25 portprober = require('./net/portprober'),
26 remote = require('./remote');
27
28
29/**
30 * Name of the PhantomJS executable.
31 * @type {string}
32 * @const
33 */
34var PHANTOMJS_EXE =
35 process.platform === 'win32' ? 'phantomjs.exe' : 'phantomjs';
36
37
38/**
39 * Capability that designates the location of the PhantomJS executable to use.
40 * @type {string}
41 * @const
42 */
43var BINARY_PATH_CAPABILITY = 'phantomjs.binary.path';
44
45
46/**
47 * Capability that designates the CLI arguments to pass to PhantomJS.
48 * @type {string}
49 * @const
50 */
51var CLI_ARGS_CAPABILITY = 'phantomjs.cli.args';
52
53
54/**
55 * Default log file to use if one is not specified through CLI args.
56 * @type {string}
57 * @const
58 */
59var DEFAULT_LOG_FILE = 'phantomjsdriver.log';
60
61
62/**
63 * Finds the PhantomJS executable.
64 * @param {string=} opt_exe Path to the executable to use.
65 * @return {string} The located executable.
66 * @throws {Error} If the executable cannot be found on the PATH, or if the
67 * provided executable path does not exist.
68 */
69function findExecutable(opt_exe) {
70 var exe = opt_exe || io.findInPath(PHANTOMJS_EXE, true);
71 if (!exe) {
72 throw Error(
73 'The PhantomJS executable could not be found on the current PATH. ' +
74 'Please download the latest version from ' +
75 'http://phantomjs.org/download.html and ensure it can be found on ' +
76 'your PATH. For more information, see ' +
77 'https://github.com/ariya/phantomjs/wiki');
78 }
79 if (!fs.existsSync(exe)) {
80 throw Error('File does not exist: ' + exe);
81 }
82 return exe;
83}
84
85
86/**
87 * Maps WebDriver logging level name to those recognised by PhantomJS.
88 * @type {!Object.<webdriver.logging.LevelName, string>}
89 * @const
90 */
91var WEBDRIVER_TO_PHANTOMJS_LEVEL = (function() {
92 var map = {};
93 map[LogLevel.ALL] = map[LogLevel.DEBUG] = 'DEBUG';
94 map[LogLevel.INFO] = 'INFO';
95 map[LogLevel.WARNING] = 'WARN';
96 map[LogLevel.SEVERE] = map[LogLevel.OFF] = 'ERROR';
97 return map;
98})();
99
100
101/**
102 * Creates a new PhantomJS WebDriver client.
103 * @param {webdriver.Capabilities=} opt_capabilities The desired capabilities.
104 * @return {!webdriver.WebDriver} A new WebDriver instance.
105 */
106function createDriver(opt_capabilities) {
107 var capabilities = opt_capabilities || webdriver.Capabilities.phantomjs();
108 var exe = findExecutable(capabilities.get(BINARY_PATH_CAPABILITY));
109 var args = ['--webdriver-logfile=' + DEFAULT_LOG_FILE];
110
111 var logPrefs = capabilities.get(webdriver.Capability.LOGGING_PREFS);
112 if (logPrefs && logPrefs[webdriver.logging.Type.DRIVER]) {
113 var level = WEBDRIVER_TO_PHANTOMJS_LEVEL[
114 logPrefs[webdriver.logging.Type.DRIVER]];
115 if (level) {
116 args.push('--webdriver-loglevel=' + level);
117 }
118 }
119
120 var proxy = capabilities.get(webdriver.Capability.PROXY);
121 if (proxy) {
122 switch (proxy.proxyType) {
123 case 'manual':
124 if (proxy.httpProxy) {
125 args.push(
126 '--proxy-type=http',
127 '--proxy=http://' + proxy.httpProxy);
128 }
129 break;
130 case 'pac':
131 throw Error('PhantomJS does not support Proxy PAC files');
132 case 'system':
133 args.push('--proxy-type=system');
134 break;
135 case 'direct':
136 args.push('--proxy-type=none');
137 break;
138 }
139 }
140 args = args.concat(capabilities.get(CLI_ARGS_CAPABILITY) || []);
141
142 var port = portprober.findFreePort();
143 var service = new remote.DriverService(exe, {
144 port: port,
145 args: webdriver.promise.when(port, function(port) {
146 args.push('--webdriver=' + port);
147 return args;
148 })
149 });
150
151 var executor = executors.createExecutor(service.start());
152 var driver = webdriver.WebDriver.createSession(executor, capabilities);
153 var boundQuit = driver.quit.bind(driver);
154 driver.quit = function() {
155 return boundQuit().thenFinally(service.kill.bind(service));
156 };
157 return driver;
158}
159
160
161// PUBLIC API
162
163
164exports.createDriver = createDriver;