Skip to content

Commit a003f94

Browse files
committed
#1816 allow clipboard operations in remote Chromium browsers
Theoretically, this solution should work for Chrome, but didn't work for me: driver.setPermission("clipboard-read", "granted"); driver.setPermission("clipboard-write", "granted");
1 parent 9d26f63 commit a003f94

2 files changed

Lines changed: 42 additions & 4 deletions

File tree

src/main/java/com/codeborne/selenide/DefaultClipboard.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.codeborne.selenide;
22

3+
import org.openqa.selenium.chromium.ChromiumDriver;
4+
import org.openqa.selenium.devtools.DevTools;
5+
import org.openqa.selenium.devtools.HasDevTools;
6+
import org.openqa.selenium.devtools.v127.browser.Browser;
7+
38
import javax.annotation.CheckReturnValue;
49
import javax.annotation.Nonnull;
510
import javax.annotation.ParametersAreNonnullByDefault;
@@ -8,6 +13,14 @@
813
import java.awt.datatransfer.StringSelection;
914
import java.awt.datatransfer.UnsupportedFlavorException;
1015
import java.io.IOException;
16+
import java.util.List;
17+
import java.util.Optional;
18+
19+
import static com.codeborne.selenide.impl.WebdriverUnwrapper.cast;
20+
import static com.codeborne.selenide.impl.WebdriverUnwrapper.instanceOf;
21+
import static java.util.Optional.empty;
22+
import static org.openqa.selenium.devtools.v127.browser.model.PermissionType.CLIPBOARDREADWRITE;
23+
import static org.openqa.selenium.devtools.v127.browser.model.PermissionType.CLIPBOARDSANITIZEDWRITE;
1124

1225
@ParametersAreNonnullByDefault
1326
public class DefaultClipboard implements Clipboard {
@@ -31,12 +44,25 @@ public Clipboard object() {
3144
return this;
3245
}
3346

47+
private boolean grantPermission() {
48+
Optional<HasDevTools> cdpBrowser = cast(driver, HasDevTools.class);
49+
if (cdpBrowser.isPresent() && instanceOf(driver, ChromiumDriver.class)) {
50+
DevTools devTools = cdpBrowser.get().getDevTools();
51+
devTools.send(Browser.grantPermissions(List.of(CLIPBOARDREADWRITE, CLIPBOARDSANITIZEDWRITE), empty(), empty()));
52+
return true;
53+
}
54+
return false;
55+
}
56+
3457
@CheckReturnValue
3558
@Nonnull
3659
@Override
3760
public String getText() {
38-
assertRemoteState();
61+
if (grantPermission()) {
62+
return driver.executeJavaScript("return await navigator.clipboard.readText()");
63+
}
3964
try {
65+
assertLocalBrowser();
4066
return Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor).toString();
4167
}
4268
catch (UnsupportedFlavorException | IOException e) {
@@ -46,11 +72,16 @@ public String getText() {
4672

4773
@Override
4874
public void setText(String text) {
49-
assertRemoteState();
50-
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), new StringSelection(text));
75+
if (grantPermission()) {
76+
driver.executeJavaScript("await navigator.clipboard.writeText(arguments[0])", text);
77+
}
78+
else {
79+
assertLocalBrowser();
80+
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), new StringSelection(text));
81+
}
5182
}
5283

53-
private void assertRemoteState() {
84+
private void assertLocalBrowser() {
5485
if (driver.config().remote() != null)
5586
throw new IllegalStateException("Remote driver url detected! Please use remote clipboard.");
5687
}

statics/src/test/java/integration/IntegrationTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import static com.codeborne.selenide.TextCheck.FULL_TEXT;
3737
import static com.codeborne.selenide.WebDriverRunner.closeWebDriver;
3838
import static com.codeborne.selenide.WebDriverRunner.hasWebDriverStarted;
39+
import static com.codeborne.selenide.WebDriverRunner.isChrome;
40+
import static com.codeborne.selenide.WebDriverRunner.isEdge;
3941
import static com.codeborne.selenide.WebDriverRunner.isIE;
4042
import static org.assertj.core.api.Assumptions.assumeThat;
4143
import static org.openqa.selenium.remote.CapabilityType.ACCEPT_INSECURE_CERTS;
@@ -173,6 +175,11 @@ protected static FirefoxOptions firefoxOptions(@Nullable SelenideProxyServer pro
173175
}
174176

175177
protected void assumeClipboardSupported() {
178+
if (isChrome() || isEdge()) {
179+
// in Chromium browsers, we grant permissions via DevTools and access clipboard via JS
180+
return;
181+
}
182+
176183
assumeThat(headless).isFalse();
177184
assumeThat(GraphicsEnvironment.isHeadless()).isFalse();
178185
try {

0 commit comments

Comments
 (0)