Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/selenium-webdriver/test/bidi/generated/network_test.js
11822 views
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
'use strict'
19
20
const assert = require('node:assert')
21
const { suite, ignore, Pages } = require('../../../lib/test')
22
const { Browser } = require('selenium-webdriver')
23
const { Network } = require('selenium-webdriver/bidi/generated/network')
24
const { BrowsingContext } = require('selenium-webdriver/bidi/generated/browsing_context')
25
26
suite(
27
function (env) {
28
let driver
29
let network
30
let browsingContext
31
let contextId
32
33
beforeEach(async function () {
34
driver = await env.builder().build()
35
network = await Network.create(driver)
36
browsingContext = await BrowsingContext.create(driver)
37
contextId = await driver.getWindowHandle()
38
})
39
40
afterEach(function () {
41
return driver.quit()
42
})
43
44
describe('onBeforeRequestSent', function () {
45
it('receives event when a page is loaded', async function () {
46
let event = null
47
48
await network.onBeforeRequestSent((params) => {
49
if (params.request.url.includes('emptyPage') || params.request.url.includes('empty')) {
50
event = params
51
}
52
})
53
54
await browsingContext.navigate({ context: contextId, url: Pages.emptyPage, wait: 'complete' })
55
56
assert.ok(event, 'beforeRequestSent should have fired')
57
assert.strictEqual(event.request.method, 'GET')
58
assert.ok(event.request.url)
59
assert.ok(event.request.headers.length > 0, 'request should have at least one header')
60
})
61
62
it('receives cookies in beforeRequestSent', async function () {
63
let cookieEvent = null
64
65
await network.onBeforeRequestSent((params) => {
66
// Capture the first event that carries our test cookie
67
if (params.request.cookies && params.request.cookies.some((c) => c.name === 'bidi-test')) {
68
cookieEvent = params
69
}
70
})
71
72
await browsingContext.navigate({ context: contextId, url: Pages.emptyText, wait: 'complete' })
73
await driver.manage().addCookie({ name: 'bidi-test', value: 'works' })
74
await browsingContext.navigate({ context: contextId, url: Pages.emptyText, wait: 'complete' })
75
await driver.wait(() => cookieEvent !== null, 5000)
76
77
assert.ok(cookieEvent, 'beforeRequestSent with bidi-test cookie should have fired')
78
const cookie = cookieEvent.request.cookies.find((c) => c.name === 'bidi-test')
79
assert.ok(cookie, 'cookie should appear in request')
80
assert.strictEqual(cookie.value.value, 'works')
81
})
82
})
83
84
describe('onResponseCompleted', function () {
85
it('receives event when a response completes', async function () {
86
let event = null
87
88
await network.onResponseCompleted((params) => {
89
// Capture the first responseCompleted event — no URL filter needed.
90
if (!event) {
91
event = params
92
}
93
})
94
95
await browsingContext.navigate({ context: contextId, url: Pages.emptyPage, wait: 'complete' })
96
await driver.wait(() => event !== null, 5000)
97
98
assert.ok(event, 'responseCompleted should have fired')
99
assert.ok(event.response)
100
assert.ok(event.response.status >= 200)
101
assert.ok(event.response.url)
102
})
103
})
104
105
describe('onFetchError', function () {
106
it('receives event on network fetch error', async function () {
107
let errorEvent = null
108
109
await network.onFetchError((params) => {
110
errorEvent = params
111
})
112
113
// Navigate to a non-existent host to trigger a fetch error.
114
// Use wait: 'none' so the call returns immediately — waiting for
115
// 'complete' on a non-existent host blocks for the full TCP/DNS
116
// timeout before the fetchError event can be observed.
117
await browsingContext
118
.navigate({ context: contextId, url: 'http://doesnotexist.invalid/', wait: 'none' })
119
.catch(() => {})
120
await driver.wait(() => errorEvent !== null, 5000)
121
122
assert.ok(errorEvent, 'fetchError should have fired')
123
assert.ok(errorEvent.request)
124
})
125
})
126
127
describe('addIntercept and continueRequest', function () {
128
it('can add and remove an intercept', async function () {
129
const result = await network.addIntercept({
130
phases: ['beforeRequestSent'],
131
})
132
133
assert.ok(result.intercept, 'intercept id should be returned')
134
assert.strictEqual(typeof result.intercept, 'string')
135
136
await network.removeIntercept({ intercept: result.intercept })
137
})
138
139
it('throws when removing a non-existent intercept', async function () {
140
await assert.rejects(() => network.removeIntercept({ intercept: 'no-such-intercept-id' }), /no such intercept/)
141
})
142
143
it('can intercept and continue a request', async function () {
144
const intercept = await network.addIntercept({
145
phases: ['beforeRequestSent'],
146
})
147
148
let counter = 0
149
await network.onBeforeRequestSent(async (params) => {
150
if (params.isBlocked) {
151
counter++
152
try {
153
await network.continueRequest({ request: params.request.request })
154
} catch (_err) {
155
// ignore — request may already be resolved
156
}
157
}
158
})
159
160
await browsingContext.navigate({ context: contextId, url: Pages.logEntryAdded, wait: 'complete' })
161
162
assert.ok(counter >= 1, 'at least one request should have been intercepted and continued')
163
await network.removeIntercept({ intercept: intercept.intercept })
164
})
165
166
it('can intercept by url pattern', async function () {
167
const result = await network.addIntercept({
168
phases: ['beforeRequestSent'],
169
urlPatterns: [{ type: 'string', pattern: Pages.emptyPage }],
170
})
171
172
assert.ok(result.intercept)
173
174
await network.removeIntercept({ intercept: result.intercept })
175
})
176
})
177
178
describe('failRequest', function () {
179
it('can fail an intercepted request', async function () {
180
const intercept = await network.addIntercept({
181
phases: ['beforeRequestSent'],
182
urlPatterns: [{ type: 'string', pattern: Pages.emptyText }],
183
})
184
185
let interceptHandled = false
186
await network.onBeforeRequestSent(async (params) => {
187
if (params.isBlocked && params.request.url.includes('emptyText') && !interceptHandled) {
188
interceptHandled = true
189
try {
190
await network.failRequest({ request: params.request.request })
191
} catch (_err) {
192
// ignore — request may already be gone
193
}
194
}
195
})
196
197
// Navigation will fail because we're blocking it — that's expected
198
await browsingContext.navigate({ context: contextId, url: Pages.emptyText, wait: 'complete' }).catch(() => {})
199
200
await network.removeIntercept({ intercept: intercept.intercept })
201
})
202
})
203
204
describe('setCacheBehavior', function () {
205
it('can set cache behavior to bypass', async function () {
206
const contextId = await driver.getWindowHandle()
207
208
const result = await network.setCacheBehavior({
209
cacheBehavior: 'bypass',
210
contexts: [contextId],
211
})
212
})
213
214
it('can set cache behavior back to default', async function () {
215
const contextId = await driver.getWindowHandle()
216
217
await network.setCacheBehavior({ cacheBehavior: 'bypass', contexts: [contextId] })
218
await network.setCacheBehavior({ cacheBehavior: 'default', contexts: [contextId] })
219
})
220
221
it('can set global cache behavior', async function () {
222
await network.setCacheBehavior({ cacheBehavior: 'bypass' })
223
await network.setCacheBehavior({ cacheBehavior: 'default' })
224
})
225
})
226
227
describe('setExtraHeaders', function () {
228
it('can set extra headers for a context', async function () {
229
const contextId = await driver.getWindowHandle()
230
231
const result = await network.setExtraHeaders({
232
headers: [{ name: 'x-custom-header', value: { type: 'string', value: 'test-value' } }],
233
contexts: [contextId],
234
})
235
})
236
237
it('can clear extra headers', async function () {
238
const contextId = await driver.getWindowHandle()
239
240
await network.setExtraHeaders({
241
headers: [{ name: 'x-custom-header', value: { type: 'string', value: 'test' } }],
242
contexts: [contextId],
243
})
244
await network.setExtraHeaders({
245
headers: [],
246
contexts: [contextId],
247
})
248
})
249
})
250
251
describe('onResponseStarted', function () {
252
it('receives event when a response starts', async function () {
253
let event = null
254
255
await network.onResponseStarted((params) => {
256
if (!event) {
257
event = params
258
}
259
})
260
261
await browsingContext.navigate({ context: contextId, url: Pages.emptyPage, wait: 'complete' })
262
await driver.wait(() => event !== null, 5000)
263
264
assert.ok(event, 'responseStarted should have fired')
265
assert.ok(event.response)
266
})
267
})
268
},
269
{ browsers: [Browser.CHROME, Browser.FIREFOX] },
270
)
271
272