selenium-webdriver 4.8.2 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
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
+ const RealmType = {
19
+ AUDIO_WORKLET: 'audio-worklet',
20
+ DEDICATED_WORKER: 'dedicated-worker',
21
+ PAINT_WORKLET: 'paint-worklet',
22
+ SERVICE_WORKED: 'service-worker',
23
+ SHARED_WORKED: 'shared-worker',
24
+ WINDOW: 'window',
25
+ WORKER: 'worker',
26
+ WORKLET: 'worklet',
27
+
28
+ findByName(name) {
29
+ return (
30
+ Object.values(this).find((type) => {
31
+ return (
32
+ typeof type === 'string' && name.toLowerCase() === type.toLowerCase()
33
+ )
34
+ }) || null
35
+ )
36
+ },
37
+ }
38
+
39
+ class RealmInfo {
40
+ constructor(realmId, origin, realmType) {
41
+ this.realmId = realmId
42
+ this.origin = origin
43
+ this.realmType = realmType
44
+ }
45
+
46
+ static fromJson(input) {
47
+ let realmId = null
48
+ let origin = null
49
+ let realmType = null
50
+ let browsingContext = null
51
+ let sandbox = null
52
+
53
+ if ('type' in input) {
54
+ let typeString = input['type']
55
+ realmType = RealmType.findByName(typeString)
56
+ }
57
+
58
+ if ('realm' in input) {
59
+ realmId = input['realm']
60
+ }
61
+
62
+ if ('origin' in input) {
63
+ origin = input['origin']
64
+ }
65
+
66
+ if ('context' in input) {
67
+ browsingContext = input['context']
68
+ }
69
+
70
+ if ('sandbox' in input) {
71
+ sandbox = input['sandbox']
72
+ }
73
+
74
+ if (realmType === RealmType.WINDOW) {
75
+ return new WindowRealmInfo(
76
+ realmId,
77
+ origin,
78
+ realmType,
79
+ browsingContext,
80
+ sandbox
81
+ )
82
+ }
83
+
84
+ return new RealmInfo(realmId, origin, realmType)
85
+ }
86
+ }
87
+
88
+ class WindowRealmInfo extends RealmInfo {
89
+ constructor(realmId, origin, realmType, browsingContext, sandbox = null) {
90
+ super(realmId, origin, realmType)
91
+ this.browsingContext = browsingContext
92
+ this.sandbox = sandbox
93
+ }
94
+ }
95
+
96
+ module.exports = {
97
+ RealmInfo,
98
+ RealmType,
99
+ }
@@ -0,0 +1,23 @@
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
+ const ResultOwnership = {
19
+ ROOT: 'root',
20
+ NONE: 'none',
21
+ }
22
+
23
+ module.exports = { ResultOwnership }
@@ -0,0 +1,325 @@
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
+ const {
19
+ EvaluateResultType,
20
+ EvaluateResultSuccess,
21
+ EvaluateResultException,
22
+ ExceptionDetails,
23
+ } = require('./evaluateResult')
24
+ const { RealmInfo } = require('./realmInfo')
25
+ const { RemoteValue } = require('./protocolValue')
26
+
27
+ class ScriptManager {
28
+ constructor(driver) {
29
+ this._driver = driver
30
+ }
31
+
32
+ async init(browsingContextId) {
33
+ if (!(await this._driver.getCapabilities()).get('webSocketUrl')) {
34
+ throw Error('WebDriver instance must support BiDi protocol')
35
+ }
36
+
37
+ this.bidi = await this._driver.getBidi()
38
+ this._browsingContextId = browsingContextId
39
+ }
40
+
41
+ async disownRealmScript(realmId, handles) {
42
+ const params = {
43
+ method: 'script.disown',
44
+ params: {
45
+ handles: handles,
46
+ target: {
47
+ realm: realmId,
48
+ },
49
+ },
50
+ }
51
+
52
+ await this.bidi.send(params)
53
+ }
54
+
55
+ async disownBrowsingContextScript(
56
+ browsingContextId,
57
+ handles,
58
+ sandbox = null
59
+ ) {
60
+ const params = {
61
+ method: 'script.disown',
62
+ params: {
63
+ handles: handles,
64
+ target: {
65
+ context: browsingContextId,
66
+ },
67
+ },
68
+ }
69
+
70
+ if (sandbox != null) {
71
+ params.params.target['sandbox'] = sandbox
72
+ }
73
+
74
+ await this.bidi.send(params)
75
+ }
76
+
77
+ async callFunctionInRealm(
78
+ realmId,
79
+ functionDeclaration,
80
+ awaitPromise,
81
+ argumentValueList = null,
82
+ thisParameter = null,
83
+ resultOwnership = null
84
+ ) {
85
+ const params = this.getCallFunctionParams(
86
+ 'realm',
87
+ realmId,
88
+ null,
89
+ functionDeclaration,
90
+ awaitPromise,
91
+ argumentValueList,
92
+ thisParameter,
93
+ resultOwnership
94
+ )
95
+
96
+ const command = {
97
+ method: 'script.callFunction',
98
+ params,
99
+ }
100
+
101
+ let response = await this.bidi.send(command)
102
+ return this.createEvaluateResult(response)
103
+ }
104
+
105
+ async callFunctionInBrowsingContext(
106
+ browsingContextId,
107
+ functionDeclaration,
108
+ awaitPromise,
109
+ argumentValueList = null,
110
+ thisParameter = null,
111
+ resultOwnership = null,
112
+ sandbox = null
113
+ ) {
114
+ const params = this.getCallFunctionParams(
115
+ 'contextTarget',
116
+ browsingContextId,
117
+ sandbox,
118
+ functionDeclaration,
119
+ awaitPromise,
120
+ argumentValueList,
121
+ thisParameter,
122
+ resultOwnership
123
+ )
124
+
125
+ const command = {
126
+ method: 'script.callFunction',
127
+ params,
128
+ }
129
+ const response = await this.bidi.send(command)
130
+ return this.createEvaluateResult(response)
131
+ }
132
+
133
+ async evaluateFunctionInRealm(
134
+ realmId,
135
+ expression,
136
+ awaitPromise,
137
+ resultOwnership = null
138
+ ) {
139
+ const params = this.getEvaluateParams(
140
+ 'realm',
141
+ realmId,
142
+ null,
143
+ expression,
144
+ awaitPromise,
145
+ resultOwnership
146
+ )
147
+
148
+ const command = {
149
+ method: 'script.evaluate',
150
+ params,
151
+ }
152
+
153
+ let response = await this.bidi.send(command)
154
+ return this.createEvaluateResult(response)
155
+ }
156
+
157
+ async evaluateFunctionInBrowsingContext(
158
+ browsingContextId,
159
+ expression,
160
+ awaitPromise,
161
+ resultOwnership = null,
162
+ sandbox = null
163
+ ) {
164
+ const params = this.getEvaluateParams(
165
+ 'contextTarget',
166
+ browsingContextId,
167
+ sandbox,
168
+ expression,
169
+ awaitPromise,
170
+ resultOwnership
171
+ )
172
+
173
+ const command = {
174
+ method: 'script.evaluate',
175
+ params,
176
+ }
177
+
178
+ let response = await this.bidi.send(command)
179
+ return this.createEvaluateResult(response)
180
+ }
181
+
182
+ getCallFunctionParams(
183
+ targetType,
184
+ id,
185
+ sandbox,
186
+ functionDeclaration,
187
+ awaitPromise,
188
+ argumentValueList = null,
189
+ thisParameter = null,
190
+ resultOwnership = null
191
+ ) {
192
+ const params = {
193
+ functionDeclaration: functionDeclaration,
194
+ awaitPromise: awaitPromise,
195
+ }
196
+ if (targetType === 'contextTarget') {
197
+ if (sandbox != null) {
198
+ params['target'] = { context: id, sandbox: sandbox }
199
+ } else {
200
+ params['target'] = { context: id }
201
+ }
202
+ } else {
203
+ params['target'] = { realm: id }
204
+ }
205
+
206
+ if (argumentValueList != null) {
207
+ let argumentParams = []
208
+ argumentValueList.forEach((argumentValue) => {
209
+ argumentParams.push(argumentValue.asMap())
210
+ })
211
+ params['arguments'] = argumentParams
212
+ }
213
+
214
+ if (thisParameter != null) {
215
+ params['this'] = thisParameter
216
+ }
217
+
218
+ if (resultOwnership != null) {
219
+ params['resultOwnership'] = resultOwnership
220
+ }
221
+
222
+ return params
223
+ }
224
+
225
+ getEvaluateParams(
226
+ targetType,
227
+ id,
228
+ sandbox,
229
+ expression,
230
+ awaitPromise,
231
+ resultOwnership = null
232
+ ) {
233
+ const params = {
234
+ expression: expression,
235
+ awaitPromise: awaitPromise,
236
+ }
237
+ if (targetType === 'contextTarget') {
238
+ if (sandbox != null) {
239
+ params['target'] = { context: id, sandbox: sandbox }
240
+ } else {
241
+ params['target'] = { context: id }
242
+ }
243
+ } else {
244
+ params['target'] = { realm: id }
245
+ }
246
+ if (resultOwnership != null) {
247
+ params['resultOwnership'] = resultOwnership
248
+ }
249
+
250
+ return params
251
+ }
252
+
253
+ createEvaluateResult(response) {
254
+ var type = response.result.type
255
+ var realmId = response.result.realm
256
+ var evaluateResult
257
+
258
+ if (type === EvaluateResultType.SUCCESS) {
259
+ var result = response.result.result
260
+ evaluateResult = new EvaluateResultSuccess(
261
+ realmId,
262
+ new RemoteValue(result)
263
+ )
264
+ } else {
265
+ var exceptionDetails = response.result.exceptionDetails
266
+ evaluateResult = new EvaluateResultException(
267
+ realmId,
268
+ new ExceptionDetails(exceptionDetails)
269
+ )
270
+ }
271
+ return evaluateResult
272
+ }
273
+
274
+ realmInfoMapper(realms) {
275
+ var realmsList = []
276
+ realms.forEach((realm) => {
277
+ realmsList.push(RealmInfo.fromJson(realm))
278
+ })
279
+ return realmsList
280
+ }
281
+
282
+ async getAllRealms() {
283
+ const command = {
284
+ method: 'script.getRealms',
285
+ params: {},
286
+ }
287
+ let response = await this.bidi.send(command)
288
+ return this.realmInfoMapper(response.result.realms)
289
+ }
290
+
291
+ async getRealmsByType(type) {
292
+ const command = {
293
+ method: 'script.getRealms',
294
+ params: { type: type },
295
+ }
296
+ let response = await this.bidi.send(command)
297
+ return this.realmInfoMapper(response.result.realms)
298
+ }
299
+
300
+ async getRealmsInBrowsingContext(browsingContext) {
301
+ const command = {
302
+ method: 'script.getRealms',
303
+ params: { context: browsingContext },
304
+ }
305
+ let response = await this.bidi.send(command)
306
+ return this.realmInfoMapper(response.result.realms)
307
+ }
308
+
309
+ async getRealmsInBrowsingContextByType(browsingContext, type) {
310
+ const command = {
311
+ method: 'script.getRealms',
312
+ params: { context: browsingContext, type: type },
313
+ }
314
+ let response = await this.bidi.send(command)
315
+ return this.realmInfoMapper(response.result.realms)
316
+ }
317
+ }
318
+
319
+ async function getScriptManagerInstance(browsingContextId, driver) {
320
+ let instance = new ScriptManager(driver)
321
+ await instance.init(browsingContextId)
322
+ return instance
323
+ }
324
+
325
+ module.exports = getScriptManagerInstance
Binary file
Binary file
Binary file
package/chrome.js CHANGED
@@ -130,7 +130,6 @@
130
130
  const io = require('./io')
