selenium-webdriver 4.22.0 → 4.24.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 +24 -0
- package/bidi/argumentValue.js +6 -1
- package/bidi/browsingContextInspector.js +25 -2
- package/bidi/index.js +14 -6
- package/bidi/logEntries.js +15 -17
- package/bidi/logInspector.js +15 -3
- package/bidi/network.js +73 -12
- package/bidi/protocolValue.js +89 -3
- package/bidi/scriptManager.js +79 -9
- package/bin/linux/selenium-manager +0 -0
- package/bin/macos/selenium-manager +0 -0
- package/bin/windows/selenium-manager.exe +0 -0
- package/index.js +2 -0
- package/lib/atoms/bidi-mutation-listener.js +55 -0
- package/lib/atoms/find-elements.js +1 -1
- package/lib/atoms/get-attribute.js +2 -2
- package/lib/atoms/is-displayed.js +1 -1
- package/lib/network.js +78 -0
- package/lib/pinnedScript.js +1 -0
- package/lib/script.js +79 -0
- package/lib/webdriver.js +12 -0
- package/package.json +16 -15
- package/testing/index.js +99 -0
package/CHANGES.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 4.24.0
|
|
2
|
+
|
|
3
|
+
- [js] expose selenium version for node.js (#14325)
|
|
4
|
+
- [bidi] Add authentication handlers
|
|
5
|
+
- [bidi] Add high-level script command (#14293)
|
|
6
|
+
- Handle optional dependency for @bazel/runfiles
|
|
7
|
+
- remove console msg and safe exit if runfiles never found
|
|
8
|
+
- fix rbe build(use global node process)
|
|
9
|
+
- Fix error handling for missing runfiles
|
|
10
|
+
- [ci] Use a tag to figure out what we might want to release (#14378)
|
|
11
|
+
- Add CDP for Chrome 128 and remove 125
|
|
12
|
+
|
|
13
|
+
## 4.23.0
|
|
14
|
+
|
|
15
|
+
- Expose pnpm as a tool we can use
|
|
16
|
+
- [bidi] Fix the event unsubscribe method. Update modules to have close methods. (#14192)
|
|
17
|
+
- Run Node browser tests on the RBE (#14194)
|
|
18
|
+
- [bidi] Add methods to add/remove handlers in Script module (#14230)
|
|
19
|
+
- [bidi] Add source type to log entry (#14244)
|
|
20
|
+
- [bidi] Add dom mutation handlers (#14238)
|
|
21
|
+
- [bidi] Add high-level script pinning APIs (#14250)
|
|
22
|
+
- [bidi] Deprecate argument value wrapper class (#14251)
|
|
23
|
+
- Add CDP for Chrome 127 and remove 124
|
|
24
|
+
|
|
1
25
|
## 4.22.0
|
|
2
26
|
|
|
3
27
|
- [bidi] Add types for user prompt related events (#14097)
|
package/bidi/argumentValue.js
CHANGED
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
|
|
18
18
|
const { LocalValue } = require('./protocolValue')
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated
|
|
22
|
+
* in favor of LocalValue methods for all argument values.
|
|
23
|
+
* This extra wrapper is not required.
|
|
24
|
+
*/
|
|
20
25
|
class ArgumentValue {
|
|
21
26
|
constructor(value) {
|
|
22
27
|
this.value = value
|
|
@@ -24,7 +29,7 @@ class ArgumentValue {
|
|
|
24
29
|
|
|
25
30
|
asMap() {
|
|
26
31
|
if (this.value instanceof LocalValue) {
|
|
27
|
-
return this.value.
|
|
32
|
+
return this.value.asMap()
|
|
28
33
|
} else {
|
|
29
34
|
// ReferenceValue
|
|
30
35
|
return this.value.asMap()
|
|
@@ -127,10 +127,10 @@ class BrowsingContextInspector {
|
|
|
127
127
|
let response = null
|
|
128
128
|
if ('navigation' in params) {
|
|
129
129
|
response = new NavigationInfo(params.context, params.navigation, params.timestamp, params.url)
|
|
130
|
-
} else if ('type' in params) {
|
|
131
|
-
response = new UserPromptOpened(params.context, params.type, params.message)
|
|
132
130
|
} else if ('accepted' in params) {
|
|
133
131
|
response = new UserPromptClosed(params.context, params.accepted, params.userText)
|
|
132
|
+
} else if ('type' in params) {
|
|
133
|
+
response = new UserPromptOpened(params.context, params.type, params.message)
|
|
134
134
|
} else {
|
|
135
135
|
response = new BrowsingContextInfo(params.context, params.url, params.children, params.parent)
|
|
136
136
|
}
|
|
@@ -138,6 +138,29 @@ class BrowsingContextInspector {
|
|
|
138
138
|
}
|
|
139
139
|
})
|
|
140
140
|
}
|
|
141
|
+
|
|
142
|
+
async close() {
|
|
143
|
+
if (
|
|
144
|
+
this._browsingContextIds !== null &&
|
|
145
|
+
this._browsingContextIds !== undefined &&
|
|
146
|
+
this._browsingContextIds.length > 0
|
|
147
|
+
) {
|
|
148
|
+
await this.bidi.unsubscribe(
|
|
149
|
+
'browsingContext.contextCreated',
|
|
150
|
+
'browsingContext.contextDestroyed',
|
|
151
|
+
'browsingContext.fragmentNavigated',
|
|
152
|
+
'browsingContext.userPromptClosed',
|
|
153
|
+
this._browsingContextIds,
|
|
154
|
+
)
|
|
155
|
+
} else {
|
|
156
|
+
await this.bidi.unsubscribe(
|
|
157
|
+
'browsingContext.contextCreated',
|
|
158
|
+
'browsingContext.contextDestroyed',
|
|
159
|
+
'browsingContext.fragmentNavigated',
|
|
160
|
+
'browsingContext.userPromptClosed',
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
141
164
|
}
|
|
142
165
|
|
|
143
166
|
async function getBrowsingContextInstance(driver, browsingContextIds = null) {
|
package/bidi/index.js
CHANGED
|
@@ -157,6 +157,8 @@ class Index extends EventEmitter {
|
|
|
157
157
|
params.params.contexts = contextsArray
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
this.events.push(...eventsArray)
|
|
161
|
+
|
|
160
162
|
await this.send(params)
|
|
161
163
|
}
|
|
162
164
|
|
|
@@ -167,11 +169,14 @@ class Index extends EventEmitter {
|
|
|
167
169
|
* @returns {Promise<void>}
|
|
168
170
|
*/
|
|
169
171
|
async unsubscribe(events, browsingContexts) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
const eventsToRemove = typeof events === 'string' ? [events] : events
|
|
173
|
+
|
|
174
|
+
// Check if the eventsToRemove are in the subscribed events array
|
|
175
|
+
// Filter out events that are not in this.events before filtering
|
|
176
|
+
const existingEvents = eventsToRemove.filter((event) => this.events.includes(event))
|
|
177
|
+
|
|
178
|
+
// Remove the events from the subscribed events array
|
|
179
|
+
this.events = this.events.filter((event) => !existingEvents.includes(event))
|
|
175
180
|
|
|
176
181
|
if (typeof browsingContexts === 'string') {
|
|
177
182
|
this.browsingContexts.pop()
|
|
@@ -179,10 +184,13 @@ class Index extends EventEmitter {
|
|
|
179
184
|
this.browsingContexts = this.browsingContexts.filter((id) => !browsingContexts.includes(id))
|
|
180
185
|
}
|
|
181
186
|
|
|
187
|
+
if (existingEvents.length === 0) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
182
190
|
const params = {
|
|
183
191
|
method: 'session.unsubscribe',
|
|
184
192
|
params: {
|
|
185
|
-
events:
|
|
193
|
+
events: existingEvents,
|
|
186
194
|
},
|
|
187
195
|
}
|
|
188
196
|
|
package/bidi/logEntries.js
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
'use strict'
|
|
19
19
|
|
|
20
|
+
const { Source } = require('./scriptTypes')
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* Represents a base log entry.
|
|
22
24
|
* Desribed in https://w3c.github.io/webdriver-bidi/#types-log-logentry.
|
|
@@ -25,12 +27,14 @@ class BaseLogEntry {
|
|
|
25
27
|
/**
|
|
26
28
|
* Creates a new instance of BaseLogEntry.
|
|
27
29
|
* @param {string} level - The log level.
|
|
30
|
+
* @param {string} text - The log source.
|
|
28
31
|
* @param {string} text - The log text.
|
|
29
32
|
* @param {number} timeStamp - The log timestamp.
|
|
30
33
|
* @param {string} stackTrace - The log stack trace.
|
|
31
34
|
*/
|
|
32
|
-
constructor(level, text, timeStamp, stackTrace) {
|
|
35
|
+
constructor(level, source, text, timeStamp, stackTrace) {
|
|
33
36
|
this._level = level
|
|
37
|
+
this._source = new Source(source)
|
|
34
38
|
this._text = text
|
|
35
39
|
this._timeStamp = timeStamp
|
|
36
40
|
this._stackTrace = stackTrace
|
|
@@ -67,6 +71,10 @@ class BaseLogEntry {
|
|
|
67
71
|
get stackTrace() {
|
|
68
72
|
return this._stackTrace
|
|
69
73
|
}
|
|
74
|
+
|
|
75
|
+
get source() {
|
|
76
|
+
return this._source
|
|
77
|
+
}
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
/**
|
|
@@ -83,8 +91,8 @@ class GenericLogEntry extends BaseLogEntry {
|
|
|
83
91
|
* @param {string} type - The log type.
|
|
84
92
|
* @param {string} stackTrace - The log stack trace.
|
|
85
93
|
*/
|
|
86
|
-
constructor(level, text, timeStamp, type, stackTrace) {
|
|
87
|
-
super(level, text, timeStamp, stackTrace)
|
|
94
|
+
constructor(level, source, text, timeStamp, type, stackTrace) {
|
|
95
|
+
super(level, source, text, timeStamp, stackTrace)
|
|
88
96
|
this._type = type
|
|
89
97
|
}
|
|
90
98
|
|
|
@@ -103,10 +111,9 @@ class GenericLogEntry extends BaseLogEntry {
|
|
|
103
111
|
* @extends GenericLogEntry
|
|
104
112
|
*/
|
|
105
113
|
class ConsoleLogEntry extends GenericLogEntry {
|
|
106
|
-
constructor(level, text, timeStamp, type, method,
|
|
107
|
-
super(level, text, timeStamp, type, stackTrace)
|
|
114
|
+
constructor(level, source, text, timeStamp, type, method, args, stackTrace) {
|
|
115
|
+
super(level, source, text, timeStamp, type, stackTrace)
|
|
108
116
|
this._method = method
|
|
109
|
-
this._realm = realm
|
|
110
117
|
this._args = args
|
|
111
118
|
}
|
|
112
119
|
|
|
@@ -117,15 +124,6 @@ class ConsoleLogEntry extends GenericLogEntry {
|
|
|
117
124
|
get method() {
|
|
118
125
|
return this._method
|
|
119
126
|
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Gets the realm associated with the log entry.
|
|
123
|
-
* @returns {string} The realm associated with the log entry.
|
|
124
|
-
*/
|
|
125
|
-
get realm() {
|
|
126
|
-
return this._realm
|
|
127
|
-
}
|
|
128
|
-
|
|
129
127
|
/**
|
|
130
128
|
* Gets the arguments associated with the log entry.
|
|
131
129
|
* @returns {Array} The arguments associated with the log entry.
|
|
@@ -141,8 +139,8 @@ class ConsoleLogEntry extends GenericLogEntry {
|
|
|
141
139
|
* @extends GenericLogEntry
|
|
142
140
|
*/
|
|
143
141
|
class JavascriptLogEntry extends GenericLogEntry {
|
|
144
|
-
constructor(level, text, timeStamp, type, stackTrace) {
|
|
145
|
-
super(level, text, timeStamp, type, stackTrace)
|
|
142
|
+
constructor(level, source, text, timeStamp, type, stackTrace) {
|
|
143
|
+
super(level, source, text, timeStamp, type, stackTrace)
|
|
146
144
|
}
|
|
147
145
|
}
|
|
148
146
|
|
package/bidi/logInspector.js
CHANGED
|
@@ -128,11 +128,11 @@ class LogInspector {
|
|
|
128
128
|
if (params?.type === LOG.TYPE_CONSOLE) {
|
|
129
129
|
let consoleEntry = new ConsoleLogEntry(
|
|
130
130
|
params.level,
|
|
131
|
+
params.source,
|
|
131
132
|
params.text,
|
|
132
133
|
params.timestamp,
|
|
133
134
|
params.type,
|
|
134
135
|
params.method,
|
|
135
|
-
params.realm,
|
|
136
136
|
params.args,
|
|
137
137
|
params.stackTrace,
|
|
138
138
|
)
|
|
@@ -178,6 +178,7 @@ class LogInspector {
|
|
|
178
178
|
if (params?.type === LOG.TYPE_JS_LOGS) {
|
|
179
179
|
let jsEntry = new JavascriptLogEntry(
|
|
180
180
|
params.level,
|
|
181
|
+
params.source,
|
|
181
182
|
params.text,
|
|
182
183
|
params.timestamp,
|
|
183
184
|
params.type,
|
|
@@ -212,6 +213,7 @@ class LogInspector {
|
|
|
212
213
|
if (params?.type === 'javascript' && params?.level === 'error') {
|
|
213
214
|
let jsErrorEntry = new JavascriptLogEntry(
|
|
214
215
|
params.level,
|
|
216
|
+
params.source,
|
|
215
217
|
params.text,
|
|
216
218
|
params.timestamp,
|
|
217
219
|
params.type,
|
|
@@ -250,6 +252,7 @@ class LogInspector {
|
|
|
250
252
|
if (params?.type === 'javascript') {
|
|
251
253
|
let jsEntry = new JavascriptLogEntry(
|
|
252
254
|
params.level,
|
|
255
|
+
params.source,
|
|
253
256
|
params.text,
|
|
254
257
|
params.timestamp,
|
|
255
258
|
params.type,
|
|
@@ -279,11 +282,11 @@ class LogInspector {
|
|
|
279
282
|
if (params?.type === 'console') {
|
|
280
283
|
let consoleEntry = new ConsoleLogEntry(
|
|
281
284
|
params.level,
|
|
285
|
+
params.source,
|
|
282
286
|
params.text,
|
|
283
287
|
params.timestamp,
|
|
284
288
|
params.type,
|
|
285
289
|
params.method,
|
|
286
|
-
params.realm,
|
|
287
290
|
params.args,
|
|
288
291
|
params.stackTrace,
|
|
289
292
|
)
|
|
@@ -302,6 +305,7 @@ class LogInspector {
|
|
|
302
305
|
if (params !== undefined && !['console', 'javascript'].includes(params?.type)) {
|
|
303
306
|
let genericEntry = new GenericLogEntry(
|
|
304
307
|
params.level,
|
|
308
|
+
params.source,
|
|
305
309
|
params.text,
|
|
306
310
|
params.timestamp,
|
|
307
311
|
params.type,
|
|
@@ -330,7 +334,15 @@ class LogInspector {
|
|
|
330
334
|
* @returns {Promise<void>}
|
|
331
335
|
*/
|
|
332
336
|
async close() {
|
|
333
|
-
|
|
337
|
+
if (
|
|
338
|
+
this._browsingContextIds !== null &&
|
|
339
|
+
this._browsingContextIds !== undefined &&
|
|
340
|
+
this._browsingContextIds.length > 0
|
|
341
|
+
) {
|
|
342
|
+
await this.bidi.unsubscribe('log.entryAdded', this._browsingContextIds)
|
|
343
|
+
} else {
|
|
344
|
+
await this.bidi.unsubscribe('log.entryAdded')
|
|
345
|
+
}
|
|
334
346
|
}
|
|
335
347
|
}
|
|
336
348
|
|
package/bidi/network.js
CHANGED
|
@@ -21,11 +21,22 @@ const { ContinueResponseParameters } = require('./continueResponseParameters')
|
|
|
21
21
|
const { ContinueRequestParameters } = require('./continueRequestParameters')
|
|
22
22
|
const { ProvideResponseParameters } = require('./provideResponseParameters')
|
|
23
23
|
|
|
24
|
+
const NetworkEvent = {
|
|
25
|
+
BEFORE_REQUEST_SENT: 'network.beforeRequestSent',
|
|
26
|
+
RESPONSE_STARTED: 'network.responseStarted',
|
|
27
|
+
RESPONSE_COMPLETED: 'network.responseCompleted',
|
|
28
|
+
AUTH_REQUIRED: 'network.authRequired',
|
|
29
|
+
FETCH_ERROR: 'network.fetchError',
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
/**
|
|
25
33
|
* Represents all commands and events of Network module.
|
|
26
34
|
* Described in https://w3c.github.io/webdriver-bidi/#module-network.
|
|
27
35
|
*/
|
|
28
36
|
class Network {
|
|
37
|
+
#callbackId = 0
|
|
38
|
+
#listener
|
|
39
|
+
|
|
29
40
|
/**
|
|
30
41
|
* Represents a Network object.
|
|
31
42
|
* @constructor
|
|
@@ -35,6 +46,43 @@ class Network {
|
|
|
35
46
|
constructor(driver, browsingContextIds) {
|
|
36
47
|
this._driver = driver
|
|
37
48
|
this._browsingContextIds = browsingContextIds
|
|
49
|
+
this.#listener = new Map()
|
|
50
|
+
this.#listener.set(NetworkEvent.AUTH_REQUIRED, new Map())
|
|
51
|
+
this.#listener.set(NetworkEvent.BEFORE_REQUEST_SENT, new Map())
|
|
52
|
+
this.#listener.set(NetworkEvent.FETCH_ERROR, new Map())
|
|
53
|
+
this.#listener.set(NetworkEvent.RESPONSE_STARTED, new Map())
|
|
54
|
+
this.#listener.set(NetworkEvent.RESPONSE_COMPLETED, new Map())
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
addCallback(eventType, callback) {
|
|
58
|
+
const id = ++this.#callbackId
|
|
59
|
+
|
|
60
|
+
const eventCallbackMap = this.#listener.get(eventType)
|
|
61
|
+
eventCallbackMap.set(id, callback)
|
|
62
|
+
return id
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
removeCallback(id) {
|
|
66
|
+
let hasId = false
|
|
67
|
+
for (const [, callbacks] of this.#listener) {
|
|
68
|
+
if (callbacks.has(id)) {
|
|
69
|
+
callbacks.delete(id)
|
|
70
|
+
hasId = true
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!hasId) {
|
|
75
|
+
throw Error(`Callback with id ${id} not found`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
invokeCallbacks(eventType, data) {
|
|
80
|
+
const callbacks = this.#listener.get(eventType)
|
|
81
|
+
if (callbacks) {
|
|
82
|
+
for (const [, callback] of callbacks) {
|
|
83
|
+
callback(data)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
38
86
|
}
|
|
39
87
|
|
|
40
88
|
async init() {
|
|
@@ -75,10 +123,10 @@ class Network {
|
|
|
75
123
|
* Subscribes to the 'network.authRequired' event and handles it with the provided callback.
|
|
76
124
|
*
|
|
77
125
|
* @param {Function} callback - The callback function to handle the event.
|
|
78
|
-
* @returns {Promise<
|
|
126
|
+
* @returns {Promise<number>} - A promise that resolves when the subscription is successful.
|
|
79
127
|
*/
|
|
80
128
|
async authRequired(callback) {
|
|
81
|
-
await this.subscribeAndHandleEvent('network.authRequired', callback)
|
|
129
|
+
return await this.subscribeAndHandleEvent('network.authRequired', callback)
|
|
82
130
|
}
|
|
83
131
|
|
|
84
132
|
/**
|
|
@@ -97,10 +145,8 @@ class Network {
|
|
|
97
145
|
} else {
|
|
98
146
|
await this.bidi.subscribe(eventType)
|
|
99
147
|
}
|
|
100
|
-
|
|
101
|
-
}
|
|
148
|
+
let id = this.addCallback(eventType, callback)
|
|
102
149
|
|
|
103
|
-
async _on(callback) {
|
|
104
150
|
this.ws = await this.bidi.socket
|
|
105
151
|
this.ws.on('message', (event) => {
|
|
106
152
|
const { params } = JSON.parse(Buffer.from(event.toString()))
|
|
@@ -134,9 +180,10 @@ class Network {
|
|
|
134
180
|
params.errorText,
|
|
135
181
|
)
|
|
136
182
|
}
|
|
137
|
-
|
|
183
|
+
this.invokeCallbacks(eventType, response)
|
|
138
184
|
}
|
|
139
185
|
})
|
|
186
|
+
return id
|
|
140
187
|
}
|
|
141
188
|
|
|
142
189
|
/**
|
|
@@ -313,12 +360,26 @@ class Network {
|
|
|
313
360
|
* @returns {Promise<void>} A promise that resolves when the network connection is closed.
|
|
314
361
|
*/
|
|
315
362
|
async close() {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
363
|
+
if (
|
|
364
|
+
this._browsingContextIds !== null &&
|
|
365
|
+
this._browsingContextIds !== undefined &&
|
|
366
|
+
this._browsingContextIds.length > 0
|
|
367
|
+
) {
|
|
368
|
+
await this.bidi.unsubscribe(
|
|
369
|
+
'network.beforeRequestSent',
|
|
370
|
+
'network.responseStarted',
|
|
371
|
+
'network.responseCompleted',
|
|
372
|
+
'network.authRequired',
|
|
373
|
+
this._browsingContextIds,
|
|
374
|
+
)
|
|
375
|
+
} else {
|
|
376
|
+
await this.bidi.unsubscribe(
|
|
377
|
+
'network.beforeRequestSent',
|
|
378
|
+
'network.responseStarted',
|
|
379
|
+
'network.responseCompleted',
|
|
380
|
+
'network.authRequired',
|
|
381
|
+
)
|
|
382
|
+
}
|
|
322
383
|
}
|
|
323
384
|
}
|
|
324
385
|
|
package/bidi/protocolValue.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
-
const { PrimitiveType, NonPrimitiveType, RemoteType } = require('./protocolType')
|
|
18
|
+
const { PrimitiveType, NonPrimitiveType, RemoteType, SpecialNumberType } = require('./protocolType')
|
|
19
19
|
|
|
20
20
|
const TYPE_CONSTANT = 'type'
|
|
21
21
|
const VALUE_CONSTANT = 'value'
|
|
@@ -185,7 +185,93 @@ class LocalValue {
|
|
|
185
185
|
return new LocalValue(NonPrimitiveType.CHANNEL, value)
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
static createReferenceValue(handle, sharedId) {
|
|
189
|
+
return new ReferenceValue(handle, sharedId)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static getArgument(argument) {
|
|
193
|
+
let localValue = null
|
|
194
|
+
|
|
195
|
+
if (
|
|
196
|
+
argument === SpecialNumberType.NAN ||
|
|
197
|
+
argument === SpecialNumberType.MINUS_ZERO ||
|
|
198
|
+
argument === SpecialNumberType.INFINITY ||
|
|
199
|
+
argument === SpecialNumberType.MINUS_INFINITY
|
|
200
|
+
) {
|
|
201
|
+
localValue = LocalValue.createSpecialNumberValue(argument)
|
|
202
|
+
return localValue
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const type = typeof argument
|
|
206
|
+
|
|
207
|
+
switch (type) {
|
|
208
|
+
case PrimitiveType.STRING:
|
|
209
|
+
localValue = LocalValue.createStringValue(argument)
|
|
210
|
+
break
|
|
211
|
+
case PrimitiveType.NUMBER:
|
|
212
|
+
localValue = LocalValue.createNumberValue(argument)
|
|
213
|
+
break
|
|
214
|
+
case PrimitiveType.BOOLEAN:
|
|
215
|
+
localValue = LocalValue.createBooleanValue(argument)
|
|
216
|
+
break
|
|
217
|
+
case PrimitiveType.BIGINT:
|
|
218
|
+
localValue = LocalValue.createBigIntValue(argument.toString())
|
|
219
|
+
break
|
|
220
|
+
case PrimitiveType.UNDEFINED:
|
|
221
|
+
localValue = LocalValue.createUndefinedValue()
|
|
222
|
+
break
|
|
223
|
+
case NonPrimitiveType.OBJECT:
|
|
224
|
+
if (argument === null) {
|
|
225
|
+
localValue = LocalValue.createNullValue()
|
|
226
|
+
break
|
|
227
|
+
}
|
|
228
|
+
if (argument instanceof Date) {
|
|
229
|
+
localValue = LocalValue.createDateValue(argument)
|
|
230
|
+
} else if (argument instanceof Map) {
|
|
231
|
+
const map = []
|
|
232
|
+
|
|
233
|
+
argument.forEach((value, key) => {
|
|
234
|
+
let objectKey
|
|
235
|
+
if (typeof key === 'string') {
|
|
236
|
+
objectKey = key
|
|
237
|
+
} else {
|
|
238
|
+
objectKey = LocalValue.getArgument(key)
|
|
239
|
+
}
|
|
240
|
+
const objectValue = LocalValue.getArgument(value)
|
|
241
|
+
map.push([objectKey, objectValue])
|
|
242
|
+
})
|
|
243
|
+
localValue = new LocalValue(NonPrimitiveType.MAP, map)
|
|
244
|
+
} else if (argument instanceof Set) {
|
|
245
|
+
const set = []
|
|
246
|
+
argument.forEach((value) => {
|
|
247
|
+
set.push(LocalValue.getArgument(value))
|
|
248
|
+
})
|
|
249
|
+
localValue = LocalValue.createSetValue(set)
|
|
250
|
+
} else if (argument instanceof Array) {
|
|
251
|
+
const arr = []
|
|
252
|
+
argument.forEach((value) => {
|
|
253
|
+
arr.push(LocalValue.getArgument(value))
|
|
254
|
+
})
|
|
255
|
+
localValue = LocalValue.createArrayValue(arr)
|
|
256
|
+
} else if (argument instanceof RegExp) {
|
|
257
|
+
localValue = LocalValue.createRegularExpressionValue({
|
|
258
|
+
pattern: argument.source,
|
|
259
|
+
flags: argument.flags,
|
|
260
|
+
})
|
|
261
|
+
} else {
|
|
262
|
+
let value = []
|
|
263
|
+
Object.entries(argument).forEach((entry) => {
|
|
264
|
+
value.push([LocalValue.getArgument(entry[0]), LocalValue.getArgument(entry[1])])
|
|
265
|
+
})
|
|
266
|
+
localValue = new LocalValue(NonPrimitiveType.OBJECT, value)
|
|
267
|
+
}
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return localValue
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
asMap() {
|
|
189
275
|
let toReturn = {}
|
|
190
276
|
toReturn[TYPE_CONSTANT] = this.type
|
|
191
277
|
|
|
@@ -242,7 +328,7 @@ class RemoteValue {
|
|
|
242
328
|
}
|
|
243
329
|
|
|
244
330
|
deserializeValue(value, type) {
|
|
245
|
-
if (
|
|
331
|
+
if (type === NonPrimitiveType.OBJECT) {
|
|
246
332
|
return Object.fromEntries(value)
|
|
247
333
|
} else if (type === NonPrimitiveType.REGULAR_EXPRESSION) {
|
|
248
334
|
return new RegExpValue(value.pattern, value.flags)
|
package/bidi/scriptManager.js
CHANGED
|
@@ -27,14 +27,58 @@ const { RemoteValue } = require('./protocolValue')
|
|
|
27
27
|
const { Source } = require('./scriptTypes')
|
|
28
28
|
const { WebDriverError } = require('../lib/error')
|
|
29
29
|
|
|
30
|
+
const ScriptEvent = {
|
|
31
|
+
MESSAGE: 'script.message',
|
|
32
|
+
REALM_CREATED: 'script.realmCreated',
|
|
33
|
+
REALM_DESTROYED: 'script.realmDestroyed',
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
/**
|
|
31
37
|
* Represents class to run events and commands of Script module.
|
|
32
38
|
* Described in https://w3c.github.io/webdriver-bidi/#module-script.
|
|
33
39
|
* @class
|
|
34
40
|
*/
|
|
35
41
|
class ScriptManager {
|
|
42
|
+
#callbackId = 0
|
|
43
|
+
#listener
|
|
44
|
+
|
|
36
45
|
constructor(driver) {
|
|
37
46
|
this._driver = driver
|
|
47
|
+
this.#listener = new Map()
|
|
48
|
+
this.#listener.set(ScriptEvent.MESSAGE, new Map())
|
|
49
|
+
this.#listener.set(ScriptEvent.REALM_CREATED, new Map())
|
|
50
|
+
this.#listener.set(ScriptEvent.REALM_DESTROYED, new Map())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
addCallback(eventType, callback) {
|
|
54
|
+
const id = ++this.#callbackId
|
|
55
|
+
|
|
56
|
+
const eventCallbackMap = this.#listener.get(eventType)
|
|
57
|
+
eventCallbackMap.set(id, callback)
|
|
58
|
+
return id
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
removeCallback(id) {
|
|
62
|
+
let hasId = false
|
|
63
|
+
for (const [, callbacks] of this.#listener) {
|
|
64
|
+
if (callbacks.has(id)) {
|
|
65
|
+
callbacks.delete(id)
|
|
66
|
+
hasId = true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!hasId) {
|
|
71
|
+
throw Error(`Callback with id ${id} not found`)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
invokeCallbacks(eventType, data) {
|
|
76
|
+
const callbacks = this.#listener.get(eventType)
|
|
77
|
+
if (callbacks) {
|
|
78
|
+
for (const [, callback] of callbacks) {
|
|
79
|
+
callback(data)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
38
82
|
}
|
|
39
83
|
|
|
40
84
|
async init(browsingContextIds) {
|
|
@@ -251,6 +295,14 @@ class ScriptManager {
|
|
|
251
295
|
params.contexts = new Array(this._browsingContextIds)
|
|
252
296
|
}
|
|
253
297
|
|
|
298
|
+
if (argumentValueList != null) {
|
|
299
|
+
let argumentParams = []
|
|
300
|
+
argumentValueList.forEach((argumentValue) => {
|
|
301
|
+
argumentParams.push(argumentValue.asMap())
|
|
302
|
+
})
|
|
303
|
+
params['arguments'] = argumentParams
|
|
304
|
+
}
|
|
305
|
+
|
|
254
306
|
const command = {
|
|
255
307
|
method: 'script.addPreloadScript',
|
|
256
308
|
params,
|
|
@@ -433,7 +485,7 @@ class ScriptManager {
|
|
|
433
485
|
* @returns {Promise<void>} - A promise that resolves when the subscription is successful.
|
|
434
486
|
*/
|
|
435
487
|
async onMessage(callback) {
|
|
436
|
-
await this.subscribeAndHandleEvent(
|
|
488
|
+
return await this.subscribeAndHandleEvent(ScriptEvent.MESSAGE, callback)
|
|
437
489
|
}
|
|
438
490
|
|
|
439
491
|
/**
|
|
@@ -443,7 +495,7 @@ class ScriptManager {
|
|
|
443
495
|
* @returns {Promise<void>} - A promise that resolves when the subscription is successful.
|
|
444
496
|
*/
|
|
445
497
|
async onRealmCreated(callback) {
|
|
446
|
-
await this.subscribeAndHandleEvent(
|
|
498
|
+
return await this.subscribeAndHandleEvent(ScriptEvent.REALM_CREATED, callback)
|
|
447
499
|
}
|
|
448
500
|
|
|
449
501
|
/**
|
|
@@ -453,19 +505,18 @@ class ScriptManager {
|
|
|
453
505
|
* @returns {Promise<void>} - A promise that resolves when the subscription is successful.
|
|
454
506
|
*/
|
|
455
507
|
async onRealmDestroyed(callback) {
|
|
456
|
-
await this.subscribeAndHandleEvent(
|
|
508
|
+
return await this.subscribeAndHandleEvent(ScriptEvent.REALM_DESTROYED, callback)
|
|
457
509
|
}
|
|
458
510
|
|
|
459
511
|
async subscribeAndHandleEvent(eventType, callback) {
|
|
460
|
-
if (this.
|
|
461
|
-
await this.bidi.subscribe(eventType, this.
|
|
512
|
+
if (this._browsingContextIds != null) {
|
|
513
|
+
await this.bidi.subscribe(eventType, this._browsingContextIds)
|
|
462
514
|
} else {
|
|
463
515
|
await this.bidi.subscribe(eventType)
|
|
464
516
|
}
|
|
465
|
-
await this._on(callback)
|
|
466
|
-
}
|
|
467
517
|
|
|
468
|
-
|
|
518
|
+
let id = this.addCallback(eventType, callback)
|
|
519
|
+
|
|
469
520
|
this.ws = await this.bidi.socket
|
|
470
521
|
this.ws.on('message', (event) => {
|
|
471
522
|
const { params } = JSON.parse(Buffer.from(event.toString()))
|
|
@@ -482,9 +533,28 @@ class ScriptManager {
|
|
|
482
533
|
response = params.realm
|
|
483
534
|
}
|
|
484
535
|
}
|
|
485
|
-
|
|
536
|
+
this.invokeCallbacks(eventType, response)
|
|
486
537
|
}
|
|
487
538
|
})
|
|
539
|
+
|
|
540
|
+
return id
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
async close() {
|
|
544
|
+
if (
|
|
545
|
+
this._browsingContextIds !== null &&
|
|
546
|
+
this._browsingContextIds !== undefined &&
|
|
547
|
+
this._browsingContextIds.length > 0
|
|
548
|
+
) {
|
|
549
|
+
await this.bidi.unsubscribe(
|
|
550
|
+
'script.message',
|
|
551
|
+
'script.realmCreated',
|
|
552
|
+
'script.realmDestroyed',
|
|
553
|
+
this._browsingContextIds,
|
|
554
|
+
)
|
|
555
|
+
} else {
|
|
556
|
+
await this.bidi.unsubscribe('script.message', 'script.realmCreated', 'script.realmDestroyed')
|
|
557
|
+
}
|
|
488
558
|
}
|
|
489
559
|
}
|
|
490
560
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.js
CHANGED
|
@@ -44,6 +44,7 @@ const BrowsingContext = require('./bidi/browsingContext')
|
|
|
44
44
|
const BrowsingContextInspector = require('./bidi/browsingContextInspector')
|
|
45
45
|
const ScriptManager = require('./bidi/scriptManager')
|
|
46
46
|
const NetworkInspector = require('./bidi/networkInspector')
|
|
47
|
+
const version = require('./package.json').version
|
|
47
48
|
|
|
48
49
|
const Browser = capabilities.Browser
|
|
49
50
|
const Capabilities = capabilities.Capabilities
|
|
@@ -794,3 +795,4 @@ exports.BrowsingContext = BrowsingContext
|
|
|
794
795
|
exports.BrowsingContextInspector = BrowsingContextInspector
|
|
795
796
|
exports.ScriptManager = ScriptManager
|
|
796
797
|
exports.NetworkInspector = NetworkInspector
|
|
798
|
+
exports.version = version
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
function observeMutations(channel) {
|
|
19
|
+
const observer = new MutationObserver((mutations) => {
|
|
20
|
+
for (const mutation of mutations) {
|
|
21
|
+
switch (mutation.type) {
|
|
22
|
+
case 'attributes':
|
|
23
|
+
// Don't report our own attribute has changed.
|
|
24
|
+
if (mutation.attributeName === 'data-__webdriver_id') {
|
|
25
|
+
break
|
|
26
|
+
}
|
|
27
|
+
const curr = mutation.target.getAttribute(mutation.attributeName)
|
|
28
|
+
let id = mutation.target.dataset.__webdriver_id
|
|
29
|
+
if (!id) {
|
|
30
|
+
id = Math.random().toString(36).substring(2) + Date.now().toString(36)
|
|
31
|
+
mutation.target.dataset.__webdriver_id = id
|
|
32
|
+
}
|
|
33
|
+
const json = JSON.stringify({
|
|
34
|
+
target: id,
|
|
35
|
+
name: mutation.attributeName,
|
|
36
|
+
value: curr,
|
|
37
|
+
oldValue: mutation.oldValue,
|
|
38
|
+
})
|
|
39
|
+
channel(json)
|
|
40
|
+
break
|
|
41
|
+
default:
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
observer.observe(document, {
|
|
48
|
+
attributes: true,
|
|
49
|
+
attributeOldValue: true,
|
|
50
|
+
characterData: true,
|
|
51
|
+
characterDataOldValue: true,
|
|
52
|
+
childList: true,
|
|
53
|
+
subtree: true,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
@@ -87,7 +87,7 @@ ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#0
|
|
|
87
87
|
lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",
|
|
88
88
|
moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",
|
|
89
89
|
seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};var Pc="backgroundColor borderTopColor borderRightColor borderBottomColor borderLeftColor color outlineColor".split(" "),Qc=/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/,Rc=/^#(?:[0-9a-f]{3}){1,2}$/i,Sc=/^(?:rgba)?\((\d{1,3}),\s?(\d{1,3}),\s?(\d{1,3}),\s?(0|1|0\.\d*)\)$/i,Tc=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;function Uc(a,b){b=b.toLowerCase();return"style"==b?Vc(a.style.cssText):Lc&&"value"==b&&S(a,"INPUT")?a.value:Mc&&!0===a[b]?String(a.getAttribute(b)):(a=a.getAttributeNode(b))&&a.specified?a.value:null}var Wc=/[;]+(?=(?:(?:[^"]*"){2})*[^"]*$)(?=(?:(?:[^']*'){2})*[^']*$)(?=(?:[^()]*\([^()]*\))*[^()]*$)/;
|
|
90
|
-
function Vc(a){var b=[];l(a.split(Wc),function(c){var d=c.indexOf(":");0<d&&(c=[c.slice(0,d),c.slice(d+1)],2==c.length&&b.push(c[0].toLowerCase(),":",c[1],";"))});b=b.join("");return b=";"==b.charAt(b.length-1)?b:b+";"}function S(a,b){b&&"string"!==typeof b&&(b=b.toString());return
|
|
90
|
+
function Vc(a){var b=[];l(a.split(Wc),function(c){var d=c.indexOf(":");0<d&&(c=[c.slice(0,d),c.slice(d+1)],2==c.length&&b.push(c[0].toLowerCase(),":",c[1],";"))});b=b.join("");return b=";"==b.charAt(b.length-1)?b:b+";"}function S(a,b){b&&"string"!==typeof b&&(b=b.toString());return a instanceof HTMLFormElement?!!a&&1==a.nodeType&&(!b||"FORM"==b):!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)};function Xc(a,b,c,d){this.c=a;this.a=b;this.b=c;this.f=d}Xc.prototype.ceil=function(){this.c=Math.ceil(this.c);this.a=Math.ceil(this.a);this.b=Math.ceil(this.b);this.f=Math.ceil(this.f);return this};Xc.prototype.floor=function(){this.c=Math.floor(this.c);this.a=Math.floor(this.a);this.b=Math.floor(this.b);this.f=Math.floor(this.f);return this};Xc.prototype.round=function(){this.c=Math.round(this.c);this.a=Math.round(this.a);this.b=Math.round(this.b);this.f=Math.round(this.f);return this};function T(a,b,c,d){this.a=a;this.b=b;this.width=c;this.height=d}T.prototype.ceil=function(){this.a=Math.ceil(this.a);this.b=Math.ceil(this.b);this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};T.prototype.floor=function(){this.a=Math.floor(this.a);this.b=Math.floor(this.b);this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};
|
|
91
91
|
T.prototype.round=function(){this.a=Math.round(this.a);this.b=Math.round(this.b);this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var Yc="function"===typeof ShadowRoot;function Zc(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return S(a)?a:null}
|
|
92
92
|
function U(a,b){b=Ha(b);if("float"==b||"cssFloat"==b||"styleFloat"==b)b=Mc?"styleFloat":"cssFloat";a:{var c=b;var d=A(a);if(d.defaultView&&d.defaultView.getComputedStyle&&(d=d.defaultView.getComputedStyle(a,null))){c=d[c]||d.getPropertyValue(c)||"";break a}c=""}a=c||$c(a,b);if(null===a)a=null;else if(0<=oa(Pc,b)){b:{var e=a.match(Sc);if(e&&(b=Number(e[1]),c=Number(e[2]),d=Number(e[3]),e=Number(e[4]),0<=b&&255>=b&&0<=c&&255>=c&&0<=d&&255>=d&&0<=e&&1>=e)){b=[b,c,d,e];break b}b=null}if(!b)b:{if(d=a.match(Tc))if(b=
|
|
93
93
|
Number(d[1]),c=Number(d[2]),d=Number(d[3]),0<=b&&255>=b&&0<=c&&255>=c&&0<=d&&255>=d){b=[b,c,d,1];break b}b=null}if(!b)b:{b=a.toLowerCase();c=Oc[b.toLowerCase()];if(!c&&(c="#"==b.charAt(0)?b:"#"+b,4==c.length&&(c=c.replace(Qc,"#$1$1$2$2$3$3")),!Rc.test(c))){b=null;break b}b=[parseInt(c.substr(1,2),16),parseInt(c.substr(3,2),16),parseInt(c.substr(5,2),16),1]}a=b?"rgba("+b.join(", ")+")":a}return a}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
module.exports = function(){return (function(){var d=this||self;function f(a,b){function c(){}c.prototype=b.prototype;a.prototype=new c;a.prototype.constructor=a};var h=Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b,void 0)}:function(a,b){if("string"===typeof a)return"string"!==typeof b||1!=b.length?-1:a.indexOf(b,0);for(var c=0;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},k=Array.prototype.forEach?function(a,b){Array.prototype.forEach.call(a,b,void 0)}:function(a,b){for(var c=a.length,e="string"===typeof a?a.split(""):a,g=0;g<c;g++)g in e&&b.call(void 0,e[g],g,a)};function l(a,b){this.code=a;this.a=m[a]||n;this.message=b||"";a=this.a.replace(/((?:^|\s+)[a-z])/g,function(c){return c.toUpperCase().replace(/^[\s\xa0]+/g,"")});b=a.length-5;if(0>b||a.indexOf("Error",b)!=b)a+="Error";this.name=a;a=Error(this.message);a.name=this.name;this.stack=a.stack||""}f(l,Error);var n="unknown error",m={15:"element not selectable",11:"element not visible"};m[31]=n;m[30]=n;m[24]="invalid cookie domain";m[29]="invalid element coordinates";m[12]="invalid element state";m[32]="invalid selector";
|
|
3
3
|
m[51]="invalid selector";m[52]="invalid selector";m[17]="javascript error";m[405]="unsupported operation";m[34]="move target out of bounds";m[27]="no such alert";m[7]="no such element";m[8]="no such frame";m[23]="no such window";m[28]="script timeout";m[33]="session not created";m[10]="stale element reference";m[21]="timeout";m[25]="unable to set cookie";m[26]="unexpected alert open";m[13]=n;m[9]="unknown command";var p;a:{var q=d.navigator;if(q){var r=q.userAgent;if(r){p=r;break a}}p=""}function t(a){return-1!=p.indexOf(a)};function u(){return t("Firefox")||t("FxiOS")}function v(){return(t("Chrome")||t("CriOS"))&&!t("Edge")};function w(){return t("iPhone")&&!t("iPod")&&!t("iPad")};var y=t("Opera"),z=t("Trident")||t("MSIE"),A=t("Edge"),B=t("Gecko")&&!(-1!=p.toLowerCase().indexOf("webkit")&&!t("Edge"))&&!(t("Trident")||t("MSIE"))&&!t("Edge"),C=-1!=p.toLowerCase().indexOf("webkit")&&!t("Edge");function D(){var a=d.document;return a?a.documentMode:void 0}var E;
|
|
4
4
|
a:{var F="",G=function(){var a=p;if(B)return/rv:([^\);]+)(\)|;)/.exec(a);if(A)return/Edge\/([\d\.]+)/.exec(a);if(z)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(C)return/WebKit\/(\S+)/.exec(a);if(y)return/(?:Version)[ \/]?(\S+)/.exec(a)}();G&&(F=G?G[1]:"");if(z){var H=D();if(null!=H&&H>parseFloat(F)){E=String(H);break a}}E=F}var I;I=d.document&&z?D():void 0;var J=u(),K=w()||t("iPod"),L=t("iPad"),M=t("Android")&&!(v()||u()||t("Opera")||t("Silk")),N=v(),aa=t("Safari")&&!(v()||t("Coast")||t("Opera")||t("Edge")||t("Edg/")||t("OPR")||u()||t("Silk")||t("Android"))&&!(w()||t("iPad")||t("iPod"));function O(a){return(a=a.exec(p))?a[1]:""}(function(){if(J)return O(/Firefox\/([0-9.]+)/);if(z||A||y)return E;if(N)return w()||t("iPad")||t("iPod")?O(/CriOS\/([0-9.]+)/):O(/Chrome\/([0-9.]+)/);if(aa&&!(w()||t("iPad")||t("iPod")))return O(/Version\/([0-9.]+)/);if(K||L){var a=/Version\/(\S+).*Mobile\/(\S+)/.exec(p);if(a)return a[1]+"."+a[2]}else if(M)return(a=O(/Android\s+([0-9.]+)/))?a:O(/Version\/([0-9.]+)/);return""})();var P=z&&!(8<=Number(I)),ba=z&&!(9<=Number(I));var ca={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},Q={IMG:" ",BR:"\n"};function R(a,b,c){if(!(a.nodeName in ca))if(3==a.nodeType)c?b.push(String(a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):b.push(a.nodeValue);else if(a.nodeName in Q)b.push(Q[a.nodeName]);else for(a=a.firstChild;a;)R(a,b,c),a=a.nextSibling};function S(a,b){b=b.toLowerCase();return"style"==b?da(a.style.cssText):P&&"value"==b&&T(a,"INPUT")?a.value:ba&&!0===a[b]?String(a.getAttribute(b)):(a=a.getAttributeNode(b))&&a.specified?a.value:null}var ea=/[;]+(?=(?:(?:[^"]*"){2})*[^"]*$)(?=(?:(?:[^']*'){2})*[^']*$)(?=(?:[^()]*\([^()]*\))*[^()]*$)/;
|
|
5
|
-
function da(a){var b=[];k(a.split(ea),function(c){var e=c.indexOf(":");0<e&&(c=[c.slice(0,e),c.slice(e+1)],2==c.length&&b.push(c[0].toLowerCase(),":",c[1],";"))});b=b.join("");return b=";"==b.charAt(b.length-1)?b:b+";"}function U(a,b){P&&"value"==b&&T(a,"OPTION")&&null===S(a,"value")?(b=[],R(a,b,!1),a=b.join("")):a=a[b];return a}
|
|
6
|
-
function V(a){return T(a,"OPTION")?!0:T(a,"INPUT")?(a=a.type.toLowerCase(),"checkbox"==a||"radio"==a):!1};var fa={"class":"className",readonly:"readOnly"},ha="allowfullscreen allowpaymentrequest allowusermedia async autofocus autoplay checked compact complete controls declare default defaultchecked defaultselected defer disabled ended formnovalidate hidden indeterminate iscontenteditable ismap itemscope loop multiple muted nohref nomodule noresize noshade novalidate nowrap open paused playsinline pubdate readonly required reversed scoped seamless seeking selected truespeed typemustmatch willvalidate".split(" ");function W(a,b){var c=null,e=b.toLowerCase();if("style"==e)return(c=a.style)&&"string"!=typeof c&&(c=c.cssText),c;if(("selected"==e||"checked"==e)&&V(a)){if(!V(a))throw new l(15,"Element is not selectable");b="selected";c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";return U(a,b)?"true":null}var g=T(a,"A");if(T(a,"IMG")&&"src"==e||g&&"href"==e)return(c=S(a,e))&&(c=U(a,e)),c;if("spellcheck"==e){c=S(a,e);if(null!==c){if("false"==c.toLowerCase())return"false";if("true"==c.toLowerCase())return"true"}return U(a,
|
|
5
|
+
function da(a){var b=[];k(a.split(ea),function(c){var e=c.indexOf(":");0<e&&(c=[c.slice(0,e),c.slice(e+1)],2==c.length&&b.push(c[0].toLowerCase(),":",c[1],";"))});b=b.join("");return b=";"==b.charAt(b.length-1)?b:b+";"}function U(a,b){P&&"value"==b&&T(a,"OPTION")&&null===S(a,"value")?(b=[],R(a,b,!1),a=b.join("")):a=a[b];return a}
|
|
6
|
+
function T(a,b){b&&"string"!==typeof b&&(b=b.toString());return a instanceof HTMLFormElement?!!a&&1==a.nodeType&&(!b||"FORM"==b):!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}function V(a){return T(a,"OPTION")?!0:T(a,"INPUT")?(a=a.type.toLowerCase(),"checkbox"==a||"radio"==a):!1};var fa={"class":"className",readonly:"readOnly"},ha="allowfullscreen allowpaymentrequest allowusermedia async autofocus autoplay checked compact complete controls declare default defaultchecked defaultselected defer disabled ended formnovalidate hidden indeterminate iscontenteditable ismap itemscope loop multiple muted nohref nomodule noresize noshade novalidate nowrap open paused playsinline pubdate readonly required reversed scoped seamless seeking selected truespeed typemustmatch willvalidate".split(" ");function W(a,b){var c=null,e=b.toLowerCase();if("style"==e)return(c=a.style)&&"string"!=typeof c&&(c=c.cssText),c;if(("selected"==e||"checked"==e)&&V(a)){if(!V(a))throw new l(15,"Element is not selectable");b="selected";c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";return U(a,b)?"true":null}var g=T(a,"A");if(T(a,"IMG")&&"src"==e||g&&"href"==e)return(c=S(a,e))&&(c=U(a,e)),c;if("spellcheck"==e){c=S(a,e);if(null!==c){if("false"==c.toLowerCase())return"false";if("true"==c.toLowerCase())return"true"}return U(a,
|
|
7
7
|
e)+""}g=fa[b]||b;if(0<=h(ha,e))return(c=null!==S(a,b)||U(a,g))?"true":null;try{var x=U(a,g)}catch(ia){}(e=null==x)||(e=typeof x,e="object"==e&&null!=x||"function"==e);e?c=S(a,b):c=x;return null!=c?c.toString():null}var X=["_"],Y=d;X[0]in Y||"undefined"==typeof Y.execScript||Y.execScript("var "+X[0]);for(var Z;X.length&&(Z=X.shift());)X.length||void 0===W?Y[Z]&&Y[Z]!==Object.prototype[Z]?Y=Y[Z]:Y=Y[Z]={}:Y[Z]=W;; return this._.apply(null,arguments);}).apply({navigator:typeof window!='undefined'?window.navigator:null,document:typeof window!='undefined'?window.document:null}, arguments);};
|
|
@@ -10,7 +10,7 @@ moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:
|
|
|
10
10
|
seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};var ia="backgroundColor borderTopColor borderRightColor borderBottomColor borderLeftColor color outlineColor".split(" "),ja=/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/,ka=/^#(?:[0-9a-f]{3}){1,2}$/i,la=/^(?:rgba)?\((\d{1,3}),\s?(\d{1,3}),\s?(\d{1,3}),\s?(0|1|0\.\d*)\)$/i,ma=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;function m(a,b){this.code=a;this.a=p[a]||r;this.message=b||"";a=this.a.replace(/((?:^|\s+)[a-z])/g,function(c){return c.toUpperCase().replace(/^[\s\xa0]+/g,"")});b=a.length-5;if(0>b||a.indexOf("Error",b)!=b)a+="Error";this.name=a;a=Error(this.message);a.name=this.name;this.stack=a.stack||""}ca(m,Error);var r="unknown error",p={15:"element not selectable",11:"element not visible"};p[31]=r;p[30]=r;p[24]="invalid cookie domain";p[29]="invalid element coordinates";p[12]="invalid element state";
|
|
11
11
|
p[32]="invalid selector";p[51]="invalid selector";p[52]="invalid selector";p[17]="javascript error";p[405]="unsupported operation";p[34]="move target out of bounds";p[27]="no such alert";p[7]="no such element";p[8]="no such frame";p[23]="no such window";p[28]="script timeout";p[33]="session not created";p[10]="stale element reference";p[21]="timeout";p[25]="unable to set cookie";p[26]="unexpected alert open";p[13]=r;p[9]="unknown command";var u=String.prototype.trim?function(a){return a.trim()}:function(a){return/^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(a)[1]};
|
|
12
12
|
function na(a,b){var c=0;a=u(String(a)).split(".");b=u(String(b)).split(".");for(var e=Math.max(a.length,b.length),d=0;0==c&&d<e;d++){var f=a[d]||"",h=b[d]||"";do{f=/(\d*)(\D*)(.*)/.exec(f)||["","","",""];h=/(\d*)(\D*)(.*)/.exec(h)||["","","",""];if(0==f[0].length&&0==h[0].length)break;c=v(0==f[1].length?0:parseInt(f[1],10),0==h[1].length?0:parseInt(h[1],10))||v(0==f[2].length,0==h[2].length)||v(f[2],h[2]);f=f[3];h=h[3]}while(0==c)}return c}function v(a,b){return a<b?-1:a>b?1:0};var w;a:{var oa=g.navigator;if(oa){var sa=oa.userAgent;if(sa){w=sa;break a}}w=""}function x(a){return-1!=w.indexOf(a)};function y(){return x("Firefox")||x("FxiOS")}function A(){return(x("Chrome")||x("CriOS"))&&!x("Edge")};function ta(a){return String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()})};function B(){return x("iPhone")&&!x("iPod")&&!x("iPad")};function ua(a,b){var c=va;return Object.prototype.hasOwnProperty.call(c,a)?c[a]:c[a]=b(a)};var wa=x("Opera"),C=x("Trident")||x("MSIE"),xa=x("Edge"),ya=x("Gecko")&&!(-1!=w.toLowerCase().indexOf("webkit")&&!x("Edge"))&&!(x("Trident")||x("MSIE"))&&!x("Edge"),za=-1!=w.toLowerCase().indexOf("webkit")&&!x("Edge");function Aa(){var a=g.document;return a?a.documentMode:void 0}var E;
|
|
13
|
-
a:{var F="",G=function(){var a=w;if(ya)return/rv:([^\);]+)(\)|;)/.exec(a);if(xa)return/Edge\/([\d\.]+)/.exec(a);if(C)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(za)return/WebKit\/(\S+)/.exec(a);if(wa)return/(?:Version)[ \/]?(\S+)/.exec(a)}();G&&(F=G?G[1]:"");if(C){var H=Aa();if(null!=H&&H>parseFloat(F)){E=String(H);break a}}E=F}var va={};function Ba(a){return ua(a,function(){return 0<=na(E,a)})}var I;I=g.document&&C?Aa():void 0;var Ca=y(),Da=B()||x("iPod"),Ea=x("iPad"),Fa=x("Android")&&!(A()||y()||x("Opera")||x("Silk")),Ga=A(),Ha=x("Safari")&&!(A()||x("Coast")||x("Opera")||x("Edge")||x("Edg/")||x("OPR")||y()||x("Silk")||x("Android"))&&!(B()||x("iPad")||x("iPod"));function J(a){return(a=a.exec(w))?a[1]:""}(function(){if(Ca)return J(/Firefox\/([0-9.]+)/);if(C||xa||wa)return E;if(Ga)return B()||x("iPad")||x("iPod")?J(/CriOS\/([0-9.]+)/):J(/Chrome\/([0-9.]+)/);if(Ha&&!(B()||x("iPad")||x("iPod")))return J(/Version\/([0-9.]+)/);if(Da||Ea){var a=/Version\/(\S+).*Mobile\/(\S+)/.exec(w);if(a)return a[1]+"."+a[2]}else if(Fa)return(a=J(/Android\s+([0-9.]+)/))?a:J(/Version\/([0-9.]+)/);return""})();var K;if(K=C)K=!(9<=Number(I));var Ia=K;function L(a,b){this.x=void 0!==a?a:0;this.y=void 0!==b?b:0}L.prototype.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};L.prototype.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};L.prototype.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};function M(a,b){this.width=a;this.height=b}M.prototype.aspectRatio=function(){return this.width/this.height};M.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};M.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};M.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};function N(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function Ja(a,b){a&&(a=a.parentNode);for(var c=0;a;){if(b(a))return a;a=a.parentNode;c++}return null}function Ka(a){this.a=a||g.document||document};function P(a,b){b&&"string"!==typeof b&&(b=b.toString());return
|
|
13
|
+
a:{var F="",G=function(){var a=w;if(ya)return/rv:([^\);]+)(\)|;)/.exec(a);if(xa)return/Edge\/([\d\.]+)/.exec(a);if(C)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(za)return/WebKit\/(\S+)/.exec(a);if(wa)return/(?:Version)[ \/]?(\S+)/.exec(a)}();G&&(F=G?G[1]:"");if(C){var H=Aa();if(null!=H&&H>parseFloat(F)){E=String(H);break a}}E=F}var va={};function Ba(a){return ua(a,function(){return 0<=na(E,a)})}var I;I=g.document&&C?Aa():void 0;var Ca=y(),Da=B()||x("iPod"),Ea=x("iPad"),Fa=x("Android")&&!(A()||y()||x("Opera")||x("Silk")),Ga=A(),Ha=x("Safari")&&!(A()||x("Coast")||x("Opera")||x("Edge")||x("Edg/")||x("OPR")||y()||x("Silk")||x("Android"))&&!(B()||x("iPad")||x("iPod"));function J(a){return(a=a.exec(w))?a[1]:""}(function(){if(Ca)return J(/Firefox\/([0-9.]+)/);if(C||xa||wa)return E;if(Ga)return B()||x("iPad")||x("iPod")?J(/CriOS\/([0-9.]+)/):J(/Chrome\/([0-9.]+)/);if(Ha&&!(B()||x("iPad")||x("iPod")))return J(/Version\/([0-9.]+)/);if(Da||Ea){var a=/Version\/(\S+).*Mobile\/(\S+)/.exec(w);if(a)return a[1]+"."+a[2]}else if(Fa)return(a=J(/Android\s+([0-9.]+)/))?a:J(/Version\/([0-9.]+)/);return""})();var K;if(K=C)K=!(9<=Number(I));var Ia=K;function L(a,b){this.x=void 0!==a?a:0;this.y=void 0!==b?b:0}L.prototype.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};L.prototype.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};L.prototype.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};function M(a,b){this.width=a;this.height=b}M.prototype.aspectRatio=function(){return this.width/this.height};M.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};M.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};M.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};function N(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function Ja(a,b){a&&(a=a.parentNode);for(var c=0;a;){if(b(a))return a;a=a.parentNode;c++}return null}function Ka(a){this.a=a||g.document||document};function P(a,b){b&&"string"!==typeof b&&(b=b.toString());return a instanceof HTMLFormElement?!!a&&1==a.nodeType&&(!b||"FORM"==b):!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)};function Q(a,b,c,e){this.f=a;this.a=b;this.b=c;this.c=e}Q.prototype.ceil=function(){this.f=Math.ceil(this.f);this.a=Math.ceil(this.a);this.b=Math.ceil(this.b);this.c=Math.ceil(this.c);return this};Q.prototype.floor=function(){this.f=Math.floor(this.f);this.a=Math.floor(this.a);this.b=Math.floor(this.b);this.c=Math.floor(this.c);return this};Q.prototype.round=function(){this.f=Math.round(this.f);this.a=Math.round(this.a);this.b=Math.round(this.b);this.c=Math.round(this.c);return this};function R(a,b,c,e){this.a=a;this.b=b;this.width=c;this.height=e}R.prototype.ceil=function(){this.a=Math.ceil(this.a);this.b=Math.ceil(this.b);this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};R.prototype.floor=function(){this.a=Math.floor(this.a);this.b=Math.floor(this.b);this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};
|
|
14
14
|
R.prototype.round=function(){this.a=Math.round(this.a);this.b=Math.round(this.b);this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var La="function"===typeof ShadowRoot;function S(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return P(a)?a:null}
|
|
15
15
|
function T(a,b){b=ta(b);if("float"==b||"cssFloat"==b||"styleFloat"==b)b=Ia?"styleFloat":"cssFloat";a:{var c=b;var e=N(a);if(e.defaultView&&e.defaultView.getComputedStyle&&(e=e.defaultView.getComputedStyle(a,null))){c=e[c]||e.getPropertyValue(c)||"";break a}c=""}a=c||Ma(a,b);if(null===a)a=null;else if(0<=da(ia,b)){b:{var d=a.match(la);if(d&&(b=Number(d[1]),c=Number(d[2]),e=Number(d[3]),d=Number(d[4]),0<=b&&255>=b&&0<=c&&255>=c&&0<=e&&255>=e&&0<=d&&1>=d)){b=[b,c,e,d];break b}b=null}if(!b)b:{if(e=a.match(ma))if(b=
|
|
16
16
|
Number(e[1]),c=Number(e[2]),e=Number(e[3]),0<=b&&255>=b&&0<=c&&255>=c&&0<=e&&255>=e){b=[b,c,e,1];break b}b=null}if(!b)b:{b=a.toLowerCase();c=ha[b.toLowerCase()];if(!c&&(c="#"==b.charAt(0)?b:"#"+b,4==c.length&&(c=c.replace(ja,"#$1$1$2$2$3$3")),!ka.test(c))){b=null;break b}b=[parseInt(c.substr(1,2),16),parseInt(c.substr(3,2),16),parseInt(c.substr(5,2),16),1]}a=b?"rgba("+b.join(", ")+")":a}return a}
|
package/lib/network.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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 network = require('../bidi/network')
|
|
19
|
+
const { InterceptPhase } = require('../bidi/interceptPhase')
|
|
20
|
+
const { AddInterceptParameters } = require('../bidi/addInterceptParameters')
|
|
21
|
+
|
|
22
|
+
class Network {
|
|
23
|
+
#driver
|
|
24
|
+
#network
|
|
25
|
+
#callBackInterceptIdMap = new Map()
|
|
26
|
+
|
|
27
|
+
constructor(driver) {
|
|
28
|
+
this.#driver = driver
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// This should be done in the constructor.
|
|
32
|
+
// But since it needs to call async methods we cannot do that in the constructor.
|
|
33
|
+
// We can have a separate async method that initialises the Script instance.
|
|
34
|
+
// However, that pattern does not allow chaining the methods as we would like the user to use it.
|
|
35
|
+
// Since it involves awaiting to get the instance and then another await to call the method.
|
|
36
|
+
// Using this allows the user to do this "await driver.network.addAuthenticationHandler(callback)"
|
|
37
|
+
async #init() {
|
|
38
|
+
if (this.#network !== undefined) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
this.#network = await network(this.#driver)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async addAuthenticationHandler(username, password) {
|
|
45
|
+
await this.#init()
|
|
46
|
+
|
|
47
|
+
const interceptId = await this.#network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))
|
|
48
|
+
|
|
49
|
+
const id = await this.#network.authRequired(async (event) => {
|
|
50
|
+
await this.#network.continueWithAuth(event.request.request, username, password)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
this.#callBackInterceptIdMap.set(id, interceptId)
|
|
54
|
+
return id
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async removeAuthenticationHandler(id) {
|
|
58
|
+
await this.#init()
|
|
59
|
+
|
|
60
|
+
const interceptId = this.#callBackInterceptIdMap.get(id)
|
|
61
|
+
|
|
62
|
+
await this.#network.removeIntercept(interceptId)
|
|
63
|
+
await this.#network.removeCallback(id)
|
|
64
|
+
|
|
65
|
+
this.#callBackInterceptIdMap.delete(id)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async clearAuthenticationHandlers() {
|
|
69
|
+
for (const [key, value] of this.#callBackInterceptIdMap.entries()) {
|
|
70
|
+
await this.#network.removeIntercept(value)
|
|
71
|
+
await this.#network.removeCallback(key)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.#callBackInterceptIdMap.clear()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = Network
|
package/lib/pinnedScript.js
CHANGED
package/lib/script.js
CHANGED
|
@@ -16,10 +16,16 @@
|
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
18
|
const logInspector = require('../bidi/logInspector')
|
|
19
|
+
const scriptManager = require('../bidi//scriptManager')
|
|
20
|
+
const { LocalValue, ChannelValue } = require('../bidi/protocolValue')
|
|
21
|
+
const fs = require('node:fs')
|
|
22
|
+
const path = require('node:path')
|
|
23
|
+
const by = require('./by')
|
|
19
24
|
|
|
20
25
|
class Script {
|
|
21
26
|
#driver
|
|
22
27
|
#logInspector
|
|
28
|
+
#script
|
|
23
29
|
|
|
24
30
|
constructor(driver) {
|
|
25
31
|
this.#driver = driver
|
|
@@ -38,6 +44,13 @@ class Script {
|
|
|
38
44
|
this.#logInspector = await logInspector(this.#driver)
|
|
39
45
|
}
|
|
40
46
|
|
|
47
|
+
async #initScript() {
|
|
48
|
+
if (this.#script !== undefined) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
this.#script = await scriptManager([], this.#driver)
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
async addJavaScriptErrorHandler(callback) {
|
|
42
55
|
await this.#init()
|
|
43
56
|
return await this.#logInspector.onJavascriptException(callback)
|
|
@@ -58,6 +71,72 @@ class Script {
|
|
|
58
71
|
|
|
59
72
|
await this.#logInspector.removeCallback(id)
|
|
60
73
|
}
|
|
74
|
+
|
|
75
|
+
async addDomMutationHandler(callback) {
|
|
76
|
+
await this.#initScript()
|
|
77
|
+
|
|
78
|
+
let argumentValues = []
|
|
79
|
+
let value = LocalValue.createChannelValue(new ChannelValue('channel_name'))
|
|
80
|
+
argumentValues.push(value)
|
|
81
|
+
|
|
82
|
+
const filePath = path.join(__dirname, 'atoms', 'bidi-mutation-listener.js')
|
|
83
|
+
|
|
84
|
+
let mutationListener = fs.readFileSync(filePath, 'utf-8').toString()
|
|
85
|
+
await this.#script.addPreloadScript(mutationListener, argumentValues)
|
|
86
|
+
|
|
87
|
+
let id = await this.#script.onMessage(async (message) => {
|
|
88
|
+
let payload = JSON.parse(message['data']['value'])
|
|
89
|
+
let elements = await this.#driver.findElements({
|
|
90
|
+
css: '*[data-__webdriver_id=' + by.escapeCss(payload['target']) + ']',
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
if (elements.length === 0) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let event = {
|
|
98
|
+
element: elements[0],
|
|
99
|
+
attribute_name: payload['name'],
|
|
100
|
+
current_value: payload['value'],
|
|
101
|
+
old_value: payload['oldValue'],
|
|
102
|
+
}
|
|
103
|
+
callback(event)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
return id
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async removeDomMutationHandler(id) {
|
|
110
|
+
await this.#initScript()
|
|
111
|
+
|
|
112
|
+
await this.#script.removeCallback(id)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async pin(script) {
|
|
116
|
+
await this.#initScript()
|
|
117
|
+
return await this.#script.addPreloadScript(script)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async unpin(id) {
|
|
121
|
+
await this.#initScript()
|
|
122
|
+
await this.#script.removePreloadScript(id)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async execute(script, ...args) {
|
|
126
|
+
await this.#initScript()
|
|
127
|
+
|
|
128
|
+
const browsingContextId = await this.#driver.getWindowHandle()
|
|
129
|
+
|
|
130
|
+
const argumentList = []
|
|
131
|
+
|
|
132
|
+
args.forEach((arg) => {
|
|
133
|
+
argumentList.push(LocalValue.getArgument(arg))
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const response = await this.#script.callFunctionInBrowsingContext(browsingContextId, script, true, argumentList)
|
|
137
|
+
|
|
138
|
+
return response.result
|
|
139
|
+
}
|
|
61
140
|
}
|
|
62
141
|
|
|
63
142
|
module.exports = Script
|
package/lib/webdriver.js
CHANGED
|
@@ -44,6 +44,7 @@ const BIDI = require('../bidi')
|
|
|
44
44
|
const { PinnedScript } = require('./pinnedScript')
|
|
45
45
|
const JSZip = require('jszip')
|
|
46
46
|
const Script = require('./script')
|
|
47
|
+
const Network = require('./network')
|
|
47
48
|
|
|
48
49
|
// Capability names that are defined in the W3C spec.
|
|
49
50
|
const W3C_CAPABILITY_NAMES = new Set([
|
|
@@ -656,6 +657,7 @@ function filterNonW3CCaps(capabilities) {
|
|
|
656
657
|
*/
|
|
657
658
|
class WebDriver {
|
|
658
659
|
#script = undefined
|
|
660
|
+
#network = undefined
|
|
659
661
|
/**
|
|
660
662
|
* @param {!(./session.Session|IThenable<!./session.Session>)} session Either
|
|
661
663
|
* a known session or a promise that will be resolved to a session.
|
|
@@ -1116,6 +1118,16 @@ class WebDriver {
|
|
|
1116
1118
|
return this.#script
|
|
1117
1119
|
}
|
|
1118
1120
|
|
|
1121
|
+
network() {
|
|
1122
|
+
// The Network maintains state of the callbacks.
|
|
1123
|
+
// Returning a new instance of the same driver will not work while removing callbacks.
|
|
1124
|
+
if (this.#network === undefined) {
|
|
1125
|
+
this.#network = new Network(this)
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
return this.#network
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1119
1131
|
validatePrintPageParams(keys, object) {
|
|
1120
1132
|
let page = {}
|
|
1121
1133
|
let margin = {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selenium-webdriver",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.24.0",
|
|
4
4
|
"description": "The official WebDriver JavaScript bindings from the Selenium project",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -23,35 +23,36 @@
|
|
|
23
23
|
"node": ">= 14.21.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"@bazel/runfiles": "^5.8.1",
|
|
26
27
|
"jszip": "^3.10.1",
|
|
27
28
|
"tmp": "^0.2.3",
|
|
28
|
-
"ws": "
|
|
29
|
+
"ws": "^8.18.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@
|
|
32
|
-
"@eslint/js": "^9.1.1",
|
|
32
|
+
"@eslint/js": "^9.8.0",
|
|
33
33
|
"clean-jsdoc-theme": "^4.3.0",
|
|
34
|
-
"eslint": "^9.
|
|
34
|
+
"eslint": "^9.8.0",
|
|
35
35
|
"eslint-config-prettier": "^9.1.0",
|
|
36
|
-
"eslint-plugin-mocha": "^10.
|
|
37
|
-
"eslint-plugin-n": "^17.
|
|
36
|
+
"eslint-plugin-mocha": "^10.5.0",
|
|
37
|
+
"eslint-plugin-n": "^17.10.1",
|
|
38
38
|
"eslint-plugin-no-only-tests": "^3.1.0",
|
|
39
|
-
"eslint-plugin-prettier": "^5.1
|
|
39
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
40
40
|
"express": "^4.19.2",
|
|
41
|
-
"globals": "^15.
|
|
41
|
+
"globals": "^15.9.0",
|
|
42
|
+
"has-flag": "^5.0.1",
|
|
42
43
|
"jsdoc": "^4.0.3",
|
|
43
|
-
"mocha": "^10.
|
|
44
|
+
"mocha": "^10.7.0",
|
|
44
45
|
"mocha-junit-reporter": "^2.2.1",
|
|
45
|
-
"multer": "
|
|
46
|
-
"prettier": "^3.
|
|
46
|
+
"multer": "1.4.5-lts.1",
|
|
47
|
+
"prettier": "^3.3.3",
|
|
47
48
|
"serve-index": "^1.9.1",
|
|
48
|
-
"sinon": "^
|
|
49
|
+
"sinon": "^18.0.0",
|
|
50
|
+
"supports-color": "^9.4.0"
|
|
49
51
|
},
|
|
50
52
|
"scripts": {
|
|
51
53
|
"lint": "eslint .",
|
|
52
54
|
"lint:fix": "eslint . --fix",
|
|
53
|
-
"test": "
|
|
54
|
-
"test-jasmine": "bazel test //javascript/node/selenium-webdriver:tests",
|
|
55
|
+
"test": "bazel test //javascript/node/selenium-webdriver/...",
|
|
55
56
|
"generate-docs": "jsdoc --configure jsdoc_conf.json --verbose"
|
|
56
57
|
},
|
|
57
58
|
"mocha": {
|
package/testing/index.js
CHANGED
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
|
|
33
33
|
'use strict'
|
|
34
34
|
|
|
35
|
+
const fs = require('node:fs')
|
|
36
|
+
const path = require('node:path')
|
|
35
37
|
const { isatty } = require('node:tty')
|
|
36
38
|
const chrome = require('../chrome')
|
|
37
39
|
const edge = require('../edge')
|
|
@@ -43,6 +45,14 @@ const { Browser } = require('../lib/capabilities')
|
|
|
43
45
|
const { Builder } = require('../index')
|
|
44
46
|
const { getBinaryPaths } = require('../common/driverFinder')
|
|
45
47
|
|
|
48
|
+
let runfiles
|
|
49
|
+
try {
|
|
50
|
+
// Attempt to require @bazel/runfiles
|
|
51
|
+
runfiles = require('@bazel/runfiles').runfiles
|
|
52
|
+
} catch {
|
|
53
|
+
// Fall through
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
/**
|
|
47
57
|
* Describes a browser targeted by a {@linkplain suite test suite}.
|
|
48
58
|
* @record
|
|
@@ -288,6 +298,37 @@ class Environment {
|
|
|
288
298
|
const urlOrServer = URL_MAP.get(this)
|
|
289
299
|
|
|
290
300
|
const builder = new Builder()
|
|
301
|
+
|
|
302
|
+
// Sniff the environment variables for paths to use for the common browsers
|
|
303
|
+
// Chrome
|
|
304
|
+
if ('SE_CHROMEDRIVER' in process.env) {
|
|
305
|
+
const found = locate(process.env.SE_CHROMEDRIVER)
|
|
306
|
+
const service = new chrome.ServiceBuilder(found)
|
|
307
|
+
builder.setChromeService(service)
|
|
308
|
+
}
|
|
309
|
+
if ('SE_CHROME' in process.env) {
|
|
310
|
+
const binary = locate(process.env.SE_CHROME)
|
|
311
|
+
const options = new chrome.Options()
|
|
312
|
+
options.setChromeBinaryPath(binary)
|
|
313
|
+
options.setAcceptInsecureCerts(true)
|
|
314
|
+
options.addArguments('disable-infobars', 'disable-breakpad', 'disable-dev-shm-usage', 'no-sandbox')
|
|
315
|
+
builder.setChromeOptions(options)
|
|
316
|
+
}
|
|
317
|
+
// Edge
|
|
318
|
+
// Firefox
|
|
319
|
+
if ('SE_GECKODRIVER' in process.env) {
|
|
320
|
+
const found = locate(process.env.SE_GECKODRIVER)
|
|
321
|
+
const service = new firefox.ServiceBuilder(found)
|
|
322
|
+
builder.setFirefoxService(service)
|
|
323
|
+
}
|
|
324
|
+
if ('SE_FIREFOX' in process.env) {
|
|
325
|
+
const binary = locate(process.env.SE_FIREFOX)
|
|
326
|
+
const options = new firefox.Options()
|
|
327
|
+
options.enableBidi()
|
|
328
|
+
options.setBinary(binary)
|
|
329
|
+
builder.setFirefoxOptions(options)
|
|
330
|
+
}
|
|
331
|
+
|
|
291
332
|
builder.disableEnvironmentOverrides()
|
|
292
333
|
|
|
293
334
|
const realBuild = builder.build
|
|
@@ -305,6 +346,7 @@ class Environment {
|
|
|
305
346
|
// Enable BiDi for supporting browsers.
|
|
306
347
|
if (browser.name === Browser.FIREFOX || browser.name === Browser.CHROME || browser.name === Browser.EDGE) {
|
|
307
348
|
builder.setCapability('webSocketUrl', true)
|
|
349
|
+
builder.setCapability('unhandledPromptBehavior', 'ignore')
|
|
308
350
|
}
|
|
309
351
|
|
|
310
352
|
if (typeof urlOrServer === 'string') {
|
|
@@ -505,6 +547,63 @@ function getTestHook(name) {
|
|
|
505
547
|
return fn
|
|
506
548
|
}
|
|
507
549
|
|
|
550
|
+
function locate(fileLike) {
|
|
551
|
+
if (fs.existsSync(fileLike)) {
|
|
552
|
+
return fileLike
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (!runfiles) {
|
|
556
|
+
throw new Error('Unable to find ' + fileLike)
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
try {
|
|
560
|
+
return runfiles.resolve(fileLike)
|
|
561
|
+
} catch {
|
|
562
|
+
// Fall through
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Is the item in the workspace?
|
|
566
|
+
try {
|
|
567
|
+
return runfiles.resolveWorkspaceRelative(fileLike)
|
|
568
|
+
} catch {
|
|
569
|
+
// Fall through
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Find the repo mapping file
|
|
573
|
+
let repoMappingFile
|
|
574
|
+
try {
|
|
575
|
+
repoMappingFile = runfiles.resolve('_repo_mapping')
|
|
576
|
+
} catch {
|
|
577
|
+
throw new Error('Unable to locate (no repo mapping file): ' + fileLike)
|
|
578
|
+
}
|
|
579
|
+
const lines = fs.readFileSync(repoMappingFile, { encoding: 'utf8' }).split('\n')
|
|
580
|
+
|
|
581
|
+
// Build a map of "repo we declared we need" to "path"
|
|
582
|
+
const mapping = {}
|
|
583
|
+
for (const line of lines) {
|
|
584
|
+
if (line.startsWith(',')) {
|
|
585
|
+
const parts = line.split(',', 3)
|
|
586
|
+
mapping[parts[1]] = parts[2]
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Get the first segment of the path
|
|
591
|
+
const pathSegments = fileLike.split('/')
|
|
592
|
+
if (!pathSegments.length) {
|
|
593
|
+
throw new Error('Unable to locate ' + fileLike)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
pathSegments[0] = mapping[pathSegments[0]] ? mapping[pathSegments[0]] : '_main'
|
|
597
|
+
|
|
598
|
+
try {
|
|
599
|
+
return runfiles.resolve(path.join(...pathSegments))
|
|
600
|
+
} catch {
|
|
601
|
+
// Fall through
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
throw new Error('Unable to find ' + fileLike)
|
|
605
|
+
}
|
|
606
|
+
|
|
508
607
|
// PUBLIC API
|
|
509
608
|
|
|
510
609
|
module.exports = {
|