From 020a8c5c3e47b059746917332d472d902a327a04 Mon Sep 17 00:00:00 2001 From: Sem Bauke Date: Sat, 25 May 2024 21:40:44 +0200 Subject: [PATCH] feat: convert "navigation tests spec" to Playwright (#54944) Co-authored-by: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com> --- .../default/learn/challenges/navigation.ts | 2 +- e2e/challenge-reset-modal.spec.ts | 2 +- e2e/editor.spec.ts | 2 +- .../build-a-personal-portfolio-webpage.json | 3 + e2e/lower-jaw.spec.ts | 2 +- e2e/navigation-from-last-challenge.spec.ts | 90 +++++++++++++++++++ e2e/preview.spec.ts | 3 +- e2e/progress-bar.spec.ts | 2 +- e2e/projects.spec.ts | 2 +- e2e/utils/editor.ts | 14 +-- 10 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 e2e/fixtures/build-a-personal-portfolio-webpage.json create mode 100644 e2e/navigation-from-last-challenge.spec.ts diff --git a/cypress/e2e/default/learn/challenges/navigation.ts b/cypress/e2e/default/learn/challenges/navigation.ts index 608b2c2dd90..7236efc5e8c 100644 --- a/cypress/e2e/default/learn/challenges/navigation.ts +++ b/cypress/e2e/default/learn/challenges/navigation.ts @@ -15,7 +15,7 @@ const challenge2 = { const rwdChallenge = { url: '/learn/2022/responsive-web-design/build-a-personal-portfolio-webpage-project/build-a-personal-portfolio-webpage', nextUrl: - 'http://localhost:8000/learn/2022/responsive-web-design/#build-a-personal-portfolio-webpage-project' + '/learn/2022/responsive-web-design/#build-a-personal-portfolio-webpage-project' }; const rwdChallengeSolution = ` diff --git a/e2e/challenge-reset-modal.spec.ts b/e2e/challenge-reset-modal.spec.ts index 7e37f0eca48..f7b50572d05 100644 --- a/e2e/challenge-reset-modal.spec.ts +++ b/e2e/challenge-reset-modal.spec.ts @@ -57,7 +57,7 @@ test('User can reset challenge', async ({ page, isMobile, browserName }) => { // Modify the text in the editor pane, clearing first, otherwise the existing // text will be selected before typing - await focusEditor({ page, isMobile, browserName }); + await focusEditor({ page, isMobile }); await clearEditor({ page, browserName }); await getEditors(page).fill(updatedText); await expect(updatedFrame).toBeVisible({ timeout: 10000 }); diff --git a/e2e/editor.spec.ts b/e2e/editor.spec.ts index aa30d966266..64a6ee087b4 100644 --- a/e2e/editor.spec.ts +++ b/e2e/editor.spec.ts @@ -44,7 +44,7 @@ test.describe('Python Terminal', () => { 'learn/scientific-computing-with-python/learn-string-manipulation-by-building-a-cipher/step-2' ); - await focusEditor({ page, isMobile, browserName }); + await focusEditor({ page, isMobile }); await clearEditor({ page, browserName }); // Then enter invalid code await page.keyboard.insertText('def'); diff --git a/e2e/fixtures/build-a-personal-portfolio-webpage.json b/e2e/fixtures/build-a-personal-portfolio-webpage.json new file mode 100644 index 00000000000..a033b618df0 --- /dev/null +++ b/e2e/fixtures/build-a-personal-portfolio-webpage.json @@ -0,0 +1,3 @@ +{ + "content": "

text


Projects

text


" +} diff --git a/e2e/lower-jaw.spec.ts b/e2e/lower-jaw.spec.ts index 8b79cbfe672..45b2009227c 100644 --- a/e2e/lower-jaw.spec.ts +++ b/e2e/lower-jaw.spec.ts @@ -110,7 +110,7 @@ test('Prompts unauthenticated user to sign in to save progress', async ({ const loginButton = page.getByRole('link', { name: 'Sign in to save your progress' }); - await focusEditor({ page, browserName, isMobile }); + await focusEditor({ page, isMobile }); await clearEditor({ page, browserName }); await editor.fill( diff --git a/e2e/navigation-from-last-challenge.spec.ts b/e2e/navigation-from-last-challenge.spec.ts new file mode 100644 index 00000000000..3bb60e9fb0a --- /dev/null +++ b/e2e/navigation-from-last-challenge.spec.ts @@ -0,0 +1,90 @@ +import { test } from '@playwright/test'; +import solution from './fixtures/build-a-personal-portfolio-webpage.json'; +import { clearEditor, focusEditor } from './utils/editor'; +import { isMacOS } from './utils/user-agent'; + +// middle of block +const challenge1 = { + url: '/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-javascript-calculator', + nextUrl: + '/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-25--5-clock' +}; + +// last in superblock +const challenge2 = { + url: '/learn/college-algebra-with-python/build-a-data-graph-explorer-project/build-a-data-graph-explorer', + nextUrl: + '/learn/college-algebra-with-python/#build-a-data-graph-explorer-project' +}; + +const rwdChallenge = { + url: '/learn/2022/responsive-web-design/build-a-personal-portfolio-webpage-project/build-a-personal-portfolio-webpage', + nextUrl: + '/learn/2022/responsive-web-design/#build-a-personal-portfolio-webpage-project' +}; +test.use({ storageState: 'playwright/.auth/certified-user.json' }); +test.describe('Navigation from the middle or end (URL solution)', () => { + test('In the middle of a block should take you to the next challenge', async ({ + page + }) => { + await page.goto(challenge1.url); + await page + .getByRole('textbox', { name: 'solution' }) + .fill('https://example.com'); + await page.keyboard.press('Enter'); + await page + .getByRole('button', { name: 'Submit and go to next challenge' }) + .click(); + await page.waitForURL(challenge1.nextUrl); + }); + + test('at the end of a superblock should take you to the superblock page with the current block hash', async ({ + page + }) => { + await page.goto(challenge2.url); + await page + .getByRole('textbox', { name: 'solution' }) + .fill('https://example.com'); + await page.keyboard.press('Enter'); + await page + .getByRole('button', { name: 'Submit and go to next challenge' }) + .click(); + await page.waitForURL(challenge2.nextUrl); + }); +}); + +test.describe('Should take you to the next superblock (with editor solution)', () => { + test.skip( + ({ browserName }) => browserName !== 'chromium', + 'Only chromium allows us to use the clipboard API.' + ); + test('at the end of a superblock should take you to the superblock page with the current block hash', async ({ + page, + isMobile, + browserName, + context + }) => { + await context.grantPermissions(['clipboard-read', 'clipboard-write']); + await page.goto(rwdChallenge.url); + await focusEditor({ page, isMobile }); + await clearEditor({ page, browserName }); + + await page.evaluate( + async solution => await navigator.clipboard.writeText(solution.content), + solution + ); + + if (isMacOS) { + await page.keyboard.press('Meta+v'); + } else { + await page.keyboard.press('Control+v'); + } + + await page.keyboard.press('Control+Enter'); + + await page + .getByRole('button', { name: 'Submit and go to next challenge' }) + .click(); + await page.waitForURL(rwdChallenge.nextUrl); + }); +}); diff --git a/e2e/preview.spec.ts b/e2e/preview.spec.ts index 30203df1dce..5cdb6eb06d4 100644 --- a/e2e/preview.spec.ts +++ b/e2e/preview.spec.ts @@ -28,10 +28,9 @@ test.describe('Challenge Preview Component', () => { test('should render correct output of changed code', async ({ page, - browserName, isMobile }) => { - await focusEditor({ page, isMobile, browserName }); + await focusEditor({ page, isMobile }); await page.keyboard.insertText('

FreeCodeCamp

'); if (isMobile) { diff --git a/e2e/progress-bar.spec.ts b/e2e/progress-bar.spec.ts index cc9ef86aa86..8e3743ebc68 100644 --- a/e2e/progress-bar.spec.ts +++ b/e2e/progress-bar.spec.ts @@ -15,7 +15,7 @@ test.describe('Progress bar component', () => { // If focusEditor fails, typically it's because the instructions are too // large. There's a bug that means `scrollIntoView` does not work in the // editor and so we have to pick less verbose challenges until that's fixed. - await focusEditor({ page, isMobile, browserName }); + await focusEditor({ page, isMobile }); await clearEditor({ page, browserName }); await page.keyboard.insertText( diff --git a/e2e/projects.spec.ts b/e2e/projects.spec.ts index 7b77b14d752..4f289d12d00 100644 --- a/e2e/projects.spec.ts +++ b/e2e/projects.spec.ts @@ -148,7 +148,7 @@ test.describe('JavaScript projects can be submitted and then viewed in /settings '/learn/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/palindrome-checker' ); - await focusEditor({ page, browserName, isMobile }); + await focusEditor({ page, isMobile }); await clearEditor({ page, browserName }); await page.evaluate( diff --git a/e2e/utils/editor.ts b/e2e/utils/editor.ts index f749c5cb7cc..5572c3a6b52 100644 --- a/e2e/utils/editor.ts +++ b/e2e/utils/editor.ts @@ -8,12 +8,10 @@ export const getEditors = (page: Page) => { export const focusEditor = async ({ page, - isMobile, - browserName + isMobile }: { page: Page; isMobile: boolean; - browserName: string; }) => { if (isMobile) { const codeBtn = page.getByRole('tab', { name: 'Code' }); @@ -23,15 +21,7 @@ export const focusEditor = async ({ await codeBtn.click({ force: true }); } - // The editor has an overlay div, which prevents the click event from bubbling up in iOS Safari. - // This is a quirk in this browser-OS combination, and the workaround here is to use `.focus()` - // in place of `.click()` to focus on the editor. - // Ref: https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - if (isMobile && browserName === 'webkit') { - await getEditors(page).focus(); - } else { - await getEditors(page).click(); - } + await getEditors(page).focus(); }; export async function clearEditor({