@guidepup/playwright 0.16.3 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -1
- package/lib/nvdaTest.js +0 -2
- package/lib/screenReaderTest.d.ts +78 -0
- package/lib/screenReaderTest.js +138 -0
- package/lib/voiceOverTest.js +0 -3
- package/package.json +5 -3
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { nvdaTest } from "./nvdaTest";
|
|
2
2
|
export type { NVDAPlaywright } from "./nvdaTest";
|
|
3
3
|
export { screenReaderConfig } from "./screenReaderConfig";
|
|
4
|
+
export { screenReaderTest } from "./screenReaderTest";
|
|
5
|
+
export type { ScreenReaderPlaywright } from "./screenReaderTest";
|
|
4
6
|
export { voiceOverTest } from "./voiceOverTest";
|
|
5
7
|
export type { VoiceOverPlaywright } from "./voiceOverTest";
|
package/lib/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.voiceOverTest = exports.screenReaderConfig = exports.nvdaTest = void 0;
|
|
3
|
+
exports.voiceOverTest = exports.screenReaderTest = exports.screenReaderConfig = exports.nvdaTest = void 0;
|
|
4
4
|
var nvdaTest_1 = require("./nvdaTest");
|
|
5
5
|
Object.defineProperty(exports, "nvdaTest", { enumerable: true, get: function () { return nvdaTest_1.nvdaTest; } });
|
|
6
6
|
var screenReaderConfig_1 = require("./screenReaderConfig");
|
|
7
7
|
Object.defineProperty(exports, "screenReaderConfig", { enumerable: true, get: function () { return screenReaderConfig_1.screenReaderConfig; } });
|
|
8
|
+
var screenReaderTest_1 = require("./screenReaderTest");
|
|
9
|
+
Object.defineProperty(exports, "screenReaderTest", { enumerable: true, get: function () { return screenReaderTest_1.screenReaderTest; } });
|
|
8
10
|
var voiceOverTest_1 = require("./voiceOverTest");
|
|
9
11
|
Object.defineProperty(exports, "voiceOverTest", { enumerable: true, get: function () { return voiceOverTest_1.voiceOverTest; } });
|
package/lib/nvdaTest.js
CHANGED
|
@@ -59,8 +59,6 @@ exports.nvdaTest = test_1.test.extend({
|
|
|
59
59
|
if (!applicationName) {
|
|
60
60
|
throw new Error(`Browser ${browserName} is not installed.`);
|
|
61
61
|
}
|
|
62
|
-
await page.goto("about:blank", { waitUntil: "load" });
|
|
63
|
-
await page.bringToFront();
|
|
64
62
|
nvdaPlaywright.navigateToWebContent = async (clearLogs = true) => {
|
|
65
63
|
// Make sure NVDA is not in focus mode.
|
|
66
64
|
await nvdaPlaywright.perform(nvdaPlaywright.keyboardCommands.exitFocusMode);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { CommandOptions, type ScreenReader } from "@guidepup/guidepup";
|
|
2
|
+
type Prettify<T> = {
|
|
3
|
+
[K in keyof T]: T[K];
|
|
4
|
+
} & {};
|
|
5
|
+
type CaptureCommandOptions = Prettify<Pick<CommandOptions, "capture">>;
|
|
6
|
+
/**
|
|
7
|
+
* This object can be used to launch and control the default screen reader for
|
|
8
|
+
* the environment.
|
|
9
|
+
*
|
|
10
|
+
* Here's a typical example:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { screenReader } from "@guidepup/guidepup";
|
|
14
|
+
*
|
|
15
|
+
* (async () => {
|
|
16
|
+
* // Start the screen reader.
|
|
17
|
+
* await screenReader.start();
|
|
18
|
+
*
|
|
19
|
+
* // Move to the next item.
|
|
20
|
+
* await screenReader.next();
|
|
21
|
+
*
|
|
22
|
+
* // ... perform some commands.
|
|
23
|
+
*
|
|
24
|
+
* // Stop the screen reader.
|
|
25
|
+
* await screenReader.stop();
|
|
26
|
+
* })();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export interface ScreenReaderPlaywright extends ScreenReader {
|
|
30
|
+
/**
|
|
31
|
+
* Guidepup Playwright specific command that navigates the screen reader to
|
|
32
|
+
* the beginning of the browser's web content.
|
|
33
|
+
*
|
|
34
|
+
* This command should be used after page navigation.
|
|
35
|
+
*
|
|
36
|
+
* Note: this command clears all logs by default.
|
|
37
|
+
*/
|
|
38
|
+
navigateToWebContent(clearLogs?: boolean): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* These tests extend the default Playwright environment that launches the
|
|
42
|
+
* browser with a running instance of the default screen reader for the current
|
|
43
|
+
* OS.
|
|
44
|
+
*
|
|
45
|
+
* A fresh started screen reader instance `screenReader` is provided to each
|
|
46
|
+
* test.
|
|
47
|
+
*/
|
|
48
|
+
export declare const screenReaderTest: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & {
|
|
49
|
+
/**
|
|
50
|
+
* This object can be used to launch and control the default screen reader for
|
|
51
|
+
* the environment.
|
|
52
|
+
*
|
|
53
|
+
* Here's a typical example:
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { screenReader } from "@guidepup/guidepup";
|
|
57
|
+
*
|
|
58
|
+
* (async () => {
|
|
59
|
+
* // Start the screen reader.
|
|
60
|
+
* await screenReader.start();
|
|
61
|
+
*
|
|
62
|
+
* // Move to the next item.
|
|
63
|
+
* await screenReader.next();
|
|
64
|
+
*
|
|
65
|
+
* // ... perform some commands.
|
|
66
|
+
*
|
|
67
|
+
* // Stop the screen reader.
|
|
68
|
+
* await screenReader.stop();
|
|
69
|
+
* })();
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
screenReader: ScreenReaderPlaywright;
|
|
73
|
+
/**
|
|
74
|
+
* Options to start the default screen reader with.
|
|
75
|
+
*/
|
|
76
|
+
screenReaderStartOptions: CaptureCommandOptions;
|
|
77
|
+
}, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.screenReaderTest = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const guidepup_1 = require("@guidepup/guidepup");
|
|
6
|
+
const applicationNameMap_1 = require("./applicationNameMap");
|
|
7
|
+
const MAX_APPLICATION_SWITCH_RETRY_COUNT = 10;
|
|
8
|
+
const SWITCH_APPLICATION = {
|
|
9
|
+
keyCode: [guidepup_1.WindowsKeyCodes.Escape],
|
|
10
|
+
modifiers: [guidepup_1.WindowsModifiers.Alt],
|
|
11
|
+
};
|
|
12
|
+
const MOVE_TO_TOP = {
|
|
13
|
+
keyCode: [guidepup_1.WindowsKeyCodes.Home],
|
|
14
|
+
modifiers: [guidepup_1.WindowsModifiers.Control],
|
|
15
|
+
};
|
|
16
|
+
const cleanString = (str) => str
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
// REF: https://github.com/nvaccess/nvda/blob/master/source/locale/en/symbols.dic
|
|
19
|
+
.replace(/[|¦:;'"`\-‐–—·_()[\]{}\\^~]/g, " ")
|
|
20
|
+
.replace(/\s+/g, " ")
|
|
21
|
+
.trim();
|
|
22
|
+
const hasFocus = ({ applicationName, pageTitle, windowTitle, }) => {
|
|
23
|
+
const cleanedApplicationName = cleanString(applicationName);
|
|
24
|
+
const cleanedPageTitle = cleanString(pageTitle);
|
|
25
|
+
const cleanedWindowTitle = cleanString(windowTitle);
|
|
26
|
+
return ((cleanedPageTitle.length &&
|
|
27
|
+
cleanedWindowTitle.startsWith(cleanedPageTitle)) ||
|
|
28
|
+
cleanedWindowTitle.includes(cleanedApplicationName));
|
|
29
|
+
};
|
|
30
|
+
const focusBrowser = async ({ applicationName, pageTitle, }) => {
|
|
31
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.reportTitle);
|
|
32
|
+
let windowTitle = await screenReaderPlaywright.lastSpokenPhrase();
|
|
33
|
+
if (hasFocus({ applicationName, pageTitle, windowTitle })) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
let applicationSwitchRetryCount = 0;
|
|
37
|
+
while (applicationSwitchRetryCount < MAX_APPLICATION_SWITCH_RETRY_COUNT) {
|
|
38
|
+
applicationSwitchRetryCount++;
|
|
39
|
+
await screenReaderPlaywright.perform(SWITCH_APPLICATION);
|
|
40
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.reportTitle);
|
|
41
|
+
windowTitle = await screenReaderPlaywright.lastSpokenPhrase();
|
|
42
|
+
if (hasFocus({ applicationName, pageTitle, windowTitle })) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const screenReaderPlaywright = guidepup_1.screenReader;
|
|
48
|
+
/**
|
|
49
|
+
* These tests extend the default Playwright environment that launches the
|
|
50
|
+
* browser with a running instance of the default screen reader for the current
|
|
51
|
+
* OS.
|
|
52
|
+
*
|
|
53
|
+
* A fresh started screen reader instance `screenReader` is provided to each
|
|
54
|
+
* test.
|
|
55
|
+
*/
|
|
56
|
+
exports.screenReaderTest = test_1.test.extend({
|
|
57
|
+
screenReaderStartOptions: { capture: "initial" },
|
|
58
|
+
screenReader: async ({ browserName, page, screenReaderStartOptions }, use) => {
|
|
59
|
+
try {
|
|
60
|
+
const applicationName = applicationNameMap_1.applicationNameMap[browserName];
|
|
61
|
+
if (!applicationName) {
|
|
62
|
+
throw new Error(`Browser ${browserName} is not installed.`);
|
|
63
|
+
}
|
|
64
|
+
if (guidepup_1.nvda.default()) {
|
|
65
|
+
screenReaderPlaywright.navigateToWebContent = async (clearLogs = true) => {
|
|
66
|
+
// Make sure NVDA is not in focus mode.
|
|
67
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.exitFocusMode);
|
|
68
|
+
const pageTitle = await page.title();
|
|
69
|
+
// Ensure application is brought to front and focused.
|
|
70
|
+
await focusBrowser({ applicationName, pageTitle });
|
|
71
|
+
// Ensure the document is ready and focused.
|
|
72
|
+
await page.bringToFront();
|
|
73
|
+
await page.locator("body").waitFor();
|
|
74
|
+
await page.locator("body").focus();
|
|
75
|
+
await page.locator("body").click();
|
|
76
|
+
await page.locator("body").blur();
|
|
77
|
+
// NVDA appears to not work well with Firefox when switching between
|
|
78
|
+
// applications resulting in the entire browser window having NVDA focus
|
|
79
|
+
// with focus mode.
|
|
80
|
+
//
|
|
81
|
+
// One workaround is to tab to the next focusable item. From there we can
|
|
82
|
+
// toggle into (yes although we are already in it...) focus mode and back
|
|
83
|
+
// out. In case this ever transpires to not happen as expect, we then ensure
|
|
84
|
+
// we exit focus mode and move NVDA to the top of the page.
|
|
85
|
+
//
|
|
86
|
+
// REF: https://github.com/nvaccess/nvda/issues/5758
|
|
87
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.readNextFocusableItem);
|
|
88
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.toggleBetweenBrowseAndFocusMode);
|
|
89
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.toggleBetweenBrowseAndFocusMode);
|
|
90
|
+
await screenReaderPlaywright.perform(guidepup_1.NVDAKeyCodeCommands.exitFocusMode);
|
|
91
|
+
await screenReaderPlaywright.perform(MOVE_TO_TOP);
|
|
92
|
+
if (clearLogs) {
|
|
93
|
+
// Clear out logs.
|
|
94
|
+
await screenReaderPlaywright.clearItemTextLog();
|
|
95
|
+
await screenReaderPlaywright.clearSpokenPhraseLog();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
else if (guidepup_1.voiceOver.default()) {
|
|
100
|
+
screenReaderPlaywright.navigateToWebContent = async (clearLogs = true) => {
|
|
101
|
+
await (0, guidepup_1.macOSActivate)(applicationName);
|
|
102
|
+
await screenReaderPlaywright.perform({
|
|
103
|
+
keyCode: guidepup_1.MacOSKeyCodes.Control,
|
|
104
|
+
});
|
|
105
|
+
await page.bringToFront();
|
|
106
|
+
await page.locator("body").waitFor();
|
|
107
|
+
await screenReaderPlaywright.perform(guidepup_1.voiceOverKeyCodeCommands.openItemChooser);
|
|
108
|
+
await screenReaderPlaywright.type("web content");
|
|
109
|
+
await screenReaderPlaywright.perform({
|
|
110
|
+
keyCode: guidepup_1.MacOSKeyCodes.Enter,
|
|
111
|
+
});
|
|
112
|
+
await screenReaderPlaywright.interact();
|
|
113
|
+
await screenReaderPlaywright.perform(guidepup_1.voiceOverKeyCodeCommands.moveToBeginningOfText);
|
|
114
|
+
await screenReaderPlaywright.perform({
|
|
115
|
+
keyCode: guidepup_1.MacOSKeyCodes.Control,
|
|
116
|
+
});
|
|
117
|
+
if (clearLogs) {
|
|
118
|
+
await screenReaderPlaywright.clearItemTextLog();
|
|
119
|
+
await screenReaderPlaywright.clearSpokenPhraseLog();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
throw new Error("No supported screen reader");
|
|
125
|
+
}
|
|
126
|
+
await screenReaderPlaywright.start(screenReaderStartOptions);
|
|
127
|
+
await use(screenReaderPlaywright);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
try {
|
|
131
|
+
await screenReaderPlaywright.stop();
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// swallow stop failure
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
});
|
package/lib/voiceOverTest.js
CHANGED
|
@@ -47,9 +47,6 @@ exports.voiceOverTest = test_1.test.extend({
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
await voiceOverPlaywright.start(voiceOverStartOptions);
|
|
50
|
-
await (0, guidepup_1.macOSActivate)(applicationName);
|
|
51
|
-
// Cancel auto navigation
|
|
52
|
-
await voiceOverPlaywright.perform({ keyCode: guidepup_1.MacOSKeyCodes.Control }, { capture: false });
|
|
53
50
|
await use(voiceOverPlaywright);
|
|
54
51
|
}
|
|
55
52
|
finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guidepup/playwright",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Screen reader automation library for Playwright testing. ",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -34,15 +34,17 @@
|
|
|
34
34
|
"prepublish": "yarn build",
|
|
35
35
|
"pretest": "npx playwright install chromium firefox webkit",
|
|
36
36
|
"test:nvda": "yarn test:nvda:chromium && yarn test:nvda:firefox",
|
|
37
|
+
"test:screenreader": "yarn test:screenreader:chromium",
|
|
37
38
|
"test:voiceover": "yarn test:voiceover:chromium && yarn test:voiceover:firefox && yarn test:voiceover:webkit",
|
|
38
39
|
"test:nvda:chromium": "playwright test --config ./examples/playwright-nvda/chromium.config.ts ./examples/playwright-nvda/tests/chromium/",
|
|
39
40
|
"test:nvda:firefox": "playwright test --config ./examples/playwright-nvda/firefox.config.ts ./examples/playwright-nvda/tests/firefox/",
|
|
41
|
+
"test:screenreader:chromium": "playwright test --config ./examples/playwright-screenreader/chromium.config.ts ./examples/playwright-screenreader/tests/chromium/",
|
|
40
42
|
"test:voiceover:chromium": "playwright test --config ./examples/playwright-voiceover/chromium.config.ts ./examples/playwright-voiceover/tests/chromium/",
|
|
41
43
|
"test:voiceover:firefox": "playwright test --config ./examples/playwright-voiceover/firefox.config.ts ./examples/playwright-voiceover/tests/firefox/",
|
|
42
44
|
"test:voiceover:webkit": "playwright test --config ./examples/playwright-voiceover/webkit.config.ts ./examples/playwright-voiceover/tests/webkit/"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
|
-
"@guidepup/guidepup": "^0.
|
|
47
|
+
"@guidepup/guidepup": "^0.27.0",
|
|
46
48
|
"@guidepup/record": "^0.1.0",
|
|
47
49
|
"@playwright/test": "^1.60.0",
|
|
48
50
|
"@types/node": "^24.10.1",
|
|
@@ -56,7 +58,7 @@
|
|
|
56
58
|
"typescript": "^5.9.3"
|
|
57
59
|
},
|
|
58
60
|
"peerDependencies": {
|
|
59
|
-
"@guidepup/guidepup": ">=0.
|
|
61
|
+
"@guidepup/guidepup": ">=0.27.0",
|
|
60
62
|
"@playwright/test": "^1.57.0"
|
|
61
63
|
},
|
|
62
64
|
"resolutions": {
|