diff --git a/tests/e2e/auth.setup.ts b/tests/e2e/auth.setup.ts index 76cbcf471..a8eb47d80 100644 --- a/tests/e2e/auth.setup.ts +++ b/tests/e2e/auth.setup.ts @@ -1,13 +1,11 @@ import { join } from 'path' import { expect, test as setup } from '@playwright/test' import { wpCli } from './helpers/wpCli' -import { URLS } from './helpers/constants' +import { TIMEOUTS, URLS } from './helpers/constants' const authFile = join(__dirname, '.auth/user.json') -const AUTH_SETUP_TIMEOUT_MS = 120000 - setup('authenticate', async ({ page }) => { - setup.setTimeout(AUTH_SETUP_TIMEOUT_MS) + setup.setTimeout(TIMEOUTS.VERY_LONG) // Ensure a clean environment across local runs / retries. // If Safe Mode is enabled via `wp-config.php` it disables snippet execution and can @@ -60,10 +58,10 @@ setup('authenticate', async ({ page }) => { await updateBtn.first().click() } // Give the upgrade process more time to complete and the admin UI to load. - await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: 120000 }) + await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: TIMEOUTS.VERY_LONG }) } else { // Normal path: wait for admin UI. - await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: 60000 }) + await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: TIMEOUTS.LONG }) } await expect(page.locator('#adminmenu')).toBeVisible() diff --git a/tests/e2e/code-snippets-list.spec.ts b/tests/e2e/code-snippets-list.spec.ts index b2b52596c..00b89b21d 100644 --- a/tests/e2e/code-snippets-list.spec.ts +++ b/tests/e2e/code-snippets-list.spec.ts @@ -1,14 +1,17 @@ import { readFileSync } from 'fs' import { expect, test } from '@playwright/test' import { DEFAULT_E2E_SNIPPET_BASE_NAME, SnippetsTestHelper } from './helpers/SnippetsTestHelper' -import { SELECTORS } from './helpers/constants' +import { SELECTORS, TIMEOUTS } from './helpers/constants' import type { Page, Route } from '@playwright/test' // The view preference saves through an optimistic background request, so wait // for it to persist before navigating or ending the test. const switchSnippetView = async (page: Page, view: 'Card view' | 'Table view') => { const saved = page - .waitForResponse(response => response.url().includes('/snippet-view') && 'GET' !== response.request().method(), { timeout: 5000 }) + .waitForResponse( + response => response.url().includes('/snippet-view') && 'GET' !== response.request().method(), + { timeout: TIMEOUTS.SHORT } + ) .catch(() => undefined) await page.getByRole('button', { name: view }).click() await saved @@ -31,8 +34,6 @@ const clickRowAction = async (row: ReturnType, selector test.describe('Code Snippets List Page Actions', () => { let helper: SnippetsTestHelper let snippetName: string - const EXPORT_TEST_TIMEOUT_MS = 60000 - test.beforeEach(async ({ page }) => { helper = new SnippetsTestHelper(page) snippetName = SnippetsTestHelper.makeUniqueSnippetName() @@ -236,7 +237,7 @@ test.describe('Code Snippets List Page Actions', () => { if (isCreateRequest) { createRequests += 1 - await new Promise(resolve => setTimeout(resolve, 500)) + await new Promise(resolve => setTimeout(resolve, TIMEOUTS.VERY_SHORT)) } await route.continue() @@ -284,13 +285,13 @@ test.describe('Code Snippets List Page Actions', () => { // Some implementations show a confirmation modal that must be dismissed. const confirmDialog = page.locator('[role="dialog"]').filter({ hasText: /Are you sure\\?/i }) const dialogVisible = await confirmDialog - .waitFor({ state: 'visible', timeout: 2000 }) + .waitFor({ state: 'visible', timeout: TIMEOUTS.VERY_SHORT }) .then(() => true) .catch(() => false) if (dialogVisible) { await confirmDialog.locator('button:has-text("Trash"), button:has-text("Delete")').first().click() - await confirmDialog.waitFor({ state: 'hidden', timeout: 30000 }).catch(() => undefined) + await confirmDialog.waitFor({ state: 'hidden', timeout: TIMEOUTS.DEFAULT }).catch(() => undefined) } await expect(page).toHaveURL(/page=snippets/) @@ -301,16 +302,16 @@ test.describe('Code Snippets List Page Actions', () => { await expect(trashedLink).toBeVisible() await trashedLink.click() - await expect(page).toHaveURL(/status=trashed/, { timeout: 30000 }) + await expect(page).toHaveURL(/status=trashed/, { timeout: TIMEOUTS.DEFAULT }) await expect(page.locator(SELECTORS.SNIPPETS_TABLE)).toBeVisible() const trashedRow = page.locator(`${SELECTORS.SNIPPET_ROW}:has-text("${snippetName}")`).first() - await expect(trashedRow).toBeVisible({ timeout: 30000 }) + await expect(trashedRow).toBeVisible({ timeout: TIMEOUTS.DEFAULT }) await expect(trashedRow).toContainText(/Restore/i) }) test('Can export snippet from list page', async ({ page }) => { - test.setTimeout(EXPORT_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.LONG) const snippetRow = snippetRowByName(page, snippetName) await expect(snippetRow).toBeVisible() await snippetRow.hover() @@ -325,7 +326,7 @@ test.describe('Code Snippets List Page Actions', () => { }) test('Can export multiple snippets from bulk actions', async ({ page }) => { - test.setTimeout(EXPORT_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.LONG) const secondSnippetName = SnippetsTestHelper.makeUniqueSnippetName() await helper.createAndActivateSnippet({ @@ -355,7 +356,7 @@ test.describe('Code Snippets List Page Actions', () => { }) test('Can download a single snippet from bulk actions', async ({ page }) => { - test.setTimeout(EXPORT_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.LONG) await helper.filterSnippetsByName(snippetName) const snippetRow = snippetRowByName(page, snippetName) await expect(snippetRow).toBeVisible() @@ -372,7 +373,7 @@ test.describe('Code Snippets List Page Actions', () => { }) test('Can download multiple snippets from bulk actions as a zip archive', async ({ page }) => { - test.setTimeout(EXPORT_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.LONG) const secondSnippetName = SnippetsTestHelper.makeUniqueSnippetName('E2E Download CSS') await SnippetsTestHelper.createSnippetViaCli({ @@ -403,7 +404,7 @@ test.describe('Code Snippets List Page Actions', () => { }) test('Bulk download stays scoped to the current page selection', async ({ page }) => { - test.setTimeout(EXPORT_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.LONG) const bulkScopeBaseName = 'E2E Bulk Scope' const firstScopedSnippetName = SnippetsTestHelper.makeUniqueSnippetName(bulkScopeBaseName) const secondScopedSnippetName = SnippetsTestHelper.makeUniqueSnippetName(bulkScopeBaseName) @@ -448,7 +449,7 @@ test.describe('Code Snippets List Page Actions', () => { }) test('Bulk export stays scoped to the current page selection', async ({ page }) => { - test.setTimeout(EXPORT_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.LONG) const bulkScopeBaseName = 'E2E Bulk Scope Export' const firstScopedSnippetName = SnippetsTestHelper.makeUniqueSnippetName(bulkScopeBaseName) const secondScopedSnippetName = SnippetsTestHelper.makeUniqueSnippetName(bulkScopeBaseName) diff --git a/tests/e2e/code-snippets-paste-tags.spec.ts b/tests/e2e/code-snippets-paste-tags.spec.ts index 7fa4d869d..eed3abcc5 100644 --- a/tests/e2e/code-snippets-paste-tags.spec.ts +++ b/tests/e2e/code-snippets-paste-tags.spec.ts @@ -1,5 +1,6 @@ import { expect, test } from '@playwright/test' import { SnippetsTestHelper } from './helpers/SnippetsTestHelper' +import { TIMEOUTS } from './helpers/constants' import type { Page } from '@playwright/test' interface CodeMirrorHost { @@ -28,7 +29,7 @@ const enterCode = async (page: Page, code: string, origin: 'paste' | '+input'): cm.replaceRange(text, { line: 0, ch: 0 }, { line: 0, ch: 0 }, changeOrigin) }, [code, origin]) - await page.waitForTimeout(400) + await page.waitForTimeout(TIMEOUTS.VERY_SHORT) } const editorValue = (page: Page): Promise => diff --git a/tests/e2e/code-snippets-quicknav-admin-bar.spec.ts b/tests/e2e/code-snippets-quicknav-admin-bar.spec.ts index ff6dc39db..e1454b88b 100644 --- a/tests/e2e/code-snippets-quicknav-admin-bar.spec.ts +++ b/tests/e2e/code-snippets-quicknav-admin-bar.spec.ts @@ -1,12 +1,10 @@ import { expect, test } from '@playwright/test' import { SnippetsTestHelper } from './helpers/SnippetsTestHelper' import { wpCli } from './helpers/wpCli' -import { URLS } from './helpers/constants' +import { TIMEOUTS, URLS } from './helpers/constants' const QUICKNAV_PREFIX = 'E2E QuickNav' const QUICKNAV_PER_PAGE = 2 -const QUICKNAV_TEST_TIMEOUT_MS = 180000 - test.describe('Admin Bar Snippets QuickNav', () => { let activeA: string let activeB: string @@ -16,7 +14,7 @@ test.describe('Admin Bar Snippets QuickNav', () => { let inactiveA: string test.beforeAll(async () => { - test.setTimeout(QUICKNAV_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.EXTRA_LONG) await SnippetsTestHelper.setAdminBarQuickNavSettings({ enabled: true, perPage: QUICKNAV_PER_PAGE }) await SnippetsTestHelper.cleanupSnippetsByPrefix(QUICKNAV_PREFIX) @@ -41,7 +39,7 @@ test.describe('Admin Bar Snippets QuickNav', () => { }) test('Menu structure and pagination works', async ({ page }) => { - test.setTimeout(QUICKNAV_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.EXTRA_LONG) const helper = new SnippetsTestHelper(page) await helper.navigateToSnippetsAdmin() @@ -100,7 +98,7 @@ test.describe('Admin Bar Snippets QuickNav', () => { }) test('Manage submenu contains status quick links', async ({ page }) => { - test.setTimeout(QUICKNAV_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.EXTRA_LONG) const helper = new SnippetsTestHelper(page) await helper.navigateToSnippetsAdmin() @@ -118,7 +116,7 @@ test.describe('Admin Bar Snippets QuickNav', () => { }) test('QuickNav menu can be disabled via setting', async ({ page }) => { - test.setTimeout(QUICKNAV_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.EXTRA_LONG) await SnippetsTestHelper.setAdminBarQuickNavSettings({ enabled: false, perPage: QUICKNAV_PER_PAGE }) @@ -133,7 +131,7 @@ test.describe('Admin Bar Snippets QuickNav', () => { }) test('Safe Mode indicator appears only when Safe Mode is active', async ({ page }) => { - test.setTimeout(QUICKNAV_TEST_TIMEOUT_MS) + test.setTimeout(TIMEOUTS.EXTRA_LONG) const safeModeMuPluginPath = 'wp-content/mu-plugins/code-snippets-e2e-safe-mode.php' const removeMuPlugin = async () => { @@ -161,7 +159,7 @@ test.describe('Admin Bar Snippets QuickNav', () => { await page.goto(URLS.SNIPPETS_ADMIN) const safeModeNode = page.locator('#wp-admin-bar-code-snippets-safe-mode') - await expect(safeModeNode).toBeVisible({ timeout: 30000 }) + await expect(safeModeNode).toBeVisible({ timeout: TIMEOUTS.DEFAULT }) const safeModeLink = safeModeNode.locator('a').first() await expect(safeModeLink).toHaveAttribute('href', 'https://snipco.de/safe-mode') diff --git a/tests/e2e/flat-files.setup.ts b/tests/e2e/flat-files.setup.ts index 39de2119b..fcc6548de 100644 --- a/tests/e2e/flat-files.setup.ts +++ b/tests/e2e/flat-files.setup.ts @@ -1,4 +1,5 @@ import { expect, test as setup } from '@playwright/test' +import { TIMEOUTS } from './helpers/constants' setup('enable flat files', async ({ page }) => { const isMultisite = 'true' === process.env.WP_E2E_MULTISITE_MODE || '1' === process.env.WP_E2E_MULTISITE_MODE @@ -22,12 +23,12 @@ setup('enable flat files', async ({ page }) => { // Await page.click('input[type="submit"][name="submit"]') - // await page.waitForSelector('.notice-success', { timeout: 10000 }) + // await page.waitForSelector('.notice-success', { timeout: TIMEOUTS.MEDIUM }) // await expect(page.locator('.notice-success')).toContainText('Settings saved') const saveButton = page.getByRole('button', { name: 'Save Changes' }) await Promise.all([ - page.waitForURL(/settings-updated=true/, { timeout: 10000 }), + page.waitForURL(/settings-updated=true/, { timeout: TIMEOUTS.MEDIUM }), saveButton.click() ]) diff --git a/tests/e2e/helpers/SnippetsTestHelper.ts b/tests/e2e/helpers/SnippetsTestHelper.ts index 59a71a695..f6d14e4a4 100644 --- a/tests/e2e/helpers/SnippetsTestHelper.ts +++ b/tests/e2e/helpers/SnippetsTestHelper.ts @@ -13,8 +13,6 @@ const RANDOM_SLICE_END = 7 const CLICK_RETRIES = 3 const SAVE_CONFIRM_RETRIES = 3 const AT_LEAST_ONE = 1 -const SAVE_SETTLE_TIMEOUT_MS = 10000 - const getErrorMessage = (error: unknown): string => { if (error instanceof Error) { return error.message @@ -347,7 +345,7 @@ export class SnippetsTestHelper { await this.clickButton(name) const settled = await this.page.locator(SELECTORS.SAVE_SETTLED_NOTICE).first() - .waitFor({ state: 'visible', timeout: SAVE_SETTLE_TIMEOUT_MS }) + .waitFor({ state: 'visible', timeout: TIMEOUTS.MEDIUM }) .then(() => true) .catch(() => false) diff --git a/tests/e2e/helpers/constants.ts b/tests/e2e/helpers/constants.ts index 8962ad84a..15bd57072 100644 --- a/tests/e2e/helpers/constants.ts +++ b/tests/e2e/helpers/constants.ts @@ -23,8 +23,13 @@ export const SELECTORS = { } export const TIMEOUTS = { + VERY_SHORT: 2000, + SHORT: 5000, + MEDIUM: 10000, DEFAULT: 30000, - SHORT: 5000 + LONG: 60000, + VERY_LONG: 120000, + EXTRA_LONG: 180000 } export const URLS = { diff --git a/tests/e2e/rtl.setup.ts b/tests/e2e/rtl.setup.ts index 25095d636..f64c7bfe3 100644 --- a/tests/e2e/rtl.setup.ts +++ b/tests/e2e/rtl.setup.ts @@ -2,17 +2,15 @@ import { writeFileSync } from 'fs' import { expect, test as setup } from '@playwright/test' import { RTL_LOCALE, RTL_USER, rtlAuthFile, rtlCreatedMarker } from './helpers/rtlUser' import { wpCli } from './helpers/wpCli' -import { URLS } from './helpers/constants' +import { TIMEOUTS, URLS } from './helpers/constants' // The RTL specs sign in as a user of their own whose locale is right-to-left, // so the rest of the suite, which signs in as the usual admin, never sees the // site mirrored, whatever order the projects run in. The language pack is // fetched from wordpress.org when missing; if that is impossible (offline), // the specs notice the page is still left-to-right and skip themselves. -const SETUP_TIMEOUT_MS = 180000 - setup('sign in as a right-to-left user', async ({ page }) => { - setup.setTimeout(SETUP_TIMEOUT_MS) + setup.setTimeout(TIMEOUTS.EXTRA_LONG) try { await wpCli(['language', 'core', 'install', RTL_LOCALE]) @@ -41,7 +39,7 @@ setup('sign in as a right-to-left user', async ({ page }) => { page.waitForLoadState('domcontentloaded'), page.click('#wp-submit') ]) - await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: 60000 }) + await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: TIMEOUTS.LONG }) await expect(page.locator('#adminmenu')).toBeVisible() const dir = await page.evaluate(() => document.documentElement.getAttribute('dir'))