131
131
  const { Browser } = require('./lib/capabilities')
132
132
  const chromium = require('./chromium')
133
- const { driverLocation } = require('./common/seleniumManager')
134
133
 
135
134
  /**
136
135
  * Name of the ChromeDriver executable.
@@ -158,23 +157,6 @@ class ServiceBuilder extends chromium.ServiceBuilder {
158
157
  */
159
158
  constructor(opt_exe) {
160
159
  let exe = opt_exe || locateSynchronously()
161
-
162
- if (!exe) {
163
- try {
164
- exe = driverLocation(Browser.CHROME)
165
- } catch (err) {
166
- console.log(`Unable to obtain driver using Selenium Manager: ${err}`)
167
- }
168
- }
169
-
170
- if (!exe) {
171
- throw Error(
172
- `ChromeDriver could not be found on the PATH.
173
- For more information on how to install drivers see
174
- https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/.`
175
- )
176
- }
177
-
178
160
  super(exe)
179
161
  }
180
162
  }
package/chromium.js CHANGED
@@ -83,6 +83,7 @@ const error = require('./lib/error')
83
83
  const Symbols = require('./lib/symbols')
84
84
  const webdriver = require('./lib/webdriver')
85
85
  const remote = require('./remote')
86
+ const { getPath } = require('./common/driverFinder')
86
87
 
