I came up with this to test pasting using the clipboard API. A big part of the problem was permissions that as of 12/2020 need to be kinda hacked in:
// Setup web driver
ChromeOptions options = new ChromeOptions();
Map<String, Object> prefs = new HashMap<>();
Map<String, Object> profile = new HashMap<>();
Map<String, Object> contentSettings = new HashMap<>();
Map<String, Object> exceptions = new HashMap<>();
Map<String, Object> clipboard = new HashMap<>();
Map<String, Object> domain = new HashMap<>();
// Enable clipboard permissions
domain.put("expiration", 0);
domain.put("last_modified", System.currentTimeMillis());
domain.put("model", 0);
domain.put("setting", 1);
clipboard.put("https://google.com,*", domain); // <- Replace with test domain
exceptions.put("clipboard", clipboard);
contentSettings.put("exceptions", exceptions);
profile.put("content_settings", contentSettings);
prefs.put("profile", profile);
options.setExperimentalOption("prefs", prefs);
// [...]
driver.executeScript("navigator.clipboard.writeText('sample text');");
pasteButton.click();
Javascript in running in browser:
// Button handler
navigator.clipboard.readText().then(t-> console.log("pasted text: " + t));
Though if you ever spawn another window or that window loses focus, you'll get a practically-silent JavaScript error:
// JS console in browser
"DOMException: Document is not focused."
// error thrown in promise
{name: "NotAllowedError", message: "Document is not focused."}
So we need to figure out some way to bring the window into focus. We also need to prevent any other test code from interfeering with the clipboard while we are using it, so I created a Reentrant Lock.
I'm using this code to update the clipboard:
Test code:
try {
Browser.clipboardLock.lock();
b.updateClipboard("Sample text");
b.sendPaste();
}finally {
Browser.clipboardLock.unlock();
}
Browser Class:
public static ReentrantLock clipboardLock = new ReentrantLock();
public void updateClipboard(String newClipboardValue) throws InterruptedException {
if (!clipboardLock.isHeldByCurrentThread())
throw new IllegalStateException("Must own clipboardLock to update clipboard");
for (int i = 0; i < 20; i++) {
webDriver.executeScript("" +
"window.clipboardWritten = null;" +
"window.clipboardWrittenError = null;" +
"window.textToWrite=`" + newClipboardValue + "`;" +
"navigator.clipboard.writeText(window.textToWrite)" +
" .then(()=>window.clipboardWritten=window.textToWrite)" +
" .catch(r=>window.clipboardWrittenError=r)" +
";"
);
while (!newClipboardValue.equals(webDriver.executeScript("return window.clipboardWritten;"))) {
Object error = webDriver.executeScript("return window.clipboardWrittenError;");
if (error != null) {
String message = error.toString();
try {
message = ((Map) error).get("name") + ": " + ((Map) error).get("message");
} catch (Exception ex) {
log.debug("Could not get JS error string", ex);
}
if (message.equals("NotAllowedError: Document is not focused.")) {
webDriver.switchTo().window(webDriver.getWindowHandle());
break;
} else {
throw new IllegalStateException("Clipboard could not be written: " + message);
}
}
Thread.sleep(50);
}
}
}