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 | |
18 | var fs = require('fs'), |
19 | util = require('util'); |
20 | |
21 | var 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 | */ |
34 | var 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 | */ |
43 | var 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 | */ |
51 | var 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 | */ |
59 | var 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 | */ |
69 | function 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 | */ |
91 | var 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 | */ |
106 | function 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 | |
164 | exports.createDriver = createDriver; |