diff --git a/test/e2e/console/console-log_test.ts b/test/e2e/console/console-log_test.ts index a45c09df90..c0d4eb587d 100644 --- a/test/e2e/console/console-log_test.ts +++ b/test/e2e/console/console-log_test.ts @@ -4,9 +4,9 @@ import {assert} from 'chai'; -import {getBrowserAndPages, waitForFunction} from '../../shared/helper.js'; +import {activeElement, activeElementAccessibleName, activeElementTextContent, getBrowserAndPages, tabBackward, tabForward, waitForFunction} from '../../shared/helper.js'; import {describe, it} from '../../shared/mocha-extensions.js'; -import {getStructuredConsoleMessages, navigateToConsoleTab, showVerboseMessages} from '../helpers/console-helpers.js'; +import {focusConsolePrompt, getConsoleMessages, getStructuredConsoleMessages, navigateToConsoleTab, showVerboseMessages, waitForLastConsoleMessageToHaveContent} from '../helpers/console-helpers.js'; /* eslint-disable no-console */ @@ -238,4 +238,67 @@ describe('The Console Tab', async () => { assert.deepEqual(actualMessages, test.expectedMessages, 'Console message does not match the expected message'); }); } + + describe('keyboard navigation', () => { + it('can navigate between individual messages', async () => { + const {frontend} = getBrowserAndPages(); + await getConsoleMessages('focus-interaction'); + await focusConsolePrompt(); + + await tabBackward(); + assert.strictEqual(await activeElementTextContent(), 'focus-interaction.html:9'); + + await frontend.keyboard.press('ArrowUp'); + assert.strictEqual(await activeElementTextContent(), 'focus-interaction.html:9 Third message'); + + await frontend.keyboard.press('ArrowUp'); + assert.strictEqual(await activeElementTextContent(), 'focus-interaction.html:8'); + + await frontend.keyboard.press('ArrowDown'); + assert.strictEqual(await activeElementTextContent(), 'focus-interaction.html:9 Third message'); + + await tabBackward(); // Focus should now be on the console settings, e.g. out of the list of console messages + assert.strictEqual(await activeElementAccessibleName(), 'Console settings'); + + await tabForward(); // Focus is now back to the list, selecting the last message source URL + assert.strictEqual(await activeElementTextContent(), 'focus-interaction.html:9'); + + await tabForward(); + assert.strictEqual(await activeElementAccessibleName(), 'Console prompt'); + }); + + it('should not lose focus on prompt when logging and scrolling', async () => { + const {target, frontend} = getBrowserAndPages(); + + await getConsoleMessages('focus-interaction'); + await focusConsolePrompt(); + + await target.evaluate(() => { + console.log('New message'); + }); + await waitForLastConsoleMessageToHaveContent('New message'); + assert.strictEqual(await activeElementAccessibleName(), 'Console prompt'); + + await target.evaluate(() => { + for (let i = 0; i < 100; i++) { + console.log(`Message ${i}`); + } + }); + await waitForLastConsoleMessageToHaveContent('Message 99'); + assert.strictEqual(await activeElementAccessibleName(), 'Console prompt'); + + const consolePrompt = await activeElement(); + const wrappingBox = await consolePrompt.boundingBox(); + if (!wrappingBox) { + throw new Error('Can\'t compute bounding box of console prompt.'); + } + + // +20 to move from the top left point so we are definitely scrolling + // within the container + await frontend.mouse.move(wrappingBox.x + 20, wrappingBox.y + 5); + await frontend.mouse.wheel({deltaY: -500}); + + assert.strictEqual(await activeElementAccessibleName(), 'Console prompt'); + }); + }); }); diff --git a/test/e2e/emulation/custom-ua-ch_test.ts b/test/e2e/emulation/custom-ua-ch_test.ts index efc6bd42a4..e9d2298b0e 100644 --- a/test/e2e/emulation/custom-ua-ch_test.ts +++ b/test/e2e/emulation/custom-ua-ch_test.ts @@ -4,7 +4,7 @@ import {assert} from 'chai'; import type * as puppeteer from 'puppeteer'; -import {click, getBrowserAndPages, goToResource, pressKey, typeText, waitFor} from '../../shared/helper.js'; +import {click, getBrowserAndPages, goToResource, pressKey, typeText, waitFor, tabForward} from '../../shared/helper.js'; import {describe, it} from '../../shared/mocha-extensions.js'; import {waitForDomNodeToBeVisible} from '../helpers/elements-helpers.js'; import {openDeviceToolbar, reloadDockableFrontEnd, selectEdit, selectTestDevice} from '../helpers/emulation-helpers.js'; @@ -26,11 +26,6 @@ async function targetTextContent(selector: string): Promise { return elementTextContent(handle); } -export const tabForwardFrontend = async () => { - const {frontend} = getBrowserAndPages(); - await frontend.keyboard.press('Tab'); -}; - describe('Custom UA-CH emulation', async () => { beforeEach(async function() { await reloadDockableFrontEnd(); @@ -46,51 +41,51 @@ describe('Custom UA-CH emulation', async () => { await waitFor(FOCUSED_DEVICE_NAME_FIELD_SELECTOR); await typeText('Test device'); - await tabForwardFrontend(); // Focus width. - await tabForwardFrontend(); // Focus height. - await tabForwardFrontend(); // Focus DPR. + await tabForward(); // Focus width. + await tabForward(); // Focus height. + await tabForward(); // Focus DPR. await typeText('1.0'); - await tabForwardFrontend(); // Focus UA string. + await tabForward(); // Focus UA string. await typeText('Test device browser 1.0'); - await tabForwardFrontend(); // Focus device type. - await tabForwardFrontend(); // Focus folder. + await tabForward(); // Focus device type. + await tabForward(); // Focus folder. await pressKey('Space'); - await tabForwardFrontend(); // Focus help button - await tabForwardFrontend(); // Focus brand browser. + await tabForward(); // Focus help button + await tabForward(); // Focus brand browser. await typeText('Test browser'); - await tabForwardFrontend(); // Focus brand version. + await tabForward(); // Focus brand version. await typeText('1.0'); - await tabForwardFrontend(); // Focus delete button. - await tabForwardFrontend(); // Focus Add brand button. + await tabForward(); // Focus delete button. + await tabForward(); // Focus Add brand button. await pressKey('Space'); await typeText('Friendly Dragon'); - await tabForwardFrontend(); // Focus second row brand version. + await tabForward(); // Focus second row brand version. await typeText('1.1'); - await tabForwardFrontend(); // Focus second row delete button. - await tabForwardFrontend(); // Focus Add browser button. - await tabForwardFrontend(); // Focus full version. + await tabForward(); // Focus second row delete button. + await tabForward(); // Focus Add browser button. + await tabForward(); // Focus full version. await typeText('1.1.2345'); - await tabForwardFrontend(); // Focus platform. + await tabForward(); // Focus platform. await typeText('Cyborg'); - await tabForwardFrontend(); // Focus platform version. + await tabForward(); // Focus platform version. await typeText('C-1'); - await tabForwardFrontend(); // Focus architecture. + await tabForward(); // Focus architecture. await typeText('Bipedal'); - await tabForwardFrontend(); // Focus device model. + await tabForward(); // Focus device model. await typeText('C-1-Gardener'); - await tabForwardFrontend(); // Focus add button. + await tabForward(); // Focus add button. const finishAdd = await waitFor(FOCUSED_SELECTOR); const finishAddText = await elementTextContent(finishAdd); @@ -134,7 +129,7 @@ describe('Custom UA-CH emulation', async () => { if (i === 7) { await pressKey('ArrowRight'); } - await tabForwardFrontend(); + await tabForward(); } // Change the value. diff --git a/test/e2e/helpers/console-helpers.ts b/test/e2e/helpers/console-helpers.ts index e847b283c5..0f301661d0 100644 --- a/test/e2e/helpers/console-helpers.ts +++ b/test/e2e/helpers/console-helpers.ts @@ -55,6 +55,17 @@ export async function waitForConsoleMessagesToBeNonEmpty(numberOfMessages: numbe }); } +export async function waitForLastConsoleMessageToHaveContent(expectedTextContent: string) { + await waitForFunction(async () => { + const messages = await $$(CONSOLE_FIRST_MESSAGES_SELECTOR); + if (messages.length === 0) { + return false; + } + const lastMessageContent = await messages[messages.length - 1].evaluate(message => message.textContent); + return lastMessageContent === expectedTextContent; + }); +} + export async function getConsoleMessages(testName: string, withAnchor = false, callback?: () => Promise) { // Ensure Console is loaded before the page is loaded to avoid a race condition. await getCurrentConsoleMessages(); diff --git a/test/e2e/network/network-conditions_test.ts b/test/e2e/network/network-conditions_test.ts index ed714bba68..049f710941 100644 --- a/test/e2e/network/network-conditions_test.ts +++ b/test/e2e/network/network-conditions_test.ts @@ -4,7 +4,7 @@ import {assert} from 'chai'; import type {ElementHandle, Page} from 'puppeteer'; -import {getBrowserAndPages, pressKey, typeText, waitFor, waitForAria} from '../../shared/helper.js'; +import {getBrowserAndPages, pressKey, typeText, waitFor, waitForAria, tabForward} from '../../shared/helper.js'; import {describe, it} from '../../shared/mocha-extensions.js'; import {navigateToNetworkTab} from '../helpers/network-helpers.js'; import type * as Protocol from '../../../front_end/generated/protocol.js'; @@ -56,11 +56,6 @@ describe('The Network Tab', async function() { return await target.evaluate(getUserAgentMetaDataStr); } - async function tabForwardFrontend() { - const {frontend} = getBrowserAndPages(); - await frontend.keyboard.press('Tab'); - } - it('can change accepted content encodings', async () => { const section = await openNetworkConditions('.network-config-accepted-encoding'); const autoCheckbox = await waitForAria('Use browser default', section); @@ -219,42 +214,42 @@ describe('The Network Tab', async function() { const userAgent = await waitForAria('Enter a custom user agent'); await userAgent.click(); await userAgent.type('Test User Agent String'); - await tabForwardFrontend(); // focus help button + await tabForward(); // focus help button await pressKey('Space'); // open client hints section - await tabForwardFrontend(); // focus help link - await tabForwardFrontend(); // focus brand name + await tabForward(); // focus help link + await tabForward(); // focus brand name await typeText('Test Brand 1'); - await tabForwardFrontend(); // focus brand version + await tabForward(); // focus brand version await typeText('99'); - await tabForwardFrontend(); // focus delete brand button - await tabForwardFrontend(); // focus add brand button + await tabForward(); // focus delete brand button + await tabForward(); // focus add brand button await pressKey('Enter'); // add a second brand await typeText('Test Brand 2'); - await tabForwardFrontend(); // focus brand version + await tabForward(); // focus brand version await typeText('100'); - await tabForwardFrontend(); // focus delete brand button - await tabForwardFrontend(); // focus add brand button + await tabForward(); // focus delete brand button + await tabForward(); // focus add brand button await pressKey('Enter'); // add a third brand await typeText('Test Brand 3'); - await tabForwardFrontend(); // focus brand version + await tabForward(); // focus brand version await typeText('101'); - await tabForwardFrontend(); // focus delete brand button - await tabForwardFrontend(); // focus add brand button - await tabForwardFrontend(); // focus browser full version + await tabForward(); // focus delete brand button + await tabForward(); // focus add brand button + await tabForward(); // focus browser full version await typeText('99.99'); - await tabForwardFrontend(); // focus platform name + await tabForward(); // focus platform name await typeText('Test Platform'); - await tabForwardFrontend(); // focus platform version + await tabForward(); // focus platform version await typeText('10'); - await tabForwardFrontend(); // focus architecture + await tabForward(); // focus architecture await typeText('Test Architecture'); - await tabForwardFrontend(); // focus device model + await tabForward(); // focus device model await typeText('Test Model'); - await tabForwardFrontend(); // focus mobile checkbox + await tabForward(); // focus mobile checkbox await pressKey('Space'); - await tabForwardFrontend(); // focus update button + await tabForward(); // focus update button await pressKey('Enter'); const userAgentMetadata = await getUserAgentMetadataFromTarget(target); assert.deepEqual(userAgentMetadata, { @@ -274,8 +269,8 @@ describe('The Network Tab', async function() { // Delete a brand const brand = await waitForAria('Brand 1', section); // move focus back to first brand await brand.click(); - await tabForwardFrontend(); // focus brand version - await tabForwardFrontend(); // focus delete brand button + await tabForward(); // focus brand version + await tabForward(); // focus delete brand button await pressKey('Enter'); // Edit a value @@ -284,10 +279,10 @@ describe('The Network Tab', async function() { await typeText('11'); // Update - await tabForwardFrontend(); // focus architecture - await tabForwardFrontend(); // focus device model - await tabForwardFrontend(); // focus mobile checkbox - await tabForwardFrontend(); // focus update button + await tabForward(); // focus architecture + await tabForward(); // focus device model + await tabForward(); // focus mobile checkbox + await tabForward(); // focus update button await pressKey('Enter'); const updatedUserAgentMetadata = await getUserAgentMetadataFromTarget(target); assert.deepEqual(updatedUserAgentMetadata, { diff --git a/test/e2e/resources/console/BUILD.gn b/test/e2e/resources/console/BUILD.gn index c6d6e9bb62..4d522cc966 100644 --- a/test/e2e/resources/console/BUILD.gn +++ b/test/e2e/resources/console/BUILD.gn @@ -16,6 +16,7 @@ copy_to_gen("console") { "dom-interactions.html", "error-with-async-frame.html", "escaping.html", + "focus-interaction.html", "ignoreMe.js", "log-source.js", "navigation/after-navigation.html", diff --git a/test/e2e/resources/console/focus-interaction.html b/test/e2e/resources/console/focus-interaction.html new file mode 100644 index 0000000000..1d77c9abd9 --- /dev/null +++ b/test/e2e/resources/console/focus-interaction.html @@ -0,0 +1,10 @@ + + diff --git a/test/shared/helper.ts b/test/shared/helper.ts index 6db69a080c..04d051bfee 100644 --- a/test/shared/helper.ts +++ b/test/shared/helper.ts @@ -401,9 +401,9 @@ export const step = async (description: string, step: Function) => { }; export const waitForAnimationFrame = async () => { - const {target} = getBrowserAndPages(); + const {frontend} = getBrowserAndPages(); - await target.waitForFunction(() => { + await frontend.waitForFunction(() => { return new Promise(resolve => { requestAnimationFrame(resolve); }); @@ -411,11 +411,11 @@ export const waitForAnimationFrame = async () => { }; export const activeElement = async(): Promise => { - const {target} = getBrowserAndPages(); + const {frontend} = getBrowserAndPages(); await waitForAnimationFrame(); - return target.evaluateHandle(() => { + return frontend.evaluateHandle(() => { let activeElement = document.activeElement; while (activeElement && activeElement.shadowRoot) { @@ -431,18 +431,35 @@ export const activeElementTextContent = async () => { return element.evaluate(node => node.textContent); }; -export const tabForward = async () => { - const {target} = getBrowserAndPages(); - - await target.keyboard.press('Tab'); +export const activeElementAccessibleName = async () => { + const element = await activeElement(); + return element.evaluate(node => node.getAttribute('aria-label')); }; -export const tabBackward = async () => { - const {target} = getBrowserAndPages(); +export const tabForward = async (page?: puppeteer.Page) => { + let targetPage: puppeteer.Page; + if (page) { + targetPage = page; + } else { + const {frontend} = getBrowserAndPages(); + targetPage = frontend; + } - await target.keyboard.down('Shift'); - await target.keyboard.press('Tab'); - await target.keyboard.up('Shift'); + await targetPage.keyboard.press('Tab'); +}; + +export const tabBackward = async (page?: puppeteer.Page) => { + let targetPage: puppeteer.Page; + if (page) { + targetPage = page; + } else { + const {frontend} = getBrowserAndPages(); + targetPage = frontend; + } + + await targetPage.keyboard.down('Shift'); + await targetPage.keyboard.press('Tab'); + await targetPage.keyboard.up('Shift'); }; export const selectTextFromNodeToNode = async (