87
88
  /**
88
89
  * Custom command names supported by Chromium WebDriver.
@@ -684,6 +685,9 @@ class Driver extends webdriver.WebDriver {
684
685
  configureExecutor(executor, this.VENDOR_COMMAND_PREFIX)
685
686
  } else {
686
687
  let service = opt_serviceExecutor || this.getDefaultService()
688
+ if (!service.getExecutable()) {
689
+ service.setExecutable(getPath(service, caps))
690
+ }
687
691
  onQuit = () => service.kill()
688
692
  executor = createExecutor(service.start(), this.VENDOR_COMMAND_PREFIX)
689
693
  }
@@ -0,0 +1,59 @@
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
+ * This implementation is still in beta, and may change.
20
+ *
21
+ * Utility to find if a given file is present and executable.
22
+ */
23
+
24
+ const { driverLocation } = require('./seleniumManager')
25
+ const fs = require('fs')
26
+
27
+ /**
28
+ * Determines the path of the correct Selenium Manager binary
29
+ * @returns {string}
30
+ */
31
+ function getPath(service, capabilities) {
32
+ try {
33
+ return pathExists(service.getExecutable()) || driverLocation(capabilities)
34
+ } catch (e) {
35
+ throw Error(
36
+ `Unable to obtain browser driver.
37
+ For more information on how to install drivers see
38
+ https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/. ${e}`
39
+ )
40
+ }
41
+ }
42
+
43
+ /**
44
+ * _Synchronously_ attempts to locate the driver executable on the current
45
+ * system.
46
+ *
47
+ * @param {!string} driverPath
48
+ *
49
+ * @return {?string} the located executable, or `null`.
50
+ */
51
+ function pathExists(driverPath) {
52
+ if (!driverPath || !fs.existsSync(driverPath)) {
53
+ return null
54
+ }
55
+ return driverPath
56
+ }
57
+
58
+ // PUBLIC API
59
+ module.exports = { getPath }
@@ -24,13 +24,13 @@
24
24
  const { platform } = require('process')
