Files
hapi/e2e/session-title-lock.spec.ts
T
AnanovoandGitHub 577ab7546b feat(sessions): add explicit per-session title locks (#2072)
* feat(sessions): add explicit per-session title locks

* fix(sessions): preserve title locks across rename entry points
2026-10-28 12:14:48 +08:00

60 lines
3.9 KiB
TypeScript

import { expect, test } from '@playwright/test'
for (const width of [320, 390, 1280]) {
for (const locale of ['en', 'zh-CN']) {
test(`title lock draft, persistence and layout at ${width}px ${locale}`, async ({ page }, testInfo) => {
await page.setViewportSize({ width, height: 900 })
await page.addInitScript((language) => {
localStorage.setItem('hapi-lang', language)
document.documentElement.style.setProperty('--app-font-scale', '1.3')
}, locale)
await page.goto('/e2e-fixtures/session-title-lock-fixture.html')
await page.getByRole('button', { name: 'Rename 1', exact: true }).click()
const dialog = page.getByRole('dialog')
const lock = dialog.getByRole('button', { name: locale === 'en' ? 'Lock title against agent updates' : '锁定标题,阻止 AI 更新' })
const save = dialog.getByRole('button', { name: locale === 'en' ? 'Save' : '保存', exact: true })
const cancel = dialog.getByRole('button', { name: locale === 'en' ? 'Cancel' : '取消', exact: true })
await expect(lock).toHaveAttribute('aria-pressed', 'false')
await lock.click()
await expect(page.getByTestId('session-0')).toContainText('"locked":false')
await cancel.click()
await expect(dialog).not.toBeVisible()
await page.getByRole('button', { name: 'Rename 1', exact: true }).click()
await expect(lock).toHaveAttribute('aria-pressed', 'false')
await dialog.getByRole('textbox').fill('A deliberately long user title 测试标题')
await lock.click()
const bounds = await dialog.boundingBox()
expect(bounds!.x).toBeGreaterThanOrEqual(0)
expect(bounds!.x + bounds!.width).toBeLessThanOrEqual(width)
const inputBounds = await dialog.getByRole('textbox').boundingBox()
const lockBounds = await lock.boundingBox()
expect(lockBounds!.width).toBeGreaterThanOrEqual(40)
expect(lockBounds!.x + lockBounds!.width).toBeLessThanOrEqual(inputBounds!.x + inputBounds!.width + 1)
await page.screenshot({ path: testInfo.outputPath(`title-lock-${width}-${locale}.png`) })
await save.click()
await expect(dialog).not.toBeVisible()
await expect(page.getByTestId('session-0')).toContainText('"locked":true')
// Exercise the second production entry point, not just the isolated dialog.
await page.getByRole('button', { name: 'Show session list' }).click()
await page.getByRole('button', { name: /A deliberately long user title/ }).click({ button: 'right' })
await page.getByRole('menuitem', { name: locale === 'en' ? 'Rename' : '重命名', exact: true }).click()
await expect(lock).toHaveAttribute('aria-pressed', 'true')
await dialog.getByRole('textbox').fill('Human edit while locked')
await save.click()
await expect(dialog).not.toBeVisible()
await expect(page.getByTestId('session-0')).toContainText('Human edit while locked')
await expect(page.getByTestId('session-0')).toContainText('"locked":true')
await page.getByRole('button', { name: 'Rename 2', exact: true }).click()
await expect(lock).toHaveAttribute('aria-pressed', 'false')
await cancel.click()
await page.getByRole('button', { name: 'Rename 1', exact: true }).click()
await expect(lock).toHaveAttribute('aria-pressed', 'true')
await lock.press('Space')
await expect(lock).toHaveAttribute('aria-pressed', 'false')
await save.click()
await expect(page.getByTestId('session-0')).toContainText('"locked":false')
await expect(page.getByTestId('session-0')).toContainText('Human edit while locked')
})
}
}