From b8e03ca5efc2fb7d20d4fbcfe17031c168b7d399 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Thu, 27 Jun 2024 21:08:45 +0200 Subject: [PATCH] fix: flaky hotkey spec (#55345) --- e2e/hotkeys.spec.ts | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/e2e/hotkeys.spec.ts b/e2e/hotkeys.spec.ts index 306a1658be4..3d850d48fb1 100644 --- a/e2e/hotkeys.spec.ts +++ b/e2e/hotkeys.spec.ts @@ -4,10 +4,11 @@ import translations from '../client/i18n/locales/english/translations.json'; import { authedRequest } from './utils/request'; import { getEditors } from './utils/editor'; -const course = - '/learn/javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code'; - const links = { + basicJS1: + '/learn/javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code', + basicJS2: + '/learn/javascript-algorithms-and-data-structures/basic-javascript/declare-javascript-variables', frontEnd1: '/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-random-quote-machine', frontEnd2: @@ -22,11 +23,28 @@ const links = { '/learn/python-for-everybody/python-for-everybody/introduction-hardware-architecture' }; +const titles = { + basicJS1: /Comment Your JavaScript Code/, + basicJS2: /Declare JavaScript Variables/, + frontEnd2: /Build a Markdown Previewer/, + backEnd2: /Request Header Parser Microservice/, + video2: /Introduction: Hardware Architecture/ +}; +type PageId = keyof typeof titles; + // The hotkeys are attached to specific elements, so we need to wait for the // wrapper to be focused before we can test the hotkeys. const waitUntilListening = async (page: Page) => await expect(page.locator('#editor-layout')).toBeFocused(); +// This is a hack to work around the fact that the page isn't always hydrated +// with the new content when the URL changes. +const waitUntilHydrated = async (page: Page, pageId: PageId) => { + await page.waitForURL(links[pageId]); + await expect(page).toHaveTitle(titles[pageId]); + await waitUntilListening(page); +}; + test.use({ storageState: 'playwright/.auth/certified-user.json' }); test.beforeAll(async ({ request }) => { @@ -69,21 +87,17 @@ test.afterEach( ); test('User can use shortcuts in and around the editor', async ({ page }) => { - await page.goto(course); + await page.goto(links.basicJS1); await expect(getEditors(page)).toBeFocused(); await getEditors(page).press('Escape'); await expect(getEditors(page)).not.toBeFocused(); await page.keyboard.press('n'); - const nextCourse = '**/declare-javascript-variables'; - await page.waitForURL(nextCourse); - await waitUntilListening(page); + await waitUntilHydrated(page, 'basicJS2'); await page.keyboard.press('p'); - const previousCourse = '**/comment-your-javascript-code'; - await page.waitForURL(previousCourse); - await waitUntilListening(page); + await waitUntilHydrated(page, 'basicJS1'); await page.keyboard.press('e'); await expect(getEditors(page)).toBeFocused(); @@ -101,8 +115,7 @@ test('User can use shortcuts to navigate between frontend projects', async ({ await page.keyboard.press('Escape'); await page.keyboard.press('n'); - await page.waitForURL(links.frontEnd2); - await waitUntilListening(page); + await waitUntilHydrated(page, 'frontEnd2'); await page.keyboard.press('p'); await page.waitForURL(links.frontEnd1); }); @@ -115,8 +128,7 @@ test('User can use shortcuts to navigate between backend projects', async ({ await page.keyboard.press('Escape'); await page.keyboard.press('n'); - await page.waitForURL(links.backEnd2); - await waitUntilListening(page); + await waitUntilHydrated(page, 'backEnd2'); await page.keyboard.press('p'); await page.waitForURL(links.backEnd1); }); @@ -129,8 +141,7 @@ test('User can use shortcuts to navigate between video-based challenges', async await page.keyboard.press('Escape'); await page.keyboard.press('n'); - await page.waitForURL(links.video2); - await waitUntilListening(page); + await waitUntilHydrated(page, 'video2'); await page.keyboard.press('p'); await page.waitForURL(links.video1); });