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>
51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
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)
|
|
})
|
|
})
|