Skip to content

Commit 96f13f8

Browse files
authored
[java] implement file downloads (#12979)
* [java] download file to disk without string return * [java] implement options method to toggle downloads enabled
1 parent 9b0d14f commit 96f13f8

File tree

8 files changed

+193
-75
lines changed

8 files changed

+193
-75
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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;
19+
20+
import java.io.IOException;
21+
import java.nio.file.Path;
22+
import java.util.List;
23+
24+
/** Indicates that a driver supports downloading remote files. */
25+
public interface HasDownloads {
26+
27+
/**
28+
* Requires downloads to be enabled.
29+
*
30+
* <p>TODO: Create an example in the documentation and provide a link to it.
31+
*
32+
* @param capabilities the capabilities object
33+
* @throws WebDriverException if capability to enable downloads is not set
34+
*/
35+
default void requireDownloadsEnabled(Capabilities capabilities) {
36+
boolean downloadsEnabled = (boolean) capabilities.getCapability("se:downloadsEnabled");
37+
if (!downloadsEnabled) {
38+
throw new WebDriverException(
39+
"You must enable downloads in order to work with downloadable files.");
40+
}
41+
}
42+
43+
/**
44+
* Gets the downloadable files.
45+
*
46+
* @return a list of downloadable files for each key
47+
*/
48+
List<String> getDownloadableFiles();
49+
50+
/**
51+
* Downloads a file to a given location.
52+
*
53+
* @param fileName the name of the file to be downloaded
54+
* @param targetLocation the location where the file will be downloaded to
55+
* @throws IOException if an I/O error occurs while downloading the file
56+
*/
57+
void downloadFile(String fileName, Path targetLocation) throws IOException;
58+
59+
/** Deletes the downloadable files. */
60+
void deleteDownloadableFiles();
61+
}

java/src/org/openqa/selenium/remote/AbstractDriverOptions.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import static org.openqa.selenium.remote.CapabilityType.ACCEPT_INSECURE_CERTS;
2121
import static org.openqa.selenium.remote.CapabilityType.BROWSER_VERSION;
22+
import static org.openqa.selenium.remote.CapabilityType.ENABLE_DOWNLOADS;
2223
import static org.openqa.selenium.remote.CapabilityType.PAGE_LOAD_STRATEGY;
2324
import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;
2425
import static org.openqa.selenium.remote.CapabilityType.PROXY;
@@ -101,6 +102,11 @@ public DO setProxy(Proxy proxy) {
101102
return (DO) this;
102103
}
103104

105+
public DO setEnableDownloads(boolean enableDownloads) {
106+
setCapability(ENABLE_DOWNLOADS, enableDownloads);
107+
return (DO) this;
108+
}
109+
104110
@Override
105111
public Set<String> getCapabilityNames() {
106112
TreeSet<String> names = new TreeSet<>(super.getCapabilityNames());

java/src/org/openqa/selenium/remote/CapabilityType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ public interface CapabilityType {
3030
String TIMEOUTS = "timeouts";
3131
String STRICT_FILE_INTERACTABILITY = "strictFileInteractability";
3232
String UNHANDLED_PROMPT_BEHAVIOUR = "unhandledPromptBehavior";
33+
String ENABLE_DOWNLOADS = "se:downloadsEnabled";
3334
}

java/src/org/openqa/selenium/remote/DriverCommand.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ public interface DriverCommand {
171171
String GET_FEDCM_DIALOG_TYPE = "getFedCmDialogType";
172172
String SET_DELAY_ENABLED = "setDelayEnabled";
173173
String RESET_COOLDOWN = "resetCooldown";
174+
String GET_DOWNLOADABLE_FILES = "getDownloadableFiles";
175+
String DOWNLOAD_FILE = "downloadFile";
176+
String DELETE_DOWNLOADABLE_FILES = "deleteDownloadableFiles";
174177

175178
static CommandPayload NEW_SESSION(Capabilities capabilities) {
176179
Require.nonNull("Capabilities", capabilities);

java/src/org/openqa/selenium/remote/RemoteWebDriver.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424

2525
import com.google.common.collect.ImmutableMap;
2626
import com.google.common.collect.ImmutableSet;
27+
import java.io.IOException;
2728
import java.net.MalformedURLException;
2829
import java.net.URL;
30+
import java.nio.file.Path;
2931
import java.time.Duration;
3032
import java.util.ArrayList;
3133
import java.util.Base64;
@@ -51,6 +53,7 @@
5153
import org.openqa.selenium.Cookie;
5254
import org.openqa.selenium.Dimension;
5355
import org.openqa.selenium.HasCapabilities;
56+
import org.openqa.selenium.HasDownloads;
5457
import org.openqa.selenium.ImmutableCapabilities;
5558
import org.openqa.selenium.JavascriptException;
5659
import org.openqa.selenium.JavascriptExecutor;
@@ -82,6 +85,7 @@
8285
import org.openqa.selenium.interactions.Sequence;
8386
import org.openqa.selenium.internal.Debug;
8487
import org.openqa.selenium.internal.Require;
88+
import org.openqa.selenium.io.Zip;
8589
import org.openqa.selenium.json.TypeToken;
8690
import org.openqa.selenium.logging.LocalLogs;
8791
import org.openqa.selenium.logging.LoggingHandler;
@@ -105,6 +109,7 @@ public class RemoteWebDriver
105109
implements WebDriver,
106110
JavascriptExecutor,
107111
HasCapabilities,
112+
HasDownloads,
108113
HasFederatedCredentialManagement,
109114
HasVirtualAuthenticator,
110115
Interactive,
@@ -707,6 +712,51 @@ public void removeVirtualAuthenticator(VirtualAuthenticator authenticator) {
707712
ImmutableMap.of("authenticatorId", authenticator.getId()));
708713
}
709714

715+
/**
716+
* Retrieves the downloadable files as a map of file names and their corresponding URLs.
717+
*
718+
* @return A map containing file names as keys and URLs as values.
719+
* @throws WebDriverException if capability to enable downloads is not set
720+
*/
721+
@Override
722+
@SuppressWarnings("unchecked")
723+
public List<String> getDownloadableFiles() {
724+
requireDownloadsEnabled(capabilities);
725+
726+
Response response = execute(DriverCommand.GET_DOWNLOADABLE_FILES);
727+
Map<String, List<String>> value = (Map<String, List<String>>) response.getValue();
728+
return value.get("names");
729+
}
730+
731+
/**
732+
* Downloads a file from the specified location.
733+
*
734+
* @param fileName the name of the file to download
735+
* @param targetLocation the location where the file should be downloaded
736+
* @throws IOException if an I/O error occurs during the file download
737+
*/
738+
@SuppressWarnings("unchecked")
739+
@Override
740+
public void downloadFile(String fileName, Path targetLocation) throws IOException {
741+
requireDownloadsEnabled(capabilities);
742+
743+
Response response = execute(DriverCommand.DOWNLOAD_FILE, Map.of("name", fileName));
744+
String contents = ((Map<String, String>) response.getValue()).get("contents");
745+
Zip.unzip(contents, targetLocation.toFile());
746+
}
747+
748+
/**
749+
* Deletes all downloadable files.
750+
*
751+
* @throws WebDriverException capability to enable downloads must be set
752+
*/
753+
@Override
754+
public void deleteDownloadableFiles() {
755+
requireDownloadsEnabled(capabilities);
756+
757+
execute(DriverCommand.DELETE_DOWNLOADABLE_FILES);
758+
}
759+
710760
@Override
711761
public void setDelayEnabled(boolean enabled) {
712762
execute(DriverCommand.SET_DELAY_ENABLED(enabled));

java/src/org/openqa/selenium/remote/codec/AbstractHttpCommandCodec.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import static org.openqa.selenium.remote.DriverCommand.CLOSE;
3333
import static org.openqa.selenium.remote.DriverCommand.DELETE_ALL_COOKIES;
3434
import static org.openqa.selenium.remote.DriverCommand.DELETE_COOKIE;
35+
import static org.openqa.selenium.remote.DriverCommand.DELETE_DOWNLOADABLE_FILES;
36+
import static org.openqa.selenium.remote.DriverCommand.DOWNLOAD_FILE;
3537
import static org.openqa.selenium.remote.DriverCommand.ELEMENT_EQUALS;
3638
import static org.openqa.selenium.remote.DriverCommand.ELEMENT_SCREENSHOT;
3739
import static org.openqa.selenium.remote.DriverCommand.FIND_CHILD_ELEMENT;
@@ -51,6 +53,7 @@
5153
import static org.openqa.selenium.remote.DriverCommand.GET_CREDENTIALS;
5254
import static org.openqa.selenium.remote.DriverCommand.GET_CURRENT_CONTEXT_HANDLE;
5355
import static org.openqa.selenium.remote.DriverCommand.GET_CURRENT_URL;
56+
import static org.openqa.selenium.remote.DriverCommand.GET_DOWNLOADABLE_FILES;
5457
import static org.openqa.selenium.remote.DriverCommand.GET_ELEMENT_LOCATION;
5558
import static org.openqa.selenium.remote.DriverCommand.GET_ELEMENT_RECT;
5659
import static org.openqa.selenium.remote.DriverCommand.GET_ELEMENT_SIZE;
@@ -237,6 +240,10 @@ public AbstractHttpCommandCodec() {
237240
defineCommand(GET_FEDCM_DIALOG_TYPE, get(fedcm + "/getdialogtype"));
238241
defineCommand(SET_DELAY_ENABLED, post(fedcm + "/setdelayenabled"));
239242
defineCommand(RESET_COOLDOWN, post(fedcm + "/resetCooldown"));
243+
244+
defineCommand(GET_DOWNLOADABLE_FILES, get(sessionId + "/se/files"));
245+
defineCommand(DOWNLOAD_FILE, post(sessionId + "/se/files"));
246+
defineCommand(DELETE_DOWNLOADABLE_FILES, delete(sessionId + "/se/files"));
240247
}
241248

242249
protected static CommandSpec delete(String path) {

java/test/org/openqa/selenium/chrome/ChromeOptionsTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ void canAddW3CCompliantOptions() {
8484
.setAcceptInsecureCerts(true)
8585
.setPageLoadStrategy(PageLoadStrategy.EAGER)
8686
.setStrictFileInteractability(true)
87+
.setEnableDownloads(true)
8788
.setImplicitWaitTimeout(Duration.ofSeconds(1))
8889
.setPageLoadTimeout(Duration.ofSeconds(2))
8990
.setScriptTimeout(Duration.ofSeconds(3));
@@ -96,6 +97,7 @@ void canAddW3CCompliantOptions() {
9697
assertThat(mappedOptions.get("acceptInsecureCerts")).isEqualTo(true);
9798
assertThat(mappedOptions.get("pageLoadStrategy")).hasToString("eager");
9899
assertThat(mappedOptions.get("strictFileInteractability")).isEqualTo(true);
100+
assertThat(mappedOptions.get("se:downloadsEnabled")).isEqualTo(true);
99101

100102
Map<String, Long> expectedTimeouts = new HashMap<>();
101103
expectedTimeouts.put("implicit", 1000L);

0 commit comments

Comments
 (0)