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 at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// 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 and
13// limitations under the License.
14
15var base = require('./_base'),
16 executors = require('./executors');
17
18// 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');
24
25
26
27/**
28 * Creates new {@link webdriver.WebDriver WebDriver} instances. The environment
29 * 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 builder
33 * instances. This environment variable should be set to a fully qualified
34 * URL for a WebDriver server (e.g. http://localhost:4444/wd/hub).
35 *
36 * <li>{@code SELENIUM_BROWSER}: defines the target browser in the form
37 * {@code browser[:version][:platform]}.
38 * </ul>
39 *
40 * <p>Suppose you had mytest.js that created WebDriver with
41 * {@code var driver = new webdriver.Builder().build();}.
42 *
43 * This test could be made to use Firefox on the local machine by running with
44 * {@code SELENIUM_BROWSER=firefox node mytest.js}.
45 *
46 * <p>Alternatively, you could request Chrome 36 on Linux from a remote
47 * server with {@code
48 * SELENIUM_BROWSER=chrome:36:LINUX
49 * SELENIUM_REMOTE_URL=http://www.example.com:4444/wd/hub
50 * node mytest.js}.
51 *
52 * @constructor
53 */
54var Builder = function() {
55
56 /** @private {webdriver.promise.ControlFlow} */
57 this.flow_ = null;
58
59 /** @private {string} */
60 this.url_ = '';
61
62 /** @private {!webdriver.Capabilities} */
63 this.capabilities_ = new Capabilities();
64
65 /** @private {chrome.Options} */
66 this.chromeOptions_ = null;
67
68 /** @private {firefox.Options} */
69 this.firefoxOptions_ = null;
70};
71
72
73/**
74 * Sets the URL of a remote WebDriver server to use. Once a remote URL has been
75 * specified, the builder direct all new clients to that server. If this method
76 * 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 the
79 * {@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};
88
89
90/**
91 * @return {string} The URL of the WebDriver server this instance is configured
92 * to use.
93 */
94Builder.prototype.getServerUrl = function() {
95 return this.url_;
96};
97
98
99/**
100 * Sets the desired capabilities when requesting a new session. This will
101 * overwrite any previously set capabilities.
102 * @param {!(Object|webdriver.Capabilities)} capabilities The desired
103 * 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};
110
111
112/**
113 * Returns the base set of capabilities this instance is currently configured
114 * to use.
115 * @return {!webdriver.Capabilities} The current capabilities for this builder.
116 */
117Builder.prototype.getCapabilities = function() {
118 return this.capabilities_;
119};
120
121
122/**
123 * Configures the target browser for clients created by this instance.
124 * Any calls to {@link #withCapabilities} after this function will
125 * 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 the
129 * 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 any
134 * version should be used.
135 * @param {string=} opt_platform The desired platform; may be omitted if any
136 * 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};
145
146
147/**
148 * Sets the proxy configuration to use for WebDriver clients created by this
149 * builder. Any calls to {@link #withCapabilities} after this function will
150 * 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};
158
159
160/**
161 * Sets the logging preferences for the created session. Preferences may be
162 * changed by repeated calls, or by calling {@link #withCapabilities}.
163 * @param {!(webdriver.logging.Preferences|Object.<string, string>)} prefs The
164 * desired logging preferences.
165 * @return {!Builder} A self reference.
166 */
167Builder.prototype.setLoggingPrefs = function(prefs) {
168 this.capabilities_.setLoggingPrefs(prefs);
169 return this;
170};
171
172
173/**
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};
182
183
184/**
185 * Sets how elements should be scrolled into view for interaction.
186 * @param {number} behavior The desired scroll behavior: either 0 to align with
187 * 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};
194
195
196/**
197 * Sets the default action to take with an unexpected alert before returning
198 * 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};
207
208
209/**
210 * Sets Chrome-specific options for drivers created by this builder. Any
211 * logging or proxy settings defined on the given options will take precedence
212 * 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};
222
223
224/**
225 * Sets Firefox-specific options for drivers created by this builder. Any
226 * logging or proxy settings defined on the given options will take precedence
227 * 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};
237
238
239/**
240 * Sets the control flow that created drivers should execute actions in. If
241 * the flow is never set, or is set to {@code null}, it will use the active
242 * flow at the time {@link #build()} is called.
243 * @param {webdriver.promise.ControlFlow} flow The control flow to use, or
244 * {@code null} to
245 * @return {!Builder} A self reference.
246 */
247Builder.prototype.setControlFlow = function(flow) {
248 this.flow_ = flow;
249 return this;
250};
251
252
253/**
254 * Creates a new WebDriver client based on this builder's current
255 * 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 current
262 // environment.
263 var capabilities = new Capabilities(this.capabilities_);
264
265 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 }
272
273 browser = capabilities.get(Capability.BROWSER_NAME);
274
275 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 }
280
281 // Apply browser specific overrides.
282 if (browser === Browser.CHROME && this.chromeOptions_) {
283 capabilities.merge(this.chromeOptions_.toCapabilities());
284 }
285
286 if (browser === Browser.FIREFOX && this.firefoxOptions_) {
287 capabilities.merge(this.firefoxOptions_.toCapabilities());
288 }
289
290 // 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 }
296
297 // Check for a native browser.
298 switch (browser) {
299 case Browser.CHROME:
300 // Requiring 'chrome' above would create a cycle:
301 // index -> builder -> chrome -> index
302 var chrome = require('./chrome');
303 return new chrome.Driver(capabilities, null, this.flow_);
304
305 case Browser.FIREFOX:
306 // Requiring 'firefox' above would create a cycle:
307 // index -> builder -> firefox -> index
308 var firefox = require('./firefox');
309 return new firefox.Driver(capabilities, this.flow_);
310
311 case Browser.PHANTOM_JS:
312 // Requiring 'phantomjs' would create a cycle:
313 // index -> builder -> phantomjs -> index
314 var phantomjs = require('./phantomjs');
315 return new phantomjs.Driver(capabilities, this.flow_);
316
317 default:
318 throw new Error('Do not know how to build driver: ' + browser
319 + '; did you forget to call usingServer(url)?');
320 }
321};
322
323
324// PUBLIC API
325
326
327exports.Builder = Builder;