test(e2e): fix flaky focus mode tests

Fixed 6 flaky E2E tests in focus mode by addressing race conditions
with countdown animation and session state transitions.

Changes:
- Added pointer-events: none to countdown component to prevent blocking
  clicks during fade-out animation (195ms)
- Replaced arbitrary timeouts with explicit waits for session-in-progress
  indicator (complete session button) in all focus mode tests
- Tests now wait for countdown animation to fully complete before
  interacting with UI elements

Root causes:
1. Countdown overlay intercepted pointer events during fade animation,
   causing clicks to fail intermittently
2. 900ms delay between countdown completion and session start caused
   race conditions when using fixed timeouts

Affected tests:
- focus-mode-break.spec.ts (4 tests)
- flowtime-timer-bug-5117.spec.ts (2 tests)

All tests now pass consistently without retries.
This commit is contained in:
Johannes Millan 2026-01-16 22:28:16 +01:00
parent 44f1d7540a
commit e66518868f
3 changed files with 31 additions and 5 deletions

View file

@ -28,6 +28,7 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
}) => {
const focusModeOverlay = page.locator('focus-mode-overlay');
const focusModeBreak = page.locator('focus-mode-break');
const focusModeCountdown = page.locator('focus-mode-countdown');
const mainFocusButton = page
.getByRole('button')
.filter({ hasText: 'center_focus_strong' });
@ -43,6 +44,7 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
await expect(focusModeOverlay).toBeVisible({ timeout: 5000 });
await pomodoroModeButton.click();
await playButton.click();
await expect(focusModeCountdown).not.toBeVisible({ timeout: 10000 });
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
await completeSessionButton.click();
await expect(focusModeBreak).toBeVisible({ timeout: 10000 });
@ -59,6 +61,7 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
const focusModeOverlay = page.locator('focus-mode-overlay');
const focusModeBreak = page.locator('focus-mode-break');
const focusModeMain = page.locator('focus-mode-main');
const focusModeCountdown = page.locator('focus-mode-countdown');
const mainFocusButton = page
.getByRole('button')
.filter({ hasText: 'center_focus_strong' });
@ -85,6 +88,9 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
// Start a focus session
await playButton.click();
// Wait for countdown animation to complete
await expect(focusModeCountdown).not.toBeVisible({ timeout: 10000 });
// Wait for session to be in progress, then complete it
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
await completeSessionButton.click();
@ -122,6 +128,7 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
// Locators
const focusModeOverlay = page.locator('focus-mode-overlay');
const focusModeBreak = page.locator('focus-mode-break');
const focusModeCountdown = page.locator('focus-mode-countdown');
const mainFocusButton = page
.getByRole('button')
.filter({ hasText: 'center_focus_strong' });
@ -143,6 +150,9 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
await pomodoroModeButton.click();
await playButton.click();
// Wait for countdown animation to complete
await expect(focusModeCountdown).not.toBeVisible({ timeout: 10000 });
// Complete the session
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
await completeSessionButton.click();
@ -160,6 +170,7 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
const focusModeOverlay = page.locator('focus-mode-overlay');
const focusModeBreak = page.locator('focus-mode-break');
const focusModeMain = page.locator('focus-mode-main');
const focusModeCountdown = page.locator('focus-mode-countdown');
const mainFocusButton = page
.getByRole('button')
.filter({ hasText: 'center_focus_strong' });
@ -181,6 +192,9 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
await pomodoroModeButton.click();
await playButton.click();
// Wait for countdown animation to complete
await expect(focusModeCountdown).not.toBeVisible({ timeout: 10000 });
// Complete the session
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
await completeSessionButton.click();
@ -203,6 +217,7 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
const focusModeOverlay = page.locator('focus-mode-overlay');
const focusModeBreak = page.locator('focus-mode-break');
const focusModeMain = page.locator('focus-mode-main');
const focusModeCountdown = page.locator('focus-mode-countdown');
const mainFocusButton = page
.getByRole('button')
.filter({ hasText: 'center_focus_strong' });
@ -224,6 +239,9 @@ test.describe('Focus Mode - Break Controls (Issue #5995)', () => {
await pomodoroModeButton.click();
await playButton.click();
// Wait for countdown animation to complete
await expect(focusModeCountdown).not.toBeVisible({ timeout: 10000 });
// Complete the session
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
await completeSessionButton.click();

View file

@ -120,6 +120,9 @@ test.describe('Bug #5117: Flowtime timer stops at Countdown duration', () => {
// Wait for the 5-4-3-2-1 countdown animation to complete
const countdownComponent = page.locator('focus-mode-countdown');
const completeSessionButton = page.locator(
'focus-mode-main button.complete-session-btn',
);
// Wait for countdown to appear and then disappear
try {
@ -132,10 +135,10 @@ test.describe('Bug #5117: Flowtime timer stops at Countdown duration', () => {
console.log('Countdown animation not visible (may be skipped in settings)');
}
// Wait for the timer to start running
await page.waitForTimeout(2000);
// Wait for session to be in progress (complete session button becomes visible)
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
// Wait for clock-time to show a non-zero value (indicating session has started)
// Wait for clock-time to show a non-zero value (indicating timer has started ticking)
await expect(async () => {
const text = await clockTime.textContent();
const trimmed = text?.trim() || '';
@ -241,6 +244,10 @@ test.describe('Bug #5117: Flowtime timer stops at Countdown duration', () => {
// Wait for countdown animation to complete
const countdownComponent = page.locator('focus-mode-countdown');
const completeSessionButton = page.locator(
'focus-mode-main button.complete-session-btn',
);
try {
await expect(countdownComponent).toBeVisible({ timeout: 2000 });
console.log('Countdown animation started...');
@ -250,8 +257,8 @@ test.describe('Bug #5117: Flowtime timer stops at Countdown duration', () => {
console.log('Countdown animation not visible (may be skipped)');
}
// Wait for session to start
await page.waitForTimeout(2000);
// Wait for session to be in progress (complete session button becomes visible)
await expect(completeSessionButton).toBeVisible({ timeout: 10000 });
// Wait for clock-time to show a non-zero value
await expect(async () => {

View file

@ -14,6 +14,7 @@
gap: var(--s3);
padding: var(--s4);
z-index: var(--z-focus-mode-countdown);
pointer-events: none;
}
.message-stack {