selenium-webdriver 4.14.0 → 4.15.0
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 +16 -0
- package/bidi/browsingContext.js +144 -0
- package/bidi/browsingContextInspector.js +28 -0
- package/bin/linux/selenium-manager +0 -0
- package/bin/macos/selenium-manager +0 -0
- package/bin/windows/selenium-manager.exe +0 -0
- package/common/seleniumManager.js +5 -3
- package/devtools/CDPConnection.js +5 -1
- package/example/logging.js +1 -1
- package/index.js +1 -1
- package/lib/http.js +8 -8
- package/lib/webdriver.js +8 -3
- package/package.json +1 -1
- package/remote/index.js +1 -1
- package/remote/util.js +6 -3
package/CHANGES.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 4.15.0
|
|
2
|
+
|
|
3
|
+
#### :bug: Bug fix
|
|
4
|
+
|
|
5
|
+
* Replace calls to console.log with managed loggers (#12909)
|
|
6
|
+
|
|
7
|
+
#### :nail_care: Polish
|
|
8
|
+
|
|
9
|
+
* Add CDP v119 and remove v116
|
|
10
|
+
|
|
11
|
+
#### :rocket: New Feature
|
|
12
|
+
|
|
13
|
+
* Add BiDi captureScreenshot command (#12510)
|
|
14
|
+
* Add BiDi browsing context activate command, handle user prompt command and reload command
|
|
15
|
+
* Add BiDi browsing context commands and events (#13078)
|
|
16
|
+
|
|
1
17
|
## 4.14.0
|
|
2
18
|
|
|
3
19
|
#### :nail_care: Polish
|
package/bidi/browsingContext.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
+
const { InvalidArgumentError, NoSuchFrameError } = require('../lib/error')
|
|
18
19
|
const { BrowsingContextInfo } = require('./browsingContextTypes')
|
|
19
20
|
class BrowsingContext {
|
|
20
21
|
constructor(driver) {
|
|
@@ -165,6 +166,149 @@ class BrowsingContext {
|
|
|
165
166
|
const response = await this.bidi.send(params)
|
|
166
167
|
return new PrintResult(response.result.data)
|
|
167
168
|
}
|
|
169
|
+
|
|
170
|
+
async captureScreenshot() {
|
|
171
|
+
let params = {
|
|
172
|
+
method: 'browsingContext.captureScreenshot',
|
|
173
|
+
params: {
|
|
174
|
+
context: this._id,
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const response = await this.bidi.send(params)
|
|
179
|
+
this.checkErrorInScreenshot(response)
|
|
180
|
+
return response['result']['data']
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async captureBoxScreenshot(x, y, width, height) {
|
|
184
|
+
let params = {
|
|
185
|
+
method: 'browsingContext.captureScreenshot',
|
|
186
|
+
params: {
|
|
187
|
+
context: this._id,
|
|
188
|
+
clip: {
|
|
189
|
+
type: 'viewport',
|
|
190
|
+
x: x,
|
|
191
|
+
y: y,
|
|
192
|
+
width: width,
|
|
193
|
+
height: height,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const response = await this.bidi.send(params)
|
|
199
|
+
this.checkErrorInScreenshot(response)
|
|
200
|
+
return response['result']['data']
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async captureElementScreenshot(
|
|
204
|
+
sharedId,
|
|
205
|
+
handle = undefined,
|
|
206
|
+
scrollIntoView = undefined
|
|
207
|
+
) {
|
|
208
|
+
let params = {
|
|
209
|
+
method: 'browsingContext.captureScreenshot',
|
|
210
|
+
params: {
|
|
211
|
+
context: this._id,
|
|
212
|
+
clip: {
|
|
213
|
+
type: 'element',
|
|
214
|
+
element: {
|
|
215
|
+
sharedId: sharedId,
|
|
216
|
+
handle: handle,
|
|
217
|
+
},
|
|
218
|
+
scrollIntoView: scrollIntoView,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const response = await this.bidi.send(params)
|
|
224
|
+
this.checkErrorInScreenshot(response)
|
|
225
|
+
return response['result']['data']
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
checkErrorInScreenshot(response) {
|
|
229
|
+
if ('error' in response) {
|
|
230
|
+
const { error, msg } = response
|
|
231
|
+
|
|
232
|
+
switch (error) {
|
|
233
|
+
case 'invalid argument':
|
|
234
|
+
throw new InvalidArgumentError(msg)
|
|
235
|
+
|
|
236
|
+
case 'no such frame':
|
|
237
|
+
throw new NoSuchFrameError(msg)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async activate() {
|
|
243
|
+
const params = {
|
|
244
|
+
method: 'browsingContext.activate',
|
|
245
|
+
params: {
|
|
246
|
+
context: this._id,
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let result = await this.bidi.send(params)
|
|
251
|
+
if ('error' in result) {
|
|
252
|
+
throw Error(result['error'])
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async handleUserPrompt(accept = undefined, userText = undefined) {
|
|
257
|
+
const params = {
|
|
258
|
+
method: 'browsingContext.handleUserPrompt',
|
|
259
|
+
params: {
|
|
260
|
+
context: this._id,
|
|
261
|
+
accept: accept,
|
|
262
|
+
userText: userText,
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
let result = await this.bidi.send(params)
|
|
267
|
+
if ('error' in result) {
|
|
268
|
+
throw Error(result['error'])
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async reload(ignoreCache = undefined, readinessState = undefined) {
|
|
273
|
+
if (
|
|
274
|
+
readinessState !== undefined &&
|
|
275
|
+
!['none', 'interactive', 'complete'].includes(readinessState)
|
|
276
|
+
) {
|
|
277
|
+
throw Error(
|
|
278
|
+
`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const params = {
|
|
283
|
+
method: 'browsingContext.reload',
|
|
284
|
+
params: {
|
|
285
|
+
context: this._id,
|
|
286
|
+
ignoreCache: ignoreCache,
|
|
287
|
+
wait: readinessState,
|
|
288
|
+
},
|
|
289
|
+
}
|
|
290
|
+
const navigateResult = (await this.bidi.send(params))['result']
|
|
291
|
+
|
|
292
|
+
return new NavigateResult(
|
|
293
|
+
navigateResult['url'],
|
|
294
|
+
navigateResult['navigation']
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async setViewport(width, height, devicePixelRatio = undefined) {
|
|
299
|
+
const params = {
|
|
300
|
+
method: 'browsingContext.setViewport',
|
|
301
|
+
params: {
|
|
302
|
+
context: this._id,
|
|
303
|
+
viewport: { width: width, height: height },
|
|
304
|
+
devicePixelRatio: devicePixelRatio,
|
|
305
|
+
},
|
|
306
|
+
}
|
|
307
|
+
let result = await this.bidi.send(params)
|
|
308
|
+
if ('error' in result) {
|
|
309
|
+
throw Error(result['error'])
|
|
310
|
+
}
|
|
311
|
+
}
|
|
168
312
|
}
|
|
169
313
|
|
|
170
314
|
class NavigateResult {
|
|
@@ -37,6 +37,34 @@ class BrowsingContextInspector {
|
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
async onNavigationStarted(callback) {
|
|
41
|
+
await this.subscribeAndHandleEvent(
|
|
42
|
+
'browsingContext.navigationStarted',
|
|
43
|
+
callback
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async onFragmentNavigated(callback) {
|
|
48
|
+
await this.subscribeAndHandleEvent(
|
|
49
|
+
'browsingContext.fragmentNavigated',
|
|
50
|
+
callback
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async onUserPromptClosed(callback) {
|
|
55
|
+
await this.subscribeAndHandleEvent(
|
|
56
|
+
'browsingContext.userPromptClosed',
|
|
57
|
+
callback
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async onUserPromptOpened(callback) {
|
|
62
|
+
await this.subscribeAndHandleEvent(
|
|
63
|
+
'browsingContext.userPromptOpened',
|
|
64
|
+
callback
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
40
68
|
async onDomContentLoaded(callback) {
|
|
41
69
|
await this.subscribeAndHandleEvent(
|
|
42
70
|
'browsingContext.domContentLoaded',
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -26,7 +26,9 @@ const path = require('path')
|
|
|
26
26
|
const fs = require('fs')
|
|
27
27
|
const spawnSync = require('child_process').spawnSync
|
|
28
28
|
const { Capability } = require('../lib/capabilities')
|
|
29
|
+
const logging = require('../lib/logging')
|
|
29
30
|
|
|
31
|
+
const log_ = logging.getLogger(logging.Type.DRIVER)
|
|
30
32
|
let debugMessagePrinted = false
|
|
31
33
|
|
|
32
34
|
/**
|
|
@@ -53,7 +55,7 @@ function getBinary() {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
if (!debugMessagePrinted) {
|
|
56
|
-
|
|
58
|
+
log_.debug(`Selenium Manager binary found at ${filePath}`)
|
|
57
59
|
debugMessagePrinted = true // Set the flag to true after printing the debug message
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -140,10 +142,10 @@ function driverLocation(options) {
|
|
|
140
142
|
function logOutput(output) {
|
|
141
143
|
for (const key in output.logs) {
|
|
142
144
|
if (output.logs[key].level === 'WARN') {
|
|
143
|
-
|
|
145
|
+
log_.warning(`${output.logs[key].message}`)
|
|
144
146
|
}
|
|
145
147
|
if (['DEBUG', 'INFO'].includes(output.logs[key].level)) {
|
|
146
|
-
|
|
148
|
+
log_.debug(`${output.logs[key].message}`)
|
|
147
149
|
}
|
|
148
150
|
}
|
|
149
151
|
}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
+
const logging = require('../lib/logging')
|
|
19
|
+
|
|
18
20
|
const RESPONSE_TIMEOUT = 1000 * 30
|
|
19
21
|
class CDPConnection {
|
|
20
22
|
constructor(wsConnection) {
|
|
@@ -65,7 +67,9 @@ class CDPConnection {
|
|
|
65
67
|
resolve(payload)
|
|
66
68
|
}
|
|
67
69
|
} catch (err) {
|
|
68
|
-
|
|
70
|
+
logging
|
|
71
|
+
.getLogger(logging.Type.BROWSER)
|
|
72
|
+
.error(`Failed parse message: ${err.message}`)
|
|
69
73
|
}
|
|
70
74
|
}
|
|
71
75
|
|
package/example/logging.js
CHANGED
|
@@ -27,7 +27,7 @@ const edge = require('../edge')
|
|
|
27
27
|
const { Builder, By, Key, logging, until } = require('..')
|
|
28
28
|
|
|
29
29
|
logging.installConsoleHandler()
|
|
30
|
-
logging.getLogger(
|
|
30
|
+
logging.getLogger(`${logging.Type.DRIVER}.http`).setLevel(logging.Level.ALL)
|
|
31
31
|
;(async function () {
|
|
32
32
|
let driver
|
|
33
33
|
try {
|
package/index.js
CHANGED
|
@@ -194,7 +194,7 @@ function createDriver(ctor, ...args) {
|
|
|
194
194
|
class Builder {
|
|
195
195
|
constructor() {
|
|
196
196
|
/** @private @const */
|
|
197
|
-
this.log_ = logging.getLogger(
|
|
197
|
+
this.log_ = logging.getLogger(`${logging.Type.DRIVER}.Builder`)
|
|
198
198
|
|
|
199
199
|
/** @private {string} */
|
|
200
200
|
this.url_ = ''
|
package/lib/http.js
CHANGED
|
@@ -34,6 +34,8 @@ const { Session } = require('./session')
|
|
|
34
34
|
const webElement = require('./webelement')
|
|
35
35
|
const { isObject } = require('./util')
|
|
36
36
|
|
|
37
|
+
const log_ = logging.getLogger(`${logging.Type.DRIVER}.http`)
|
|
38
|
+
|
|
37
39
|
const getAttribute = requireAtom(
|
|
38
40
|
'get-attribute.js',
|
|
39
41
|
'//javascript/node/selenium-webdriver/lib/atoms:get-attribute.js'
|
|
@@ -58,10 +60,10 @@ function requireAtom(module, bazelTarget) {
|
|
|
58
60
|
} catch (ex) {
|
|
59
61
|
try {
|
|
60
62
|
const file = bazelTarget.slice(2).replace(':', '/')
|
|
61
|
-
|
|
63
|
+
log_.log(`../../../bazel-bin/${file}`)
|
|
62
64
|
return require(path.resolve(`../../../bazel-bin/${file}`))
|
|
63
65
|
} catch (ex2) {
|
|
64
|
-
|
|
66
|
+
log_.error(ex2)
|
|
65
67
|
throw Error(
|
|
66
68
|
`Failed to import atoms module ${module}. If running in dev mode, you` +
|
|
67
69
|
` need to run \`bazel build ${bazelTarget}\` from the project` +
|
|
@@ -153,8 +155,6 @@ const Atom = {
|
|
|
153
155
|
FIND_ELEMENTS: findElements,
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
const LOG = logging.getLogger('webdriver.http')
|
|
157
|
-
|
|
158
158
|
function post(path) {
|
|
159
159
|
return resource('POST', path)
|
|
160
160
|
}
|
|
@@ -428,7 +428,7 @@ class Client {
|
|
|
428
428
|
* command to execute.
|
|
429
429
|
*/
|
|
430
430
|
function buildRequest(customCommands, command) {
|
|
431
|
-
|
|
431
|
+
log_.finest(() => `Translating command: ${command.getName()}`)
|
|
432
432
|
let spec = customCommands && customCommands.get(command.getName())
|
|
433
433
|
if (spec) {
|
|
434
434
|
return toHttpRequest(spec)
|
|
@@ -436,7 +436,7 @@ function buildRequest(customCommands, command) {
|
|
|
436
436
|
|
|
437
437
|
spec = W3C_COMMAND_MAP.get(command.getName())
|
|
438
438
|
if (typeof spec === 'function') {
|
|
439
|
-
|
|
439
|
+
log_.finest(() => `Transforming command for W3C: ${command.getName()}`)
|
|
440
440
|
let newCommand = spec(command)
|
|
441
441
|
return buildRequest(customCommands, newCommand)
|
|
442
442
|
} else if (spec) {
|
|
@@ -451,7 +451,7 @@ function buildRequest(customCommands, command) {
|
|
|
451
451
|
* @return {!Request}
|
|
452
452
|
*/
|
|
453
453
|
function toHttpRequest(resource) {
|
|
454
|
-
|
|
454
|
+
log_.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`)
|
|
455
455
|
let parameters = command.getParameters()
|
|
456
456
|
let path = buildPath(resource.path, parameters)
|
|
457
457
|
return new Request(resource.method, path, parameters)
|
|
@@ -487,7 +487,7 @@ class Executor {
|
|
|
487
487
|
this.customCommands_ = null
|
|
488
488
|
|
|
489
489
|
/** @private {!logging.Logger} */
|
|
490
|
-
this.log_ = logging.getLogger(
|
|
490
|
+
this.log_ = logging.getLogger(`${logging.Type.DRIVER}.http.Executor`)
|
|
491
491
|
}
|
|
492
492
|
|
|
493
493
|
/**
|
package/lib/webdriver.js
CHANGED
|
@@ -2158,6 +2158,8 @@ class Window {
|
|
|
2158
2158
|
constructor(driver) {
|
|
2159
2159
|
/** @private {!WebDriver} */
|
|
2160
2160
|
this.driver_ = driver
|
|
2161
|
+
/** @private {!Logger} */
|
|
2162
|
+
this.log_ = logging.getLogger(logging.Type.DRIVER)
|
|
2161
2163
|
}
|
|
2162
2164
|
|
|
2163
2165
|
/**
|
|
@@ -2252,7 +2254,7 @@ class Window {
|
|
|
2252
2254
|
*/
|
|
2253
2255
|
async getSize(windowHandle = 'current') {
|
|
2254
2256
|
if (windowHandle !== 'current') {
|
|
2255
|
-
|
|
2257
|
+
this.log_.warning(
|
|
2256
2258
|
`Only 'current' window is supported for W3C compatible browsers.`
|
|
2257
2259
|
)
|
|
2258
2260
|
}
|
|
@@ -2275,7 +2277,7 @@ class Window {
|
|
|
2275
2277
|
windowHandle = 'current'
|
|
2276
2278
|
) {
|
|
2277
2279
|
if (windowHandle !== 'current') {
|
|
2278
|
-
|
|
2280
|
+
this.log_.warning(
|
|
2279
2281
|
`Only 'current' window is supported for W3C compatible browsers.`
|
|
2280
2282
|
)
|
|
2281
2283
|
}
|
|
@@ -2547,6 +2549,9 @@ class WebElement {
|
|
|
2547
2549
|
|
|
2548
2550
|
/** @private {!Promise<string>} */
|
|
2549
2551
|
this.id_ = Promise.resolve(id)
|
|
2552
|
+
|
|
2553
|
+
/** @private {!Logger} */
|
|
2554
|
+
this.log_ = logging.getLogger(logging.Type.DRIVER)
|
|
2550
2555
|
}
|
|
2551
2556
|
|
|
2552
2557
|
/**
|
|
@@ -2794,7 +2799,7 @@ class WebElement {
|
|
|
2794
2799
|
keys.join('')
|
|
2795
2800
|
)
|
|
2796
2801
|
} catch (ex) {
|
|
2797
|
-
|
|
2802
|
+
this.log_.error(
|
|
2798
2803
|
'Error trying parse string as a file with file detector; sending keys instead' +
|
|
2799
2804
|
ex
|
|
2800
2805
|
)
|
package/package.json
CHANGED
package/remote/index.js
CHANGED
|
@@ -120,7 +120,7 @@ class DriverService {
|
|
|
120
120
|
*/
|
|
121
121
|
constructor(executable, options) {
|
|
122
122
|
/** @private @const */
|
|
123
|
-
this.log_ = logging.getLogger(
|
|
123
|
+
this.log_ = logging.getLogger(`${logging.Type.DRIVER}.DriverService`)
|
|
124
124
|
/** @private {string} */
|
|
125
125
|
this.executable_ = executable
|
|
126
126
|
|
package/remote/util.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
const path = require('path')
|
|
21
21
|
const cp = require('child_process')
|
|
22
|
+
const logging = require('../lib/logging')
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* returns path to java or 'java' string if JAVA_HOME does not exist in env obj
|
|
@@ -54,9 +55,11 @@ function isSelenium3x(seleniumStandalonePath) {
|
|
|
54
55
|
*/
|
|
55
56
|
function formatSpawnArgs(seleniumStandalonePath, args) {
|
|
56
57
|
if (isSelenium3x(seleniumStandalonePath)) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
logging
|
|
59
|
+
.getLogger(logging.Type.SERVER)
|
|
60
|
+
.warning(
|
|
61
|
+
'Deprecation: Support for Standalone Server 3.x will be removed soon. Please update to version 4.x',
|
|
62
|
+
)
|
|
60
63
|
return args
|
|
61
64
|
}
|
|
62
65
|
|