From 3dd54b2dca9f7659a79481e000710b1bd2bd531d Mon Sep 17 00:00:00 2001 From: 3rg1s <0x0byte@protonmail.com> Date: Sun, 25 Feb 2024 13:57:12 +0200 Subject: [PATCH 1/3] feat: run server if not running --- playwright.config.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/playwright.config.ts b/playwright.config.ts index bb48d8e01b..ab4fefa7fb 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -6,6 +6,15 @@ import { devices } from '@playwright/test'; * See https://playwright.dev/docs/test-configuration. */ const config: PlaywrightTestConfig = { + // Run your local dev server before starting the tests + webServer: { + command: 'npm run dev', + url: 'http://127.0.0.1:3000', + reuseExistingServer: !process.env.CI, + stdout: 'ignore', + stderr: 'pipe', + }, + testDir: './tests/integration', /* Maximum time one test can run for. */ timeout: 30 * 1000, From cdcb1fb2e07b584df89382e81f9cf617c5d9d7bc Mon Sep 17 00:00:00 2001 From: 3rg1s <0x0byte@protonmail.com> Date: Sun, 25 Feb 2024 17:29:57 +0200 Subject: [PATCH 2/3] feat: retain trace on failures --- playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright.config.ts b/playwright.config.ts index ab4fefa7fb..e7b2fe17ce 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -40,7 +40,7 @@ const config: PlaywrightTestConfig = { /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: 'retain-on-failure', }, /* Configure projects for major browsers */ From 33bf8141e52d5da33ddb3a93944d26516df07289 Mon Sep 17 00:00:00 2001 From: 3rg1s <0x0byte@protonmail.com> Date: Sun, 25 Feb 2024 17:30:58 +0200 Subject: [PATCH 3/3] feat: update spec files --- .../drawers/navigation-menu/drawer.spec.ts | 6 +-- .../drawers/settings/drawer.spec.ts | 8 +-- .../drawers/settings/font-switcher.spec.ts | 6 +-- .../drawers/settings/theme-switcher.spec.ts | 4 +- .../navbar/language-selector.spec.ts | 49 ++++++++++--------- 5 files changed, 35 insertions(+), 38 deletions(-) diff --git a/tests/integration/drawers/navigation-menu/drawer.spec.ts b/tests/integration/drawers/navigation-menu/drawer.spec.ts index 06fefe6047..272b66eea1 100644 --- a/tests/integration/drawers/navigation-menu/drawer.spec.ts +++ b/tests/integration/drawers/navigation-menu/drawer.spec.ts @@ -22,11 +22,7 @@ test('Feedback item should open in a new tab', async ({ page }) => { // 2. Make sure feedback.quran.com opens in a new tab await Promise.all([ page.waitForEvent('popup'), - page - .locator( - 'a:nth-child(11) .LinkContainer_anchor__bOj_o .NavigationDrawerItem_container__ZbHp6 .NavigationDrawerItem_innerContainer__KIZpr', - ) - .click(), // Feedback nav item + page.locator('a', { hasText: 'Feedback' }).first().click(), // Feedback nav item ]); }); diff --git a/tests/integration/drawers/settings/drawer.spec.ts b/tests/integration/drawers/settings/drawer.spec.ts index ceecfe9c80..da67d92fd8 100644 --- a/tests/integration/drawers/settings/drawer.spec.ts +++ b/tests/integration/drawers/settings/drawer.spec.ts @@ -9,11 +9,11 @@ test.beforeEach(async ({ page }) => { test('Settings drawer icon should open the drawer when clicked', async ({ page, context }) => { const homepage = new Homepage(page, context); // 1. Make sure the theme section is not visible - await expect(page.locator('button:has-text("Light")')).not.toBeVisible(); + await expect(page.locator('button', { hasText: 'Light' })).not.toBeVisible(); // 2. Click the settings drawer trigger await homepage.openSettingsDrawer(); // 3. Make sure the theme section is visible - await expect(page.locator('button:has-text("Light")')).toBeVisible(); - await expect(page.locator('button:has-text("Sepia")')).toBeVisible(); - await expect(page.locator('button:has-text("Dark")')).toBeVisible(); + await expect(page.locator('button', { hasText: 'Light' })).toBeVisible(); + await expect(page.locator('button', { hasText: 'Sepia' })).toBeVisible(); + await expect(page.locator('button', { hasText: 'Dark' })).toBeVisible(); }); diff --git a/tests/integration/drawers/settings/font-switcher.spec.ts b/tests/integration/drawers/settings/font-switcher.spec.ts index 453bb3125a..01a05117e4 100644 --- a/tests/integration/drawers/settings/font-switcher.spec.ts +++ b/tests/integration/drawers/settings/font-switcher.spec.ts @@ -13,8 +13,6 @@ test('Selecting a non-default theme should persist the selected font', async ({ context, }) => { const homepage = new Homepage(page, context); - // we cannot access the local storage in webkit straight away so we need to wait for 1 second - await page.waitForTimeout(1000); // 1. make sure code v1 and 16-line Mushaf are persisted by default let persistedQuranReaderStyles = (await homepage.getPersistedValue( 'quranReaderStyles', @@ -27,13 +25,13 @@ test('Selecting a non-default theme should persist the selected font', async ({ await page.locator('text=IndoPak').click(); // 4. Choose Indopak 15-line Mushaf await page.locator('select[name="lines"]').selectOption(MushafLines.FifteenLines); - // 5. make sure indopak and 15-line Mushaf are persisted + // 5. Make sure indopak and 15-line Mushaf are persisted persistedQuranReaderStyles = (await homepage.getPersistedValue( 'quranReaderStyles', )) as QuranReaderStyles; expect(persistedQuranReaderStyles.quranFont).toBe(QuranFont.IndoPak); expect(persistedQuranReaderStyles.mushafLines).toBe(MushafLines.FifteenLines); - // 6. reload the page. + // 6. Reload the page. await page.reload(); // 7. Open the settings drawer await homepage.openSettingsDrawer(); diff --git a/tests/integration/drawers/settings/theme-switcher.spec.ts b/tests/integration/drawers/settings/theme-switcher.spec.ts index d859c173dd..3cdd5ad43d 100644 --- a/tests/integration/drawers/settings/theme-switcher.spec.ts +++ b/tests/integration/drawers/settings/theme-switcher.spec.ts @@ -11,7 +11,7 @@ test.describe('Theme Switcher', () => { const homepage = new Homepage(page, context); // 1. Open the settings drawer await homepage.openSettingsDrawer(); - // 2. get the current active theme + // 2. Get the current active theme const activeTheme = await page.locator('.ThemeSection_iconActive__Q_xs9 + span').textContent(); expect(activeTheme).toBe('Auto'); }); @@ -26,7 +26,7 @@ test.describe('Theme Switcher', () => { // 2. Open the settings drawer await homepage.openSettingsDrawer(); // 3. Click on the light theme - await page.locator('button:has-text("Light")').click(); + await page.locator('button', { hasText: 'Light' }).click(); // 4. Make sure the light theme is the currently selected theme bodyTheme = await page.locator('body').getAttribute('data-theme'); expect(bodyTheme).toBe('light'); diff --git a/tests/integration/navbar/language-selector.spec.ts b/tests/integration/navbar/language-selector.spec.ts index 96a67197b4..fca7b6a182 100644 --- a/tests/integration/navbar/language-selector.spec.ts +++ b/tests/integration/navbar/language-selector.spec.ts @@ -7,47 +7,50 @@ test.beforeEach(async ({ page }) => { test('Clicking on Nav bar language selector icon should open the language selector menu', async ({ page, }) => { - // 1. make sure the language selector items are not visible - await expect(page.locator('div[role="menuitem"]:has-text("English")')).not.toBeVisible(); + // 1. Make sure the language selector items are not visible + await expect(page.getByRole('menuitem', { name: 'English' })).not.toBeVisible(); // 2. Click on the language selector nav bar trigger await page.locator('[aria-label="Select Language"]').click(); // 3. Make sure the language selector items are visible - await expect(page.locator('div[role="menuitem"]:has-text("English")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("العربية")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("বাংলা")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("فارسی")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Français")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Italiano")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Dutch")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Português")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("русский")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Shqip")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("ภาษาไทย")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Türkçe")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("اردو")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("简体中文")')).toBeVisible(); - await expect(page.locator('div[role="menuitem"]:has-text("Melayu")')).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'English' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'العربية' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'বাংলা' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'فارسی' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Français' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Italiano' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Dutch' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Português' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'русский' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Shqip' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'ภาษาไทย' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Türkçe' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'اردو' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: '简体中文' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Melayu' })).toBeVisible(); }); test('Choosing a language should navigate the user to the localized page of that language', async ({ page, + baseURL, }) => { // 1. Make sure we are on the English version await expect(page).toHaveURL('/'); // 2. Open the language selector menu await page.locator('[aria-label="Select Language"]').click(); - // 3. select the Bengali language and make sure we are navigated to /bn - await Promise.all([page.waitForNavigation({ url: '/bn' }), page.locator('text=বাংলা').click()]); + // 3. Select the Bengali language and make sure we are navigated to /bn + await page.locator('text=বাংলা').click(); + await page.waitForURL('**/bn'); + expect(page.url()).toBe(`${baseURL}/bn`); }); test('Choosing a language should persist', async ({ page, baseURL }) => { // 1. Open the language selector menu await page.locator('[aria-label="Select Language"]').click(); - // 2. select the Arabic language and make sure we are navigated to /ar - await Promise.all([page.waitForNavigation({ url: '/ar' }), page.locator('text=العربية').click()]); + // 2. Select the Arabic language and make sure we are navigated to /ar + await page.locator('text=العربية').click(); + await page.waitForURL('**/ar'); // 3. Navigate again to / await page.goto('/'); - const currentUrl = page.url(); // 4. Make sure the user is redirected to /ar - expect(currentUrl).toBe(`${baseURL}/ar`); + expect(page.url()).toBe(`${baseURL}/ar`); });