From 8dd7cd99ef92bdf348b08c27ddb5a50b6066ea92 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Wed, 6 May 2026 15:52:27 +0200 Subject: [PATCH] test(e2e): tighten boards #7498 regression specs Multi-review feedback: drop waitForTimeout (project rule), use the taskPage.markTaskAsDone helper instead of raw locator clicks, and scope the Eisenhower assertion to the specific quadrant the task belongs in. Also exact-match the Kanban "Create Tag" button to avoid matching the Eisenhower tab's plural label when both tab bodies briefly co-exist. --- .../boards/issue-7498-kanban-done.spec.ts | 22 +++++------ .../boards/issue-7498-task-disappears.spec.ts | 37 ++++++++++--------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/e2e/tests/boards/issue-7498-kanban-done.spec.ts b/e2e/tests/boards/issue-7498-kanban-done.spec.ts index f4032e4cf6..db57381d97 100644 --- a/e2e/tests/boards/issue-7498-kanban-done.spec.ts +++ b/e2e/tests/boards/issue-7498-kanban-done.spec.ts @@ -10,6 +10,7 @@ test.describe('Boards #7498 — Kanban', () => { test('task with In Progress tag lands in DONE after done-toggle', async ({ page, workViewPage, + taskPage, testPrefix, }) => { await workViewPage.waitForTaskList(); @@ -28,10 +29,12 @@ test.describe('Boards #7498 — Kanban', () => { // On a fresh profile the Kanban panels reference KANBAN_IN_PROGRESS which // doesn't exist yet — the board renders a "Create Tag" prompt instead of - // the columns. Click it and wait for the panels to appear. - const createTagsBtn = page.locator('button', { hasText: /create tags?/i }); - await createTagsBtn.waitFor({ state: 'visible', timeout: 10000 }); - await createTagsBtn.click(); + // the columns. Match the singular Kanban label exactly so we don't also + // pick up the Eisenhower tab's "Create Tags" button when both tab bodies + // are momentarily in the DOM during the mat-tab transition. + const createTagBtn = page.getByRole('button', { name: 'Create Tag', exact: true }); + await createTagBtn.waitFor({ state: 'visible', timeout: 10000 }); + await createTagBtn.click(); const inProgressPanel = page .locator('board-panel') @@ -48,7 +51,6 @@ test.describe('Boards #7498 — Kanban', () => { await inlineInput.waitFor({ state: 'visible', timeout: 5000 }); await inlineInput.fill(taskName); await page.keyboard.press('Enter'); - await page.keyboard.press('Escape'); const inProgressTask = inProgressPanel .locator('planner-task') @@ -56,19 +58,17 @@ test.describe('Boards #7498 — Kanban', () => { .first(); await expect(inProgressTask).toBeVisible({ timeout: 10000 }); - // Click the done-toggle (circle) on the task. - await inProgressTask.hover(); - await inProgressTask.locator('done-toggle').click(); - await page.waitForTimeout(500); + await taskPage.markTaskAsDone(inProgressTask); // The task should land in the DONE column. Pre-fix it would have been - // filtered out by `excludedTagIds: [IN_PROGRESS_TAG.id]`. + // filtered out by `excludedTagIds: [IN_PROGRESS_TAG.id]`. Playwright auto- + // retries until the state settles after the toggle animation. const donePanel = page .locator('board-panel') .filter({ has: page.locator('header .title', { hasText: /^done$/i }) }) .first(); await expect( donePanel.locator('planner-task').filter({ hasText: taskName }).first(), - ).toBeVisible({ timeout: 5000 }); + ).toBeVisible(); }); }); diff --git a/e2e/tests/boards/issue-7498-task-disappears.spec.ts b/e2e/tests/boards/issue-7498-task-disappears.spec.ts index 3f68949dce..aef7f88cb7 100644 --- a/e2e/tests/boards/issue-7498-task-disappears.spec.ts +++ b/e2e/tests/boards/issue-7498-task-disappears.spec.ts @@ -8,15 +8,18 @@ import { expect, test } from '../../fixtures/test.fixture'; * original quadrant. */ test.describe('Boards #7498', () => { - test('Eisenhower: task stays visible after done-toggle', async ({ + test('Eisenhower: task stays in its quadrant after done-toggle', async ({ page, workViewPage, + taskPage, + testPrefix, }) => { await workViewPage.waitForTaskList(); // Plain task with no tags lands in the NOT_URGENT_AND_NOT_IMPORTANT // quadrant (excluded: [Important, Urgent], included: []). - await workViewPage.addTask('repro7498 task'); + const taskName = `${testPrefix}repro7498-eisenhower`; + await workViewPage.addTask(taskName); await page.goto('/#/boards'); await page.waitForLoadState('networkidle'); @@ -35,24 +38,24 @@ test.describe('Boards #7498', () => { await createTagsBtn.click(); } - const task = page - .locator('board-panel planner-task') - .filter({ hasText: 'repro7498 task' }) + const notUrgentNotImportantPanel = page + .locator('board-panel') + .filter({ + has: page.locator('header .title', { hasText: /not urgent.*not important/i }), + }) .first(); - await expect(task).toBeVisible({ timeout: 10000 }); + await expect(notUrgentNotImportantPanel).toBeVisible({ timeout: 10000 }); - await task.hover(); - await task.locator('done-toggle').click(); + const task = notUrgentNotImportantPanel + .locator('planner-task') + .filter({ hasText: taskName }) + .first(); + await expect(task).toBeVisible(); - // Wait past the 200ms done-animation delay used in toggleDoneWithAnimation. - await page.waitForTimeout(500); + await taskPage.markTaskAsDone(task); - // Fixed behavior: the task remains visible somewhere on the board. - await expect( - page - .locator('board-panel planner-task') - .filter({ hasText: 'repro7498 task' }) - .first(), - ).toBeVisible(); + // Fixed behavior: the task is still in its original quadrant — Playwright + // auto-retries the assertion until the toggle's 200ms animation settles. + await expect(task).toBeVisible(); }); });