2026-09-10 19:57:45 +00:00
|
|
|
import { type Page } from '@playwright/test'
|
|
|
|
|
|
2026-08-13 18:39:35 +00:00
|
|
|
import { expect, test } from '#tests/e2e/fixtures'
|
|
|
|
|
import { CanvasHelper } from '#tests/helpers/canvas'
|
|
|
|
|
|
2026-09-10 19:57:45 +00:00
|
|
|
function recoverySnapshotCount(page: Page): Promise<number> {
|
|
|
|
|
return page.evaluate(async () => {
|
|
|
|
|
const request = indexedDB.open('open-pencil-recovery')
|
|
|
|
|
const database = await new Promise<IDBDatabase>((resolve, reject) => {
|
|
|
|
|
request.onsuccess = () => resolve(request.result)
|
|
|
|
|
request.onerror = () => reject(request.error)
|
|
|
|
|
})
|
|
|
|
|
const transaction = database.transaction('meta')
|
|
|
|
|
const countRequest = transaction.objectStore('meta').count()
|
|
|
|
|
return new Promise<number>((resolve, reject) => {
|
|
|
|
|
countRequest.onsuccess = () => resolve(countRequest.result)
|
|
|
|
|
countRequest.onerror = () => reject(countRequest.error)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-13 18:39:35 +00:00
|
|
|
test('keeps an unsaved document recoverable after its tab closes', async ({ browser, baseURL }) => {
|
|
|
|
|
const context = await browser.newContext({ baseURL })
|
|
|
|
|
const page = await context.newPage()
|
|
|
|
|
await page.goto('/')
|
|
|
|
|
const canvas = new CanvasHelper(page)
|
|
|
|
|
await canvas.waitForInit()
|
|
|
|
|
|
|
|
|
|
await page.evaluate(async () => {
|
|
|
|
|
const store = window.openPencil?.getStore?.()
|
|
|
|
|
if (!store) throw new Error('OpenPencil store not initialized')
|
|
|
|
|
const id = store.createShape('RECTANGLE', 120, 120, 240, 140)
|
|
|
|
|
await store.persistRecoveryNow()
|
|
|
|
|
store.updateNode(id, { name: 'Retained recovery rectangle' })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await page.keyboard.press('ControlOrMeta+t')
|
|
|
|
|
await expect(page.getByRole('button', { name: 'New tab' })).toBeVisible()
|
|
|
|
|
await page.getByTestId('tabbar-tab').first().getByTestId('tabbar-close').click()
|
|
|
|
|
await expect(page.getByRole('button', { name: 'New tab' })).toBeHidden()
|
2026-09-10 19:57:45 +00:00
|
|
|
await expect.poll(() => recoverySnapshotCount(page)).toBe(1)
|
2026-08-13 18:39:35 +00:00
|
|
|
|
|
|
|
|
await page.reload()
|
|
|
|
|
await expect(page.getByRole('alertdialog', { name: 'Recover unsaved work' })).toBeVisible()
|
|
|
|
|
await page.getByRole('button', { name: 'Restore' }).click()
|
|
|
|
|
await expect(page.getByText('Retained recovery rectangle')).toBeVisible()
|
|
|
|
|
|
|
|
|
|
await context.close()
|
|
|
|
|
})
|
2026-09-10 19:57:45 +00:00
|
|
|
|
|
|
|
|
test('discards a closed tab snapshot in auto-recover mode', async ({ browser, baseURL }) => {
|
|
|
|
|
const context = await browser.newContext({ baseURL })
|
|
|
|
|
const page = await context.newPage()
|
|
|
|
|
await page.goto('/?recover=auto')
|
|
|
|
|
const canvas = new CanvasHelper(page)
|
|
|
|
|
await canvas.waitForInit()
|
|
|
|
|
|
|
|
|
|
await page.evaluate(async () => {
|
|
|
|
|
const store = window.openPencil?.getStore?.()
|
|
|
|
|
if (!store) throw new Error('OpenPencil store not initialized')
|
|
|
|
|
const id = store.createShape('RECTANGLE', 120, 120, 240, 140)
|
|
|
|
|
await store.persistRecoveryNow()
|
|
|
|
|
store.updateNode(id, { name: 'Closed tab rectangle' })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await page.keyboard.press('ControlOrMeta+t')
|
|
|
|
|
await page.getByTestId('tabbar-tab').first().getByTestId('tabbar-close').click()
|
|
|
|
|
|
|
|
|
|
// Auto-recover mode must drop the snapshot instead of retaining it, otherwise
|
|
|
|
|
// the silently-restored document resurrects the closed tab on every reload.
|
|
|
|
|
await expect.poll(() => recoverySnapshotCount(page)).toBe(0)
|
|
|
|
|
|
|
|
|
|
await page.reload()
|
|
|
|
|
await expect(page.getByRole('alertdialog', { name: 'Recover unsaved work' })).toBeHidden()
|
|
|
|
|
await expect(page.getByText('Closed tab rectangle')).toHaveCount(0)
|
|
|
|
|
|
|
|
|
|
await context.close()
|
|
|
|
|
})
|