selenium-webdriver 4.8.0 → 4.8.2
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.
- package/CHANGES.md +26 -0
- package/bin/linux/selenium-manager +0 -0
- package/bin/macos/selenium-manager +0 -0
- package/bin/windows/selenium-manager.exe +0 -0
- package/chrome.js +3 -8
- package/common/seleniumManager.js +16 -8
- package/devtools/CDPConnection.js +37 -0
- package/edge.js +3 -9
- package/firefox.js +3 -7
- package/ie.js +4 -9
- package/lib/pinnedScript.js +59 -0
- package/lib/webdriver.js +93 -2
- package/package.json +1 -1
package/CHANGES.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
## v4.8.2
|
|
2
|
+
|
|
3
|
+
#### :nail_care: Polish
|
|
4
|
+
|
|
5
|
+
* Add CDP support for v111 and remove v108
|
|
6
|
+
* Using json output with Selenium Manager
|
|
7
|
+
|
|
8
|
+
#### :bug: Bug Fix
|
|
9
|
+
|
|
10
|
+
fix: Using status from response (#11742)
|
|
11
|
+
|
|
12
|
+
## v4.8.1
|
|
13
|
+
|
|
14
|
+
#### :rocket: New Feature
|
|
15
|
+
|
|
16
|
+
* Add script pinning (#11584)
|
|
17
|
+
|
|
18
|
+
#### :nail_care: Polish
|
|
19
|
+
|
|
20
|
+
* Add CDP support for v110 and remove v107
|
|
21
|
+
* Updating Selenium Manager binaries for 4.8.1 release
|
|
22
|
+
|
|
23
|
+
#### :bug: Bug Fix
|
|
24
|
+
|
|
25
|
+
fix: iedriver download with selenium-manager #11579
|
|
26
|
+
|
|
1
27
|
## v4.8.0
|
|
2
28
|
|
|
3
29
|
#### :rocket: New Feature
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/chrome.js
CHANGED
|
@@ -160,10 +160,6 @@ class ServiceBuilder extends chromium.ServiceBuilder {
|
|
|
160
160
|
let exe = opt_exe || locateSynchronously()
|
|
161
161
|
|
|
162
162
|
if (!exe) {
|
|
163
|
-
console.log(
|
|
164
|
-
` The ChromeDriver could not be found on the current PATH, trying Selenium Manager`
|
|
165
|
-
)
|
|
166
|
-
|
|
167
163
|
try {
|
|
168
164
|
exe = driverLocation(Browser.CHROME)
|
|
169
165
|
} catch (err) {
|
|
@@ -173,10 +169,9 @@ class ServiceBuilder extends chromium.ServiceBuilder {
|
|
|
173
169
|
|
|
174
170
|
if (!exe) {
|
|
175
171
|
throw Error(
|
|
176
|
-
`
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
and ensure it can be found on your PATH.`
|
|
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/.`
|
|
180
175
|
)
|
|
181
176
|
}
|
|
182
177
|
|
|
@@ -30,7 +30,7 @@ const execSync = require('child_process').execSync
|
|
|
30
30
|
* currently supported browsers for selenium-manager
|
|
31
31
|
* @type {string[]}
|
|
32
32
|
*/
|
|
33
|
-
const Browser = ['chrome', 'firefox', 'edge']
|
|
33
|
+
const Browser = ['chrome', 'firefox', 'edge', 'iexplorer']
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Determines the path of the correct Selenium Manager binary
|
|
@@ -69,22 +69,30 @@ function driverLocation(browser) {
|
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
let args = [getBinary(), '--browser', browser]
|
|
73
|
-
let
|
|
72
|
+
let args = [getBinary(), '--browser', browser, '--output', 'json']
|
|
73
|
+
let output
|
|
74
74
|
|
|
75
75
|
try {
|
|
76
|
-
|
|
76
|
+
output = JSON.parse(execSync(args.join(' ')).toString())
|
|
77
77
|
} catch (e) {
|
|
78
|
+
let error
|
|
79
|
+
try {
|
|
80
|
+
error = JSON.parse(e.stdout.toString()).result.message
|
|
81
|
+
} catch (e) {
|
|
82
|
+
error = e.toString()
|
|
83
|
+
}
|
|
78
84
|
throw new Error(
|
|
79
|
-
`Error executing command with ${args}
|
|
85
|
+
`Error executing command with ${args}: ${error}`
|
|
80
86
|
)
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
for (const key in output.logs){
|
|
90
|
+
if (output.logs[key].level === 'WARN') {
|
|
91
|
+
console.warn(`${output.logs[key].message}`)
|
|
92
|
+
}
|
|
85
93
|
}
|
|
86
94
|
|
|
87
|
-
return result.
|
|
95
|
+
return output.result.message
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
// PUBLIC API
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
+
const RESPONSE_TIMEOUT = 1000 * 30
|
|
18
19
|
class CDPConnection {
|
|
19
20
|
constructor(wsConnection) {
|
|
20
21
|
this._wsConnection = wsConnection
|
|
@@ -35,6 +36,42 @@ class CDPConnection {
|
|
|
35
36
|
const mergedMessage = Object.assign({ params: params }, message)
|
|
36
37
|
this._wsConnection.send(JSON.stringify(mergedMessage), callback)
|
|
37
38
|
}
|
|
39
|
+
|
|
40
|
+
async send(method, params) {
|
|
41
|
+
let cdp_id = this.cmd_id++
|
|
42
|
+
let message = {
|
|
43
|
+
method,
|
|
44
|
+
id: cdp_id,
|
|
45
|
+
}
|
|
46
|
+
if (this.sessionId) {
|
|
47
|
+
message['sessionId'] = this.sessionId
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const mergedMessage = Object.assign({ params: params }, message)
|
|
51
|
+
this._wsConnection.send(JSON.stringify(mergedMessage))
|
|
52
|
+
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const timeoutId = setTimeout(() => {
|
|
55
|
+
reject(new Error(`Request with id ${cdp_id} timed out`))
|
|
56
|
+
handler.off('message', listener)
|
|
57
|
+
}, RESPONSE_TIMEOUT)
|
|
58
|
+
|
|
59
|
+
const listener = (data) => {
|
|
60
|
+
try {
|
|
61
|
+
const payload = JSON.parse(data.toString())
|
|
62
|
+
if (payload.id === cdp_id) {
|
|
63
|
+
clearTimeout(timeoutId)
|
|
64
|
+
handler.off('message', listener)
|
|
65
|
+
resolve(payload)
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.error(`Failed parse message: ${err.message}`)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const handler = this._wsConnection.on('message', listener)
|
|
73
|
+
})
|
|
74
|
+
}
|
|
38
75
|
}
|
|
39
76
|
|
|
40
77
|
exports.CdpConnection = CDPConnection
|
package/edge.js
CHANGED
|
@@ -109,10 +109,6 @@ class ServiceBuilder extends chromium.ServiceBuilder {
|
|
|
109
109
|
let exe = opt_exe || locateSynchronously()
|
|
110
110
|
|
|
111
111
|
if (!exe) {
|
|
112
|
-
console.log(
|
|
113
|
-
`The WebDriver for Edge could not be found on the current PATH, trying Selenium Manager`
|
|
114
|
-
)
|
|
115
|
-
|
|
116
112
|
try {
|
|
117
113
|
exe = driverLocation('edge')
|
|
118
114
|
} catch (err) {
|
|
@@ -122,13 +118,11 @@ class ServiceBuilder extends chromium.ServiceBuilder {
|
|
|
122
118
|
|
|
123
119
|
if (!exe) {
|
|
124
120
|
throw Error(
|
|
125
|
-
`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
`and ensure it can be found on your PATH.`
|
|
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/.`
|
|
129
124
|
)
|
|
130
125
|
}
|
|
131
|
-
|
|
132
126
|
super(exe)
|
|
133
127
|
this.setLoopback(true)
|
|
134
128
|
}
|
package/firefox.js
CHANGED
|
@@ -474,10 +474,6 @@ function findGeckoDriver() {
|
|
|
474
474
|
let exe = locateSynchronously()
|
|
475
475
|
|
|
476
476
|
if (!exe) {
|
|
477
|
-
console.log(
|
|
478
|
-
`The ${GECKO_DRIVER_EXE} executable could not be found on the current PATH, trying Selenium Manager`
|
|
479
|
-
)
|
|
480
|
-
|
|
481
477
|
try {
|
|
482
478
|
exe = driverLocation(Browser.FIREFOX)
|
|
483
479
|
} catch (err) {
|
|
@@ -487,9 +483,9 @@ function findGeckoDriver() {
|
|
|
487
483
|
|
|
488
484
|
if (!exe) {
|
|
489
485
|
throw Error(
|
|
490
|
-
`
|
|
491
|
-
|
|
492
|
-
|
|
486
|
+
`GeckoDriver could not be found on the PATH.
|
|
487
|
+
For more information on how to install drivers see
|
|
488
|
+
https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/.`
|
|
493
489
|
)
|
|
494
490
|
}
|
|
495
491
|
|
package/ie.js
CHANGED
|
@@ -401,12 +401,8 @@ function createServiceFromCapabilities(capabilities) {
|
|
|
401
401
|
|
|
402
402
|
let exe = locateSynchronously()
|
|
403
403
|
if (!exe) {
|
|
404
|
-
console.log(
|
|
405
|
-
`The ${IEDRIVER_EXE} executable could not be found on the current PATH, trying Selenium Manager`
|
|
406
|
-
)
|
|
407
|
-
|
|
408
404
|
try {
|
|
409
|
-
exe = driverLocation(
|
|
405
|
+
exe = driverLocation('iexplorer')
|
|
410
406
|
} catch (err) {
|
|
411
407
|
console.log(`Unable to obtain driver using Selenium Manager: ${err}`)
|
|
412
408
|
}
|
|
@@ -414,10 +410,9 @@ function createServiceFromCapabilities(capabilities) {
|
|
|
414
410
|
|
|
415
411
|
if (!exe || !fs.existsSync(exe)) {
|
|
416
412
|
throw Error(
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
'ensure it can be found on your system PATH.'
|
|
413
|
+
`IEDriver could not be found on the PATH.
|
|
414
|
+
For more information on how to install drivers see
|
|
415
|
+
https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/.`
|
|
421
416
|
)
|
|
422
417
|
}
|
|
423
418
|
|
|
@@ -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
|
+
const crypto = require('crypto')
|
|
19
|
+
|
|
20
|
+
class PinnedScript {
|
|
21
|
+
constructor(script) {
|
|
22
|
+
this.scriptSource_ = script
|
|
23
|
+
this.scriptHandle_ = crypto.randomUUID().replace(/-/gi, '')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get handle() {
|
|
27
|
+
return this.scriptHandle_
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get source() {
|
|
31
|
+
return this.scriptSource_
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get scriptId() {
|
|
35
|
+
return this.scriptId_
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set scriptId(id) {
|
|
39
|
+
this.scriptId_ = id
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
creationScript() {
|
|
43
|
+
return `function __webdriver_${this.scriptHandle_}(arguments) { ${this.scriptSource_} }`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
executionScript() {
|
|
47
|
+
return `return __webdriver_${this.scriptHandle_}(arguments)`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
removalScript() {
|
|
51
|
+
return `__webdriver_${this.scriptHandle_} = undefined`
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// PUBLIC API
|
|
56
|
+
|
|
57
|
+
module.exports = {
|
|
58
|
+
PinnedScript,
|
|
59
|
+
}
|
package/lib/webdriver.js
CHANGED
|
@@ -41,6 +41,7 @@ const { Credential } = require('./virtual_authenticator')
|
|
|
41
41
|
const webElement = require('./webelement')
|
|
42
42
|
const { isObject } = require('./util')
|
|
43
43
|
const BIDI = require('../bidi')
|
|
44
|
+
const { PinnedScript } = require('./pinnedScript')
|
|
44
45
|
|
|
45
46
|
// Capability names that are defined in the W3C spec.
|
|
46
47
|
const W3C_CAPABILITY_NAMES = new Set([
|
|
@@ -686,6 +687,8 @@ class WebDriver {
|
|
|
686
687
|
|
|
687
688
|
/** @private {./virtual_authenticator}*/
|
|
688
689
|
this.authenticatorId_ = null
|
|
690
|
+
|
|
691
|
+
this.pinnedScripts_ = {}
|
|
689
692
|
}
|
|
690
693
|
|
|
691
694
|
/**
|
|
@@ -795,6 +798,15 @@ class WebDriver {
|
|
|
795
798
|
if (typeof script === 'function') {
|
|
796
799
|
script = 'return (' + script + ').apply(null, arguments);'
|
|
797
800
|
}
|
|
801
|
+
|
|
802
|
+
if (script && script instanceof PinnedScript) {
|
|
803
|
+
return this.execute(
|
|
804
|
+
new command.Command(command.Name.EXECUTE_SCRIPT)
|
|
805
|
+
.setParameter('script', script.executionScript())
|
|
806
|
+
.setParameter('args', args)
|
|
807
|
+
)
|
|
808
|
+
}
|
|
809
|
+
|
|
798
810
|
return this.execute(
|
|
799
811
|
new command.Command(command.Name.EXECUTE_SCRIPT)
|
|
800
812
|
.setParameter('script', script)
|
|
@@ -807,6 +819,15 @@ class WebDriver {
|
|
|
807
819
|
if (typeof script === 'function') {
|
|
808
820
|
script = 'return (' + script + ').apply(null, arguments);'
|
|
809
821
|
}
|
|
822
|
+
|
|
823
|
+
if (script && script instanceof PinnedScript) {
|
|
824
|
+
return this.execute(
|
|
825
|
+
new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT)
|
|
826
|
+
.setParameter('script', script.executionScript())
|
|
827
|
+
.setParameter('args', args)
|
|
828
|
+
)
|
|
829
|
+
}
|
|
830
|
+
|
|
810
831
|
return this.execute(
|
|
811
832
|
new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT)
|
|
812
833
|
.setParameter('script', script)
|
|
@@ -1226,7 +1247,9 @@ class WebDriver {
|
|
|
1226
1247
|
this._wsUrl = await this.getWsUrl(debuggerUrl, target, caps)
|
|
1227
1248
|
return new Promise((resolve, reject) => {
|
|
1228
1249
|
try {
|
|
1229
|
-
this._wsConnection = new WebSocket(
|
|
1250
|
+
this._wsConnection = new WebSocket(
|
|
1251
|
+
this._wsUrl.replace('localhost', '127.0.0.1')
|
|
1252
|
+
)
|
|
1230
1253
|
this._cdpConnection = new cdp.CdpConnection(this._wsConnection)
|
|
1231
1254
|
} catch (err) {
|
|
1232
1255
|
reject(err)
|
|
@@ -1382,7 +1405,7 @@ class WebDriver {
|
|
|
1382
1405
|
if (requestPausedParams.request.url == httpResponse.urlToIntercept) {
|
|
1383
1406
|
connection.execute('Fetch.fulfillRequest', {
|
|
1384
1407
|
requestId: requestPausedParams['requestId'],
|
|
1385
|
-
responseCode:
|
|
1408
|
+
responseCode: httpResponse.status,
|
|
1386
1409
|
responseHeaders: httpResponse.headers,
|
|
1387
1410
|
body: httpResponse.body,
|
|
1388
1411
|
})
|
|
@@ -1532,6 +1555,74 @@ class WebDriver {
|
|
|
1532
1555
|
})
|
|
1533
1556
|
}
|
|
1534
1557
|
|
|
1558
|
+
async pinScript(script) {
|
|
1559
|
+
let pinnedScript = new PinnedScript(script)
|
|
1560
|
+
let connection
|
|
1561
|
+
if (Object.is(this._cdpConnection, undefined)) {
|
|
1562
|
+
connection = await this.createCDPConnection('page')
|
|
1563
|
+
} else {
|
|
1564
|
+
connection = this._cdpConnection
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
await connection.execute('Page.enable', {}, null)
|
|
1568
|
+
|
|
1569
|
+
await connection.execute(
|
|
1570
|
+
'Runtime.evaluate',
|
|
1571
|
+
{
|
|
1572
|
+
expression: pinnedScript.creationScript(),
|
|
1573
|
+
},
|
|
1574
|
+
null
|
|
1575
|
+
)
|
|
1576
|
+
|
|
1577
|
+
let result = await connection.send(
|
|
1578
|
+
'Page.addScriptToEvaluateOnNewDocument',
|
|
1579
|
+
{
|
|
1580
|
+
source: pinnedScript.creationScript(),
|
|
1581
|
+
}
|
|
1582
|
+
)
|
|
1583
|
+
|
|
1584
|
+
pinnedScript.scriptId = result['result']['identifier']
|
|
1585
|
+
|
|
1586
|
+
this.pinnedScripts_[pinnedScript.handle] = pinnedScript
|
|
1587
|
+
|
|
1588
|
+
return pinnedScript
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
async unpinScript(script) {
|
|
1592
|
+
if (script && !(script instanceof PinnedScript)) {
|
|
1593
|
+
throw Error(`Pass valid PinnedScript object. Received: ${script}`)
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
if (script.handle in this.pinnedScripts_) {
|
|
1597
|
+
let connection
|
|
1598
|
+
if (Object.is(this._cdpConnection, undefined)) {
|
|
1599
|
+
connection = this.createCDPConnection('page')
|
|
1600
|
+
} else {
|
|
1601
|
+
connection = this._cdpConnection
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
await connection.execute('Page.enable', {}, null)
|
|
1605
|
+
|
|
1606
|
+
await connection.execute(
|
|
1607
|
+
'Runtime.evaluate',
|
|
1608
|
+
{
|
|
1609
|
+
expression: script.removalScript(),
|
|
1610
|
+
},
|
|
1611
|
+
null
|
|
1612
|
+
)
|
|
1613
|
+
|
|
1614
|
+
await connection.execute(
|
|
1615
|
+
'Page.removeScriptToEvaluateOnLoad',
|
|
1616
|
+
{
|
|
1617
|
+
identifier: script.scriptId,
|
|
1618
|
+
},
|
|
1619
|
+
null
|
|
1620
|
+
)
|
|
1621
|
+
|
|
1622
|
+
delete this.pinnedScripts_[script.handle]
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1535
1626
|
/**
|
|
1536
1627
|
*
|
|
1537
1628
|
* @returns The value of authenticator ID added
|