Fix animation stale reference

This commit is contained in:
2026-07-21 16:03:28 +10:00
parent d2d82ae6ae
commit 9af84760fa
12 changed files with 225 additions and 38 deletions

View File

@@ -32,6 +32,17 @@ async function waitForTransition(page: Page) {
await expect(page.locator('.nvr-router-view')).not.toHaveClass(/nvr-router-view--interactive/)
}
async function flickToNextTab(page: Page) {
// Start on the route header, outside conversation-owned drag targets.
const frame = await page.locator('[data-native-role="active"] .app-header, [data-native-role="to"] .app-header').last().boundingBox()
if (!frame) throw new Error('Active route header did not render')
const y = frame.y + frame.height * 0.5
await page.mouse.move(frame.x + frame.width * 0.68, y)
await page.mouse.down()
await page.mouse.move(frame.x + frame.width * 0.48, y)
await page.mouse.up()
}
test('navigates a conversation and returns through the native runtime', async ({ page }) => {
await page.goto('/inbox')
await expect(page.getByRole('heading', { name: 'Messages' })).toBeVisible()
@@ -131,6 +142,26 @@ test('moves sibling screens edge-to-edge at one-to-one drag progress', async ({
await page.mouse.up()
})
test('accepts a second fast tab flick while the first spring is still settling', async ({ page }) => {
await page.goto('/inbox')
const routerView = page.locator('.nvr-router-view')
await flickToNextTab(page)
await expect(page).toHaveURL(/\/stories$/)
await expect(routerView).toHaveClass(/nvr-router-view--interactive/)
await flickToNextTab(page)
await expect(page).toHaveURL(/\/profile$/)
await waitForTransition(page)
// A stale pointer-up cleanup used to leave an orphaned transaction here,
// permanently blocking both subsequent swipes and imperative tab links.
await page.getByRole('link', { name: /Inbox/ }).click()
await expect(page).toHaveURL(/\/inbox$/)
await waitForTransition(page)
await expect(routerView).not.toHaveAttribute('data-native-transaction')
})
test('opens and dismisses the compose sheet', async ({ page }) => {
await page.goto('/inbox')
await page.getByRole('button', { name: 'Compose' }).click()

View File

@@ -30,7 +30,12 @@ test('ships an installable standalone manifest and iOS metadata', async ({ page,
expect.objectContaining({ src: '/pwa-512.png', sizes: '512x512', type: 'image/png' }),
]))
expect((await request.get('/apple-touch-icon.png')).headers()['content-type']).toContain('image/png')
expect((await request.get('/sw.js')).ok()).toBe(true)
const workerResponse = await request.get('/sw.js')
expect(workerResponse.ok()).toBe(true)
expect(workerResponse.headers()['cache-control']).toContain('no-cache')
const worker = await workerResponse.text()
expect(worker).toContain('self.skipWaiting()')
expect(worker).toContain('clientsClaim()')
})
test('does not interfere with Safari edge touches before Home Screen installation', async ({ page }) => {
@@ -67,6 +72,7 @@ test('registers and activates the offline service worker', async ({ page }) => {
return registration.active?.scriptURL ?? ''
})
expect(workerUrl).toMatch(/\/sw\.js$/)
await expect(page.locator('html')).not.toHaveAttribute('data-pwa-update-checks', '0')
})
test('precaches lazily split routes for offline navigation', async ({ page }) => {