From 83fe8f4d0e8a4d1bc8194d88c771b7f333f23c7b Mon Sep 17 00:00:00 2001 From: Filype Pereira Date: Fri, 26 Sep 2025 21:33:58 +1200 Subject: [PATCH 1/3] New example of using clipboard --- .github/workflows/test.yml | 1 + clipboard/README.md | 20 ++++++++++++++++++++ clipboard/chrome-example.js | 19 +++++++++++++++++++ clipboard/example.html | 23 +++++++++++++++++++++++ clipboard/firefox-example.js | 16 ++++++++++++++++ package.json | 3 +++ wdio.browserChoice.conf.js | 1 + 7 files changed, 83 insertions(+) create mode 100644 clipboard/README.md create mode 100644 clipboard/chrome-example.js create mode 100644 clipboard/example.html create mode 100644 clipboard/firefox-example.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8b05238..30f178e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,7 @@ jobs: matrix: exampleDir: - click + - clipboard - customMatchers - deleteCookies - emulate diff --git a/clipboard/README.md b/clipboard/README.md new file mode 100644 index 0000000..3f61bbd --- /dev/null +++ b/clipboard/README.md @@ -0,0 +1,20 @@ +# `clipboard` Example + +This directory contains the example files for interacting with the system clipboard using +WebDriverIO. + +## Prerequisite + +Make sure to run this first, to set up the example repository: + +```sh +npm install +``` + +## Example + +Run example via: + +```sh +npm run clipboard +``` diff --git a/clipboard/chrome-example.js b/clipboard/chrome-example.js new file mode 100644 index 0000000..d8c4f87 --- /dev/null +++ b/clipboard/chrome-example.js @@ -0,0 +1,19 @@ +import { browser, expect } from '@wdio/globals' + +describe('Clipboard: Chrome', () => { + before(() => browser.url('/example.html')) + + it('should allow the browser to read the clipboard', async () => { + // set clipboard permissions + await browser.setPermissions({ name: 'clipboard-read' }, 'granted') + + const btn = await $('#copyBtn') + await btn.click() + + // now you can read the clipboard via, e.g. + const clipboardText = await browser.execute(() => navigator.clipboard.readText()) + + await expect(clipboardText).toBe('Hello from WebdriverIO clipboard test!') + }) + +}) diff --git a/clipboard/example.html b/clipboard/example.html new file mode 100644 index 0000000..e971021 --- /dev/null +++ b/clipboard/example.html @@ -0,0 +1,23 @@ + + + + + Clipboard Test + + + + + + + diff --git a/clipboard/firefox-example.js b/clipboard/firefox-example.js new file mode 100644 index 0000000..ea289d7 --- /dev/null +++ b/clipboard/firefox-example.js @@ -0,0 +1,16 @@ +import { browser, expect } from '@wdio/globals' + +describe('Clipboard: Firefox', () => { + before(() => browser.url('/example.html')) + + it('should allow the browser to read the clipboard', async () => { + const btn = await $('#copyBtn') + await btn.click() + + // now you can read the clipboard via, e.g. + const clipboardText = await browser.execute(() => navigator.clipboard.readText()) + + await expect(clipboardText).toBe('Hello from WebdriverIO clipboard test!') + }) + +}) diff --git a/package.json b/package.json index 8c1eb9b..354a5a5 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "scripts": { "api/webdriver": "cross-env EXAMPLE_RECIPE=api wdio run ./wdio.conf.js --spec ./api/webdriver/*.js", "click": "cross-env EXAMPLE_RECIPE=click wdio run ./wdio.conf.js --spec ./click/example.js", + "clipboard": "run-s clipboard:*", + "clipboard:chrome": "cross-env BROWSER=chrome EXAMPLE_RECIPE=clipboard wdio run ./wdio.browserChoice.conf.js --spec ./clipboard/chrome-example.js", + "clipboard:firefox": "cross-env BROWSER=firefox EXAMPLE_RECIPE=clipboard wdio run ./wdio.browserChoice.conf.js --spec ./clipboard/firefox-example.js", "component-testing": "run-s component-testing:*", "component-testing:svelte": "wdio run ./wdio.comp.conf.js --spec ./component-testing/svelte-example.js", "customMatchers": "cross-env TS_NODE_PROJECT=./customMatchers/tsconfig.json EXAMPLE_RECIPE=customMatchers wdio run ./wdio.conf.js --spec ./customMatchers/example.ts", diff --git a/wdio.browserChoice.conf.js b/wdio.browserChoice.conf.js index 868c190..ded4e08 100644 --- a/wdio.browserChoice.conf.js +++ b/wdio.browserChoice.conf.js @@ -31,6 +31,7 @@ const firefoxOptions = { "moz:firefoxOptions": { args: process.env.CI ? ['-headless'] : [], prefs: { + "dom.events.asyncClipboard.readText": true, // Allow clipboard read "browser.download.dir": downloadsDir, "browser.download.folderList": 2, "browser.download.manager.showWhenStarting": false, From 75e51a0c07848f5825ef9b8176065184dcd65ed9 Mon Sep 17 00:00:00 2001 From: Filype Pereira Date: Fri, 26 Sep 2025 22:48:50 +1200 Subject: [PATCH 2/3] Fix for NotAllowedError: Document is not focused --- clipboard/chrome-example.js | 26 +++++++++++++++++++++++--- clipboard/example.html | 2 -- wdio.browserChoice.conf.js | 3 ++- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/clipboard/chrome-example.js b/clipboard/chrome-example.js index d8c4f87..6a6dec2 100644 --- a/clipboard/chrome-example.js +++ b/clipboard/chrome-example.js @@ -1,4 +1,4 @@ -import { browser, expect } from '@wdio/globals' +import { browser, expect, $ } from '@wdio/globals' describe('Clipboard: Chrome', () => { before(() => browser.url('/example.html')) @@ -10,8 +10,28 @@ describe('Clipboard: Chrome', () => { const btn = await $('#copyBtn') await btn.click() - // now you can read the clipboard via, e.g. - const clipboardText = await browser.execute(() => navigator.clipboard.readText()) + // Use a focus event to trigger the async clipboard read, then save + // the result to a global variable on the window object + // Without this the clipboard read may be blocked + // with "NotAllowedError: Document is not focused." + // See: https://stackoverflow.com/questions/56306153/domexception-on-calling-navigator-clipboard-readtext + await browser.execute(() => { + const _asyncCopyFn = (async () => { + setTimeout(async () => { + window.clipboardText = await navigator.clipboard.readText(); + document.body.removeEventListener("click", _asyncCopyFn); + }, 200); + }); + document.body.addEventListener("click", _asyncCopyFn); + }); + + await $('body').click(); + + await browser.pause(300); + + // now you can read the clipboard text from the global variable + const clipboardText = await browser.execute(() => window.clipboardText); + console.log('Clipboard text:', clipboardText); await expect(clipboardText).toBe('Hello from WebdriverIO clipboard test!') }) diff --git a/clipboard/example.html b/clipboard/example.html index e971021..17e19e7 100644 --- a/clipboard/example.html +++ b/clipboard/example.html @@ -12,10 +12,8 @@ const textToCopy = "Hello from WebdriverIO clipboard test!"; try { await navigator.clipboard.writeText(textToCopy); - alert("Copied to clipboard: " + textToCopy); } catch (err) { console.error("Failed to copy:", err); - alert("Clipboard copy failed. Check browser permissions."); } }); diff --git a/wdio.browserChoice.conf.js b/wdio.browserChoice.conf.js index ded4e08..80367dd 100644 --- a/wdio.browserChoice.conf.js +++ b/wdio.browserChoice.conf.js @@ -15,8 +15,9 @@ const { FIREFOX_BINARY_PATH } = process.env const chromeOptions = { capabilities: { browserName: 'chrome', + acceptInsecureCerts: true, "goog:chromeOptions": { - args: process.env.CI ? ['headless', 'disable-gpu'] : ['disable-gpu'], + args: process.env.CI ? ['headless', 'disable-gpu'] : [], prefs: { "download.default_directory": downloadsDir } From e238ee583b2df2041386a9651ff38656f37d4b9f Mon Sep 17 00:00:00 2001 From: Filype Pereira Date: Fri, 26 Sep 2025 23:05:57 +1200 Subject: [PATCH 3/3] trigger build --ci