test: add smoke test for focus-event UI freeze regression
Verifies that window focus events don't block the main thread for >500ms, covering both single focus and rapid 5x focus (Cmd+Tab spam) scenarios. Completes the regression test requirement for the git-commands-off-main-thread fix. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
50
tests/smoke/focus-no-freeze.spec.ts
Normal file
50
tests/smoke/focus-no-freeze.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test.describe('Focus event does not freeze the UI', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await page.waitForLoadState('networkidle')
|
||||
})
|
||||
|
||||
test('window focus event completes without blocking UI for >500ms', async ({ page }) => {
|
||||
// Verify the app loaded
|
||||
await expect(page.locator('[data-testid="sidebar"]').or(page.locator('nav')).first()).toBeVisible()
|
||||
|
||||
// Measure how long the UI is blocked after a focus event.
|
||||
// We dispatch focus, then immediately schedule a rAF callback.
|
||||
// If the main thread is blocked (sync IPC), the rAF callback is delayed.
|
||||
const blockMs = await page.evaluate(() => {
|
||||
return new Promise<number>((resolve) => {
|
||||
const t0 = performance.now()
|
||||
window.dispatchEvent(new Event('focus'))
|
||||
requestAnimationFrame(() => {
|
||||
resolve(performance.now() - t0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// The focus handler must not block the main thread for more than 500ms.
|
||||
// Before the fix, git_pull ran synchronously and blocked for 2-3 seconds.
|
||||
expect(blockMs).toBeLessThan(500)
|
||||
})
|
||||
|
||||
test('rapid focus events (5x) do not accumulate freezes', async ({ page }) => {
|
||||
await expect(page.locator('[data-testid="sidebar"]').or(page.locator('nav')).first()).toBeVisible()
|
||||
|
||||
const totalMs = await page.evaluate(() => {
|
||||
return new Promise<number>((resolve) => {
|
||||
const t0 = performance.now()
|
||||
for (let i = 0; i < 5; i++) {
|
||||
window.dispatchEvent(new Event('focus'))
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
resolve(performance.now() - t0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// 5 rapid focus events should still complete in under 500ms total
|
||||
// thanks to the cooldown preventing redundant work.
|
||||
expect(totalMs).toBeLessThan(500)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user