diff --git a/src/screenReaderTest.ts b/src/screenReaderTest.ts index 2c24abd..b8f8229 100644 --- a/src/screenReaderTest.ts +++ b/src/screenReaderTest.ts @@ -130,6 +130,91 @@ export interface ScreenReaderPlaywright extends ScreenReader { navigateToWebContent(options?: CaptureCommandOptions): Promise; } +const closeMenus = async ({ + screenReaderPlaywright, +}: { + screenReaderPlaywright: ScreenReaderPlaywright; +}) => { + await screenReaderPlaywright.perform( + { keyCode: MacOSKeyCodes.Escape }, + { capture: false }, + ); +}; + +const cancelCurrentInteraction = async ({ + screenReaderPlaywright, +}: { + screenReaderPlaywright: ScreenReaderPlaywright; +}) => { + await screenReaderPlaywright.perform( + { keyCode: MacOSKeyCodes.Control }, + { capture: false }, + ); +}; + +const openItemChooser = async ({ + screenReaderPlaywright, +}: { + screenReaderPlaywright: ScreenReaderPlaywright; +}) => { + let lastSpokenPhrase = ""; + + while (!lastSpokenPhrase.toLowerCase().includes("item chooser")) { + await cancelCurrentInteraction({ screenReaderPlaywright }); + await delay(100); + await closeMenus({ screenReaderPlaywright }); + await delay(100); + + await screenReaderPlaywright.perform( + voiceOverKeyCodeCommands.openItemChooser, + { capture: true }, + ); + + lastSpokenPhrase = await screenReaderPlaywright.lastSpokenPhrase(); + } +}; + +async function selectWebContentItem({ + screenReaderPlaywright, +}: { + screenReaderPlaywright: ScreenReaderPlaywright; +}) { + // eslint-disable-next-line no-constant-condition + while (true) { + let matched = false; + + for (const character of "web content") { + await cancelCurrentInteraction({ screenReaderPlaywright }); + await delay(100); + + await screenReaderPlaywright.type(character, { capture: "initial" }); + const lastSpokenPhrase = await screenReaderPlaywright.lastSpokenPhrase(); + + if (lastSpokenPhrase.toLowerCase().includes("web content")) { + matched = true; + + break; + } + } + + if (matched) { + break; + } + + // Clear the entire Item Chooser search. + await screenReaderPlaywright.perform( + { keyCode: MacOSKeyCodes.Backspace }, + { capture: false }, + ); + await delay(100); + } + + await screenReaderPlaywright.perform( + { keyCode: MacOSKeyCodes.Enter }, + { capture: false }, + ); +} + const screenReaderPlaywright: ScreenReaderPlaywright = screenReader as ScreenReaderPlaywright; @@ -261,14 +346,18 @@ export const screenReaderTest = test.extend<{ screenReaderPlaywright.navigateToWebContent = async ({ capture, } = {}) => { + const currentSpokenPhraseLog = [ + ...(await screenReaderPlaywright.spokenPhraseLog()), + ]; + const currentItemTextLog = [ + ...(await screenReaderPlaywright.itemTextLog()), + ]; + // Ensure application is brought to front and focused. await macOSActivate(applicationName); // Cancel automatic behaviours/previous commands. - await screenReaderPlaywright.perform( - { keyCode: MacOSKeyCodes.Control }, - { capture: false }, - ); + await cancelCurrentInteraction({ screenReaderPlaywright }); await delay(100); // Ensure the document is ready and focused. @@ -301,31 +390,24 @@ export const screenReaderTest = test.extend<{ document.body.prepend(marker); }); - // Open the web item chooser. - await screenReaderPlaywright.perform( - voiceOverKeyCodeCommands.openItemChooser, - { capture: false }, - ); - await delay(500); - - // Filter by "web content" - currently web content items for all browsers - // are suffixed by "web content". - for (const character of "web content") { - await screenReaderPlaywright.type(character, { capture: false }); - await delay(100); - } - - // Select the web content window spot. - await screenReaderPlaywright.perform( - { keyCode: MacOSKeyCodes.Enter }, - { capture: false }, - ); - await delay(100); + // Open item chooser and select web content. + await openItemChooser({ screenReaderPlaywright }); + await selectWebContentItem({ screenReaderPlaywright }); // Navigate into web content. await screenReaderPlaywright.interact({ capture: false }); await delay(100); + await screenReaderPlaywright.clearSpokenPhraseLog(); + await screenReaderPlaywright.clearItemTextLog(); + + const spokenPhraseLog = + await screenReaderPlaywright.spokenPhraseLog(); + const itemTextLog = await screenReaderPlaywright.itemTextLog(); + + spokenPhraseLog.push(...currentSpokenPhraseLog); + itemTextLog.push(...currentItemTextLog); + // Navigate to the first element of the page using the provided // capture settings. await screenReaderPlaywright.next({ capture }); diff --git a/src/voiceOverTest.ts b/src/voiceOverTest.ts index 727ba95..f8123e5 100644 --- a/src/voiceOverTest.ts +++ b/src/voiceOverTest.ts @@ -44,6 +44,91 @@ export interface VoiceOverPlaywright extends VoiceOver { ): Promise; } +const closeMenus = async ({ + voiceOverPlaywright, +}: { + voiceOverPlaywright: VoiceOverPlaywright; +}) => { + await voiceOverPlaywright.perform( + { keyCode: MacOSKeyCodes.Escape }, + { capture: false }, + ); +}; + +const cancelCurrentInteraction = async ({ + voiceOverPlaywright, +}: { + voiceOverPlaywright: VoiceOverPlaywright; +}) => { + await voiceOverPlaywright.perform( + { keyCode: MacOSKeyCodes.Control }, + { capture: false }, + ); +}; + +const openItemChooser = async ({ + voiceOverPlaywright, +}: { + voiceOverPlaywright: VoiceOverPlaywright; +}) => { + let lastSpokenPhrase = ""; + + while (!lastSpokenPhrase.toLowerCase().includes("item chooser")) { + await cancelCurrentInteraction({ voiceOverPlaywright }); + await delay(100); + await closeMenus({ voiceOverPlaywright }); + await delay(100); + + await voiceOverPlaywright.perform( + voiceOverPlaywright.keyboardCommands.openItemChooser, + { capture: true }, + ); + + lastSpokenPhrase = await voiceOverPlaywright.lastSpokenPhrase(); + } +}; + +async function selectWebContentItem({ + voiceOverPlaywright, +}: { + voiceOverPlaywright: VoiceOverPlaywright; +}) { + // eslint-disable-next-line no-constant-condition + while (true) { + let matched = false; + + for (const character of "web content") { + await cancelCurrentInteraction({ voiceOverPlaywright }); + await delay(100); + + await voiceOverPlaywright.type(character, { capture: "initial" }); + const lastSpokenPhrase = await voiceOverPlaywright.lastSpokenPhrase(); + + if (lastSpokenPhrase.toLowerCase().includes("web content")) { + matched = true; + + break; + } + } + + if (matched) { + break; + } + + // Clear the entire Item Chooser search. + await voiceOverPlaywright.perform( + { keyCode: MacOSKeyCodes.Backspace }, + { capture: false }, + ); + await delay(100); + } + + await voiceOverPlaywright.perform( + { keyCode: MacOSKeyCodes.Enter }, + { capture: false }, + ); +} + const voiceOverPlaywright: VoiceOverPlaywright = voiceOver as VoiceOverPlaywright; @@ -96,14 +181,18 @@ export const voiceOverTest = test.extend<{ } voiceOverPlaywright.navigateToWebContent = async ({ capture } = {}) => { + const currentSpokenPhraseLog = [ + ...(await voiceOverPlaywright.spokenPhraseLog()), + ]; + const currentItemTextLog = [ + ...(await voiceOverPlaywright.itemTextLog()), + ]; + // Ensure application is brought to front and focused. await macOSActivate(applicationName); // Cancel automatic behaviours/previous commands. - await voiceOverPlaywright.perform( - { keyCode: MacOSKeyCodes.Control }, - { capture: false }, - ); + await cancelCurrentInteraction({ voiceOverPlaywright }); await delay(100); // Ensure the document is ready and focused. @@ -136,31 +225,23 @@ export const voiceOverTest = test.extend<{ document.body.prepend(marker); }); - // Open the web item chooser. - await voiceOverPlaywright.perform( - voiceOverPlaywright.keyboardCommands.openItemChooser, - { capture: false }, - ); - await delay(500); - - // Filter by "web content" - currently web content items for all browsers - // are suffixed by "web content". - for (const character of "web content") { - await voiceOverPlaywright.type(character, { capture: false }); - await delay(100); - } - - // Select the web content window spot. - await voiceOverPlaywright.perform( - { keyCode: MacOSKeyCodes.Enter }, - { capture: false }, - ); - await delay(100); + // Open item chooser and select web content. + await openItemChooser({ voiceOverPlaywright }); + await selectWebContentItem({ voiceOverPlaywright }); // Navigate into web content. await voiceOverPlaywright.interact({ capture: false }); await delay(100); + await voiceOverPlaywright.clearSpokenPhraseLog(); + await voiceOverPlaywright.clearItemTextLog(); + + const spokenPhraseLog = await voiceOverPlaywright.spokenPhraseLog(); + const itemTextLog = await voiceOverPlaywright.itemTextLog(); + + spokenPhraseLog.push(...currentSpokenPhraseLog); + itemTextLog.push(...currentItemTextLog); + // Navigate to the first element of the page using the provided // capture settings. await voiceOverPlaywright.next({ capture });