25
25
  const path = require('path')
26
26
  const fs = require('fs')
27
- const execSync = require('child_process').execSync
27
+ const spawnSync = require('child_process').spawnSync
28
28
 
29
29
  /**
30
30
  * currently supported browsers for selenium-manager
31
31
  * @type {string[]}
32
32
  */
33
- const Browser = ['chrome', 'firefox', 'edge', 'iexplorer']
33
+ const Browser = ['chrome', 'firefox', 'edge', 'MicrosoftEdge', 'iexplorer']
34
34
 
35
35
  /**
36
36
  * Determines the path of the correct Selenium Manager binary
@@ -47,7 +47,14 @@ function getBinary() {
47
47
  const file =
48
48
  directory === 'windows' ? 'selenium-manager.exe' : 'selenium-manager'
49
49
 
50
- const filePath = path.join(__dirname, '..', '/bin', directory, file)
50
+ let seleniumManagerBasePath
51
+ if (process.env.SELENIUM_MANAGER_BASE_PATH) {
52
+ seleniumManagerBasePath = process.env.SELENIUM_MANAGER_BASE_PATH
53
+ } else {
54
+ seleniumManagerBasePath = path.join(__dirname, '..', '/bin')
55
+ }
56
+
57
+ const filePath = path.join(seleniumManagerBasePath, directory, file)
51
58
 
52
59
  if (!fs.existsSync(filePath)) {
53
60
  throw new Error(`Unable to obtain Selenium Manager`)
@@ -58,35 +65,55 @@ function getBinary() {
58
65
 
59
66
  /**
60
67
  * Determines the path of the correct driver
61
- * @param {Browser|string} browser name to fetch the driver
68
+ * @param {Capabilities} options browser options to fetch the driver
62
69
  * @returns {string} path of the driver location
63
70
  */
