From d64014d086d82bec018b3872bacf41983f7b8339 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Fri, 17 Apr 2026 13:59:48 +0200 Subject: [PATCH] test(e2e): wait for .isDone in supersync mark-done helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TaskService.toggleDoneWithAnimation schedules the setDone dispatch via setTimeout(200ms) to play the mark-done animation. markTaskDone and markSubtaskDone returned immediately after clicking done-toggle, so a following syncAndWait() could start before the late updateTask op was captured. The op then landed during the sync's upload batch, leaving hasPendingOps=true after sync completed and the .sync-state-ico check mark never appeared — supersync.page.ts:1762 timed out. Fixes flaky "4.1 Complex chain of actions syncs correctly" and "Time tracking data persists after archive". --- e2e/utils/supersync-helpers.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/e2e/utils/supersync-helpers.ts b/e2e/utils/supersync-helpers.ts index f824347100..8a4e2368d4 100644 --- a/e2e/utils/supersync-helpers.ts +++ b/e2e/utils/supersync-helpers.ts @@ -491,6 +491,12 @@ export const getParentTaskElement = ( /** * Mark a task as done by hovering and clicking the done button. * + * Waits for the `.isDone` class to appear before returning. `TaskService.toggleDoneWithAnimation` + * schedules the actual `setDone` dispatch via `setTimeout(200ms)` for the mark-done animation, + * so without this wait a following sync can start before the updateTask op is captured — the + * late op then lands during the sync's upload, leaving `hasPendingOps=true` and the check icon + * never appears. + * * @param client - The simulated E2E client * @param taskName - The task name to mark as done */ @@ -501,12 +507,18 @@ export const markTaskDone = async ( const task = getTaskElement(client, taskName); await task.hover(); await task.locator('done-toggle').click(); + await expect(getDoneTaskElement(client, taskName).first()).toBeVisible({ + timeout: UI_VISIBLE_TIMEOUT, + }); }; /** * Mark a subtask as done by hovering and clicking the done button. * Uses getSubtaskElement to avoid matching parent tasks. * + * Waits for `.isDone` for the same reason as `markTaskDone` — the 200ms animation delay in + * `toggleDoneWithAnimation` would otherwise race the following sync and leave pending ops. + * * @param client - The simulated E2E client * @param subtaskName - The subtask name to mark as done */ @@ -517,6 +529,9 @@ export const markSubtaskDone = async ( const subtask = getSubtaskElement(client, subtaskName); await subtask.hover(); await subtask.locator('done-toggle').click(); + await expect(getDoneSubtaskElement(client, subtaskName).first()).toBeVisible({ + timeout: UI_VISIBLE_TIMEOUT, + }); }; /**