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 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
@@ -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
- console.debug(`Selenium Manager binary found at ${filePath}`)
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
- console.warn(`${output.logs[key].message}`)
145
+ log_.warning(`${output.logs[key].message}`)
144
146
  }
145
147
  if (['DEBUG', 'INFO'].includes(output.logs[key].level)) {
146
- console.debug(`${output.logs[key].message}`)
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
- console.error(`Failed parse message: ${err.message}`)
70
+ logging
71
+ .getLogger(logging.Type.BROWSER)
72
+ .error(`Failed parse message: ${err.message}`)
69
73
  }
70
74
  }
71
75
 
@@ -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('webdriver.http').setLevel(logging.Level.ALL)
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('webdriver.Builder')
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
- console.log(`../../../bazel-bin/${file}`)
63
+ log_.log(`../../../bazel-bin/${file}`)
62
64
  return require(path.resolve(`../../../bazel-bin/${file}`))
63
65
  } catch (ex2) {
64
- console.log(ex2)
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
- LOG.finest(() => `Translating command: ${command.getName()}`)
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
- LOG.finest(() => `Transforming command for W3C: ${command.getName()}`)
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
- LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`)
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('webdriver.http.Executor')
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
- console.warn(
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
- console.warn(
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
- console.log(
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selenium-webdriver",
3
- "version": "4.14.0",
3
+ "version": "4.15.0",
4
4
  "description": "The official WebDriver JavaScript bindings from the Selenium project",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
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('webdriver.DriverService')
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
- console.warn(
58
- 'Deprecation: Support for Standalone Server 3.x will be removed soon. Please update to version 4.x'
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