Skip to content

Commit 72bfa0f

Browse files
Merge branch 'trunk' into 15697Fixx
2 parents 3e68109 + 01548e0 commit 72bfa0f

File tree

5 files changed

+174
-29
lines changed

5 files changed

+174
-29
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
package org.openqa.selenium.bidi.browsingcontext;
19+
20+
import org.openqa.selenium.json.JsonInput;
21+
22+
public class DownloadInfo extends NavigationInfo {
23+
24+
private final String suggestedFilename;
25+
26+
private DownloadInfo(
27+
String browsingContextId,
28+
String navigationId,
29+
long timestamp,
30+
String url,
31+
String suggestedFilename) {
32+
super(browsingContextId, navigationId, timestamp, url);
33+
this.suggestedFilename = suggestedFilename;
34+
}
35+
36+
public static DownloadInfo fromJson(JsonInput input) {
37+
String browsingContextId = null;
38+
String navigationId = null;
39+
long timestamp = 0;
40+
String url = null;
41+
String suggestedFilename = null;
42+
43+
input.beginObject();
44+
while (input.hasNext()) {
45+
switch (input.nextName()) {
46+
case "context":
47+
browsingContextId = input.read(String.class);
48+
break;
49+
50+
case "navigation":
51+
navigationId = input.read(String.class);
52+
break;
53+
54+
case "timestamp":
55+
timestamp = input.read(Long.class);
56+
break;
57+
58+
case "url":
59+
url = input.read(String.class);
60+
break;
61+
62+
case "suggestedFilename":
63+
suggestedFilename = input.read(String.class);
64+
break;
65+
66+
default:
67+
input.skipValue();
68+
break;
69+
}
70+
}
71+
72+
input.endObject();
73+
74+
return new DownloadInfo(browsingContextId, navigationId, timestamp, url, suggestedFilename);
75+
}
76+
77+
public String getSuggestedFilename() {
78+
return suggestedFilename;
79+
}
80+
}

java/src/org/openqa/selenium/bidi/browsingcontext/NavigationInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class NavigationInfo {
3333

3434
private final String url;
3535

36-
private NavigationInfo(
36+
protected NavigationInfo(
3737
String browsingContextId, String navigationId, long timestamp, String url) {
3838
this.browsingContextId = browsingContextId;
3939
this.navigationId = navigationId;

java/src/org/openqa/selenium/bidi/module/BrowsingContextInspector.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.openqa.selenium.bidi.Event;
3030
import org.openqa.selenium.bidi.HasBiDi;
3131
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
32+
import org.openqa.selenium.bidi.browsingcontext.DownloadInfo;
3233
import org.openqa.selenium.bidi.browsingcontext.HistoryUpdated;
3334
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
3435
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
@@ -61,6 +62,14 @@ public class BrowsingContextInspector implements AutoCloseable {
6162
}
6263
};
6364

65+
private final Function<Map<String, Object>, DownloadInfo> downloadWillBeginMapper =
66+
params -> {
67+
try (StringReader reader = new StringReader(JSON.toJson(params));
68+
JsonInput input = JSON.newInput(reader)) {
69+
return input.read(DownloadInfo.class);
70+
}
71+
};
72+
6473
private final Event<BrowsingContextInfo> browsingContextCreated =
6574
new Event<>("browsingContext.contextCreated", browsingContextInfoMapper);
6675

@@ -79,6 +88,9 @@ public class BrowsingContextInspector implements AutoCloseable {
7988

8089
private final Set<Event<NavigationInfo>> navigationEventSet = new HashSet<>();
8190

91+
private final Event<DownloadInfo> downloadWillBeginEvent =
92+
new Event<>("browsingContext.downloadWillBegin", downloadWillBeginMapper);
93+
8294
private final Event<UserPromptOpened> userPromptOpened =
8395
new Event<>(
8496
"browsingContext.userPromptOpened",
@@ -151,8 +163,12 @@ public void onBrowsingContextLoaded(Consumer<NavigationInfo> consumer) {
151163
addNavigationEventListener("browsingContext.load", consumer);
152164
}
153165

154-
public void onDownloadWillBegin(Consumer<NavigationInfo> consumer) {
155-
addNavigationEventListener("browsingContext.downloadWillBegin", consumer);
166+
public void onDownloadWillBegin(Consumer<DownloadInfo> consumer) {
167+
if (browsingContextIds.isEmpty()) {
168+
this.bidi.addListener(downloadWillBeginEvent, consumer);
169+
} else {
170+
this.bidi.addListener(browsingContextIds, downloadWillBeginEvent, consumer);
171+
}
156172
}
157173

158174
public void onNavigationAborted(Consumer<NavigationInfo> consumer) {
@@ -210,6 +226,7 @@ public void close() {
210226
this.bidi.clearListener(userPromptOpened);
211227
this.bidi.clearListener(userPromptClosed);
212228
this.bidi.clearListener(historyUpdated);
229+
this.bidi.clearListener(downloadWillBeginEvent);
213230

214231
navigationEventSet.forEach(this.bidi::clearListener);
215232
}

java/test/org/openqa/selenium/bidi/browsingcontext/BrowsingContextInspectorTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
3232
import org.openqa.selenium.testing.JupiterTestBase;
3333
import org.openqa.selenium.testing.NeedsFreshDriver;
34+
import org.openqa.selenium.testing.NotYetImplemented;
3435

3536
class BrowsingContextInspectorTest extends JupiterTestBase {
3637

@@ -231,4 +232,51 @@ void canListenToNavigationCommittedEvent()
231232
assertThat(navigationInfo.getUrl()).contains("/bidi/logEntryAdded.html");
232233
}
233234
}
235+
236+
@Test
237+
@NeedsFreshDriver
238+
@NotYetImplemented(FIREFOX)
239+
void canListenToDownloadWillBeginEvent()
240+
throws ExecutionException, InterruptedException, TimeoutException {
241+
try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
242+
CompletableFuture<DownloadInfo> future = new CompletableFuture<>();
243+
244+
inspector.onDownloadWillBegin(future::complete);
245+
246+
BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
247+
context.navigate(appServer.whereIs("/downloads/download.html"), ReadinessState.COMPLETE);
248+
249+
driver.findElement(By.id("file-1")).click();
250+
251+
DownloadInfo downloadInfo = future.get(5, TimeUnit.SECONDS);
252+
assertThat(downloadInfo.getBrowsingContextId()).isEqualTo(context.getId());
253+
assertThat(downloadInfo.getUrl()).contains("/downloads/file_1.txt");
254+
assertThat(downloadInfo.getSuggestedFilename()).isEqualTo("file_1.txt");
255+
}
256+
}
257+
258+
@Test
259+
@NeedsFreshDriver
260+
@NotYetImplemented(FIREFOX)
261+
void canListenToNavigationFailedEvent()
262+
throws ExecutionException, InterruptedException, TimeoutException {
263+
try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
264+
CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
265+
266+
inspector.onNavigationFailed(future::complete);
267+
268+
BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
269+
try {
270+
context.navigate(
271+
"http://invalid-domain-that-does-not-exist.test/", ReadinessState.COMPLETE);
272+
} catch (Exception e) {
273+
// Expect an exception due to navigation failure
274+
}
275+
276+
NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);
277+
assertThat(navigationInfo.getBrowsingContextId()).isEqualTo(context.getId());
278+
assertThat(navigationInfo.getUrl())
279+
.isEqualTo("http://invalid-domain-that-does-not-exist.test/");
280+
}
281+
}
234282
}

py/conftest.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import pytest
2424

2525
from selenium import webdriver
26+
from selenium.common.exceptions import WebDriverException
2627
from selenium.webdriver.remote.server import Server
2728
from test.selenium.webdriver.common.network import get_lan_ip
2829
from test.selenium.webdriver.common.webserver import SimpleWebServer
@@ -101,7 +102,6 @@ def pytest_generate_tests(metafunc):
101102
metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True)
102103

