1 | // Licensed to the Software Freedom Conservancy (SFC) under one
|
2 | // or more contributor license agreements. See the NOTICE file
|
3 | // distributed with this work for additional information
|
4 | // regarding copyright ownership. The SFC licenses this file
|
5 | // to you under the Apache License, Version 2.0 (the
|
6 | // "License"); you may not use this file except in compliance
|
7 | // with the License. You may obtain a copy of the License at
|
8 | //
|
9 | // http://www.apache.org/licenses/LICENSE-2.0
|
10 | //
|
11 | // Unless required by applicable law or agreed to in writing,
|
12 | // software distributed under the License is distributed on an
|
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14 | // KIND, either express or implied. See the License for the
|
15 | // specific language governing permissions and limitations
|
16 | // under the License.
|
17 |
|
18 | /**
|
19 | * @fileoverview Defines a WebDriver client for Safari.
|
20 | */
|
21 |
|
22 | ;
|
23 |
|
24 | const command = require('./lib/command');
|
25 | const error = require('./lib/error');
|
26 | const http = require('./http');
|
27 | const io = require('./io');
|
28 | const portprober = require('./net/portprober');
|
29 | const promise = require('./lib/promise');
|
30 | const remote = require('./remote');
|
31 | const Symbols = require('./lib/symbols');
|
32 | const webdriver = require('./lib/webdriver');
|
33 | const {Browser, Capabilities, Capability} = require('./lib/capabilities');
|
34 |
|
35 |
|
36 | /**
|
37 | * _Synchronously_ attempts to locate the IE driver executable on the current
|
38 | * system.
|
39 | *
|
40 | * @return {?string} the located executable, or `null`.
|
41 | */
|
42 | function locateSynchronously() {
|
43 | return process.platform === 'darwin'
|
44 | ? io.findInPath('safaridriver', true) : null;
|
45 | }
|
46 |
|
47 |
|
48 | /**
|
49 | * @return {string} .
|
50 | * @throws {Error}
|
51 | */
|
52 | function findSafariDriver() {
|
53 | let exe = locateSynchronously();
|
54 | if (!exe) {
|
55 | throw Error(
|
56 | `The safaridriver executable could not be found on the current PATH.
|
57 | Please ensure you are using Safari 10.0 or above.`);
|
58 | }
|
59 | return exe;
|
60 | }
|
61 |
|
62 |
|
63 | /**
|
64 | * Creates {@link selenium-webdriver/remote.DriverService} instances that manage
|
65 | * a [safaridriver] server in a child process.
|
66 | *
|
67 | * [safaridriver]: https://developer.apple.com/library/prerelease/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html#//apple_ref/doc/uid/TP40014305-CH11-DontLinkElementID_28
|
68 | */
|
69 | class ServiceBuilder extends remote.DriverService.Builder {
|
70 | /**
|
71 | * @param {string=} opt_exe Path to the server executable to use. If omitted,
|
72 | * the builder will attempt to locate the safaridriver on the system PATH.
|
73 | */
|
74 | constructor(opt_exe) {
|
75 | super(opt_exe || findSafariDriver());
|
76 | this.setLoopback(true); // Required.
|
77 | }
|
78 | }
|
79 |
|
80 |
|
81 | const OPTIONS_CAPABILITY_KEY = 'safari.options';
|
82 | const TECHNOLOGY_PREVIEW_OPTIONS_KEY = 'technologyPreview';
|
83 |
|
84 | /**
|
85 | * Configuration options specific to the {@link Driver SafariDriver}.
|
86 | */
|
87 | class Options extends Capabilities {
|
88 | /**
|
89 | * @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
|
90 | * capabilities to initialize this instance from.
|
91 | */
|
92 | constructor(other = undefined) {
|
93 | super(other);
|
94 |
|
95 | /** @private {!Object} */
|
96 | this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {};
|
97 |
|
98 | this.set(OPTIONS_CAPABILITY_KEY, this.options_);
|
99 | this.setBrowserName(Browser.SAFARI);
|
100 | }
|
101 |
|
102 | /**
|
103 | * Instruct the SafariDriver to use the Safari Technology Preview if true.
|
104 | * Otherwise, use the release version of Safari. Defaults to using the release version of Safari.
|
105 | *
|
106 | * @param {boolean} useTechnologyPreview
|
107 | * @return {!Options} A self reference.
|
108 | */
|
109 | setTechnologyPreview(useTechnologyPreview) {
|
110 | this.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY] = !!useTechnologyPreview;
|
111 | return this;
|
112 | }
|
113 | }
|
114 |
|
115 | /**
|
116 | * @param {(Capabilities|Object<string, *>)=} o The options object
|
117 | * @return {boolean}
|
118 | */
|
119 | function useTechnologyPreview(o) {
|
120 | if (o instanceof Capabilities) {
|
121 | let options = o.get(OPTIONS_CAPABILITY_KEY);
|
122 | return !!(options && options[TECHNOLOGY_PREVIEW_OPTIONS_KEY]);
|
123 | }
|
124 |
|
125 | if (o && typeof o === 'object') {
|
126 | return !!o[TECHNOLOGY_PREVIEW_OPTIONS_KEY];
|
127 | }
|
128 |
|
129 | return false;
|
130 | }
|
131 |
|
132 |
|
133 | const SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE =
|
134 | '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver';
|
135 |
|
136 |
|
137 | /**
|
138 | * A WebDriver client for Safari. This class should never be instantiated
|
139 | * directly; instead, use the {@linkplain ./builder.Builder Builder}:
|
140 | *
|
141 | * var driver = new Builder()
|
142 | * .forBrowser('safari')
|
143 | * .build();
|
144 | *
|
145 | */
|
146 | class Driver extends webdriver.WebDriver {
|
147 | /**
|
148 | * Creates a new Safari session.
|
149 | *
|
150 | * @param {(Options|Capabilities)=} options The configuration options.
|
151 | * @return {!Driver} A new driver instance.
|
152 | */
|
153 | static createSession(options) {
|
154 | let caps = options || new Options();
|
155 |
|
156 | let exe;
|
157 | if (useTechnologyPreview(caps.get(OPTIONS_CAPABILITY_KEY))) {
|
158 | exe = SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE;
|
159 | }
|
160 |
|
161 | let service = new ServiceBuilder(exe).build();
|
162 | let executor = new http.Executor(
|
163 | service.start().then(url => new http.HttpClient(url)));
|
164 |
|
165 | return /** @type {!Driver} */(super.createSession(
|
166 | executor, caps, () => service.kill()));
|
167 | }
|
168 | }
|
169 |
|
170 |
|
171 | // Public API
|
172 |
|
173 |
|
174 | exports.Driver = Driver;
|
175 | exports.Options = Options;
|
176 | exports.ServiceBuilder = ServiceBuilder;
|
177 | exports.locateSynchronously = locateSynchronously;
|