64
71
 
65
- function driverLocation(browser) {
66
- if (!Browser.includes(browser.toLocaleString())) {
72
+ function driverLocation(options) {
73
+ if (!Browser.includes(options.getBrowserName().toLocaleString())) {
67
74
  throw new Error(
68
- `Unable to locate driver associated with browser name: ${browser}`
75
+ `Unable to locate driver associated with browser name: ${options.getBrowserName()}`
69
76
  )
70
77
  }
71
78
 
72
- let args = [getBinary(), '--browser', browser, '--output', 'json']
73
- let output
79
+ let args = ['--browser', options.getBrowserName(), '--output', 'json']
80
+
81
+ if (options.getBrowserVersion() && options.getBrowserVersion() !== "") {
82
+ args.push("--browser-version", options.getBrowserVersion())
83
+ }
84
+
85
+ const vendorOptions = options.get('goog:chromeOptions') || options.get('ms:edgeOptions')
86
+ || options.get('moz:firefoxOptions')
87
+ if (vendorOptions && vendorOptions.binary && vendorOptions.binary !== "") {
88
+ args.push("--browser-path", '"' + vendorOptions.binary + '"')
89
+ }
74
90
 
91
+ const smBinary = getBinary()
92
+ const spawnResult = spawnSync(smBinary, args)
93
+ let output
94
+ if (spawnResult.status) {
95
+ let errorMessage
96
+ if (spawnResult.stderr.toString()) {
97
+ errorMessage = spawnResult.stderr.toString()
98
+ }
99
+ if (spawnResult.stdout.toString()) {
100
+ try {
101
+ output = JSON.parse(spawnResult.stdout.toString())
102
+ errorMessage = output.result.message
103
+ } catch (e) {
104
+ errorMessage = e.toString()
105
+ }
106
+ }
107
+ throw new Error(`Error executing command for ${smBinary} with ${args}: ${errorMessage}`)
108
+ }
75
109
  try {
76
- output = JSON.parse(execSync(args.join(' ')).toString())
110
+ output = JSON.parse(spawnResult.stdout.toString())
77
111
  } catch (e) {
78
- let error
79
- try {
80
- error = JSON.parse(e.stdout.toString()).result.message
81
- } catch (e) {
82
- error = e.toString()
83
- }
84
- throw new Error(
85
- `Error executing command with ${args}: ${error}`
86
- )
112
+ throw new Error(`Error executing command for ${smBinary} with ${args}: ${e.toString()}`)
87
113
  }
88
114
 
89
- for (const key in output.logs){
115
+
116
+ for (const key in output.logs) {
90
117
  if (output.logs[key].level === 'WARN') {
91
118
  console.warn(`${output.logs[key].message}`)
92
119
  }
package/edge.js CHANGED
@@ -80,7 +80,6 @@
80
80
  const { Browser } = require('./lib/capabilities')
81
81
  const io = require('./io')
82
82
  const chromium = require('./chromium')
83
- const { driverLocation } = require('./common/seleniumManager')
84
83
 
85
84
  /**
86
85
  * Name of the EdgeDriver executable.
@@ -107,22 +106,6 @@ class ServiceBuilder extends chromium.ServiceBuilder {
107
106
  */
108
107
  constructor(opt_exe) {
109
108
  let exe = opt_exe || locateSynchronously()
110
-
111
- if (!exe) {
112
- try {
113
- exe = driverLocation('edge')
114
- } catch (err) {
115
- console.log(`Unable to obtain driver using Selenium Manager: ${err}`)
116
- }
117
- }
118
-
119
- if (!exe) {
120
- throw Error(
121
- `MSEdgeDriver could not be found on the PATH.
122
- For more information on how to install drivers see
123
- https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/.`
124
- )
125
- }
126
109
  super(exe)
127
110
  this.setLoopback(true)
128
111
  }