103104

104-
driver_instance = None
105105
selenium_driver = None
106106

107107

@@ -276,7 +276,8 @@ def service(self):
276276

277277
@property
278278
def driver(self):
279-
self._driver = self._initialize_driver()
279+
if self._driver is None:
280+
self._driver = self._initialize_driver()
280281
return self._driver
281282

282283
@property
@@ -297,21 +298,15 @@ def _initialize_driver(self):
297298
kwargs["service"] = self.service
298299
return getattr(webdriver, self.driver_class)(**kwargs)
299300

300-
@property
301301
def stop_driver(self):
302-
def fin():
303-
global driver_instance
304-
if self._driver is not None:
305-
self._driver.quit()
306-
self._driver = None
307-
driver_instance = None
308-
309-
return fin
302+
driver_to_stop = self._driver
303+
self._driver = None
304+
if driver_to_stop is not None:
305+
driver_to_stop.quit()
310306

311307

312308
@pytest.fixture(scope="function")
313309
def driver(request):
314-
global driver_instance
315310
global selenium_driver
316311
driver_class = getattr(request, "param", "Chrome").lower()
317312

@@ -345,38 +340,43 @@ def driver(request):
345340

346341
request.addfinalizer(selenium_driver.stop_driver)
347342

348-
if driver_instance is None:
349-
driver_instance = selenium_driver.driver
350-
351-
yield driver_instance
352343
# Close the browser after BiDi tests. Those make event subscriptions
353344
# and doesn't seems to be stable enough, causing the flakiness of the
354345
# subsequent tests.
355346
# Remove this when BiDi implementation and API is stable.
356-
if selenium_driver.bidi:
347+
if selenium_driver is not None and selenium_driver.bidi:
357348
request.addfinalizer(selenium_driver.stop_driver)
358349

350+
yield selenium_driver.driver
351+
359352
if request.node.get_closest_marker("no_driver_after_test"):
360-
driver_instance = None
353+
if selenium_driver is not None:
354+
try:
355+
selenium_driver.stop_driver()
356+
except WebDriverException:
357+
pass
358+
except Exception:
359+
raise
360+
selenium_driver = None
361361

362362

363363
@pytest.fixture(scope="session", autouse=True)
364364
def stop_driver(request):
365365
def fin():
366-
global driver_instance
367-
if driver_instance is not None:
368-
driver_instance.quit()
369-
driver_instance = None
366+
global selenium_driver
367+
if selenium_driver is not None:
368+
selenium_driver.stop_driver()
369+
selenium_driver = None
370370

371371
request.addfinalizer(fin)
372372

373373

374374
def pytest_exception_interact(node, call, report):
375375
if report.failed:
376-
global driver_instance
377-
if driver_instance is not None:
378-
driver_instance.quit()
379-
driver_instance = None
376+
global selenium_driver
377+
if selenium_driver is not None:
378+
selenium_driver.stop_driver()
379+
selenium_driver = None
380380

381381

382382
@pytest.fixture

0 commit comments

Comments
 (0)