Skip to content

Commit 1aa729f

Browse files
authored
418 Recipe for writting and reading from clipboard (#520)
* New example of using clipboard * Fix for NotAllowedError: Document is not focused * trigger build --ci
1 parent 38f70a6 commit 1aa729f

File tree

7 files changed

+103
-1
lines changed

7 files changed

+103
-1
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ jobs:
77
matrix:
88
exampleDir:
99
- click
10+
- clipboard
1011
- customMatchers
1112
- deleteCookies
1213
- emulate

clipboard/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# `clipboard` Example
2+
3+
This directory contains the example files for interacting with the system clipboard using
4+
WebDriverIO.
5+
6+
## Prerequisite
7+
8+
Make sure to run this first, to set up the example repository:
9+
10+
```sh
11+
npm install
12+
```
13+
14+
## Example
15+
16+
Run example via:
17+
18+
```sh
19+
npm run clipboard
20+
```

clipboard/chrome-example.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { browser, expect, $ } from '@wdio/globals'
2+
3+
describe('Clipboard: Chrome', () => {
4+
before(() => browser.url('/example.html'))
5+
6+
it('should allow the browser to read the clipboard', async () => {
7+
// set clipboard permissions
8+
await browser.setPermissions({ name: 'clipboard-read' }, 'granted')
9+
10+
const btn = await $('#copyBtn')
11+
await btn.click()
12+
13+
// Use a focus event to trigger the async clipboard read, then save
14+
// the result to a global variable on the window object
15+
// Without this the clipboard read may be blocked
16+
// with "NotAllowedError: Document is not focused."
17+
// See: https://stackoverflow.com/questions/56306153/domexception-on-calling-navigator-clipboard-readtext
18+
await browser.execute(() => {
19+
const _asyncCopyFn = (async () => {
20+
setTimeout(async () => {
21+
window.clipboardText = await navigator.clipboard.readText();
22+
document.body.removeEventListener("click", _asyncCopyFn);
23+
}, 200);
24+
});
25+
document.body.addEventListener("click", _asyncCopyFn);
26+
});
27+
28+
await $('body').click();
29+
30+
await browser.pause(300);
31+
32+
// now you can read the clipboard text from the global variable
33+
const clipboardText = await browser.execute(() => window.clipboardText);
34+
console.log('Clipboard text:', clipboardText);
35+
36+
await expect(clipboardText).toBe('Hello from WebdriverIO clipboard test!')
37+
})
38+
39+
})

clipboard/example.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Clipboard Test</title>
6+
</head>
7+
<body>
8+
<button id="copyBtn">Copy Text</button>
9+
10+
<script>
11+
document.getElementById('copyBtn').addEventListener('click', async () => {
12+
const textToCopy = "Hello from WebdriverIO clipboard test!";
13+
try {
14+
await navigator.clipboard.writeText(textToCopy);
15+
} catch (err) {
16+
console.error("Failed to copy:", err);
17+
}
18+
});
19+
</script>
20+
</body>
21+
</html>

clipboard/firefox-example.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { browser, expect } from '@wdio/globals'
2+
3+
describe('Clipboard: Firefox', () => {
4+
before(() => browser.url('/example.html'))
5+
6+
it('should allow the browser to read the clipboard', async () => {
7+
const btn = await $('#copyBtn')
8+
await btn.click()
9+
10+
// now you can read the clipboard via, e.g.
11+
const clipboardText = await browser.execute(() => navigator.clipboard.readText())
12+
13+
await expect(clipboardText).toBe('Hello from WebdriverIO clipboard test!')
14+
})
15+
16+
})

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
"scripts": {
2424
"api/webdriver": "cross-env EXAMPLE_RECIPE=api wdio run ./wdio.conf.js --spec ./api/webdriver/*.js",
2525
"click": "cross-env EXAMPLE_RECIPE=click wdio run ./wdio.conf.js --spec ./click/example.js",
26+
"clipboard": "run-s clipboard:*",
27+
"clipboard:chrome": "cross-env BROWSER=chrome EXAMPLE_RECIPE=clipboard wdio run ./wdio.browserChoice.conf.js --spec ./clipboard/chrome-example.js",
28+
"clipboard:firefox": "cross-env BROWSER=firefox EXAMPLE_RECIPE=clipboard wdio run ./wdio.browserChoice.conf.js --spec ./clipboard/firefox-example.js",
2629
"component-testing": "run-s component-testing:*",
2730
"component-testing:svelte": "wdio run ./wdio.comp.conf.js --spec ./component-testing/svelte-example.js",
2831
"customMatchers": "cross-env TS_NODE_PROJECT=./customMatchers/tsconfig.json EXAMPLE_RECIPE=customMatchers wdio run ./wdio.conf.js --spec ./customMatchers/example.ts",

wdio.browserChoice.conf.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ const { FIREFOX_BINARY_PATH } = process.env
1515
const chromeOptions = {
1616
capabilities: {
1717
browserName: 'chrome',
18+
acceptInsecureCerts: true,
1819
"goog:chromeOptions": {
19-
args: process.env.CI ? ['headless', 'disable-gpu'] : ['disable-gpu'],
20+
args: process.env.CI ? ['headless', 'disable-gpu'] : [],
2021
prefs: {
2122
"download.default_directory": downloadsDir
2223
}
@@ -31,6 +32,7 @@ const firefoxOptions = {
3132
"moz:firefoxOptions": {
3233
args: process.env.CI ? ['-headless'] : [],
3334
prefs: {
35+
"dom.events.asyncClipboard.readText": true, // Allow clipboard read
3436
"browser.download.dir": downloadsDir,
3537
"browser.download.folderList": 2,
3638
"browser.download.manager.showWhenStarting": false,

0 commit comments

Comments
 (0)