fix(web): preserve saved writes across refresh failures

This commit is contained in:
2026-07-22 13:13:03 +08:00
parent 7980943660
commit 89d2f4659f
11 changed files with 304 additions and 74 deletions

View File

@@ -684,13 +684,31 @@ if (await mobileSearchButton.count() !== 1) {
failures.push('390px workspace must provide one global search entry')
} else {
await mobileSearchButton.click()
await page.getByPlaceholder('搜索项目、任务和笔记').waitFor({ state: 'visible' })
const mobileSearchInput = page.getByPlaceholder('搜索项目、任务和笔记')
await mobileSearchInput.waitFor({ state: 'visible' })
await mobileSearchInput.fill('回调')
await mobileSearchInput.press('Enter')
const mobileSearchResult = page.getByRole('button', { name: /回调任务/ })
await mobileSearchResult.waitFor({ state: 'visible', timeout: 2000 }).catch(() => {})
if (!await mobileSearchResult.isVisible().catch(() => false)) {
failures.push('390px search must keep its result panel visible after submit')
} else {
const mobileSearchLayerVisible = await page.evaluate(() => {
const search = document.querySelector('.global-search')
return Boolean(search && getComputedStyle(search).display !== 'none')
})
if (!mobileSearchLayerVisible) failures.push('390px search must keep its input layer anchored until result selection')
await page.screenshot({ path: 'test-results/workbench-mobile-search-results.png' })
await mobileSearchResult.click()
const mobileActiveChannel = await page.locator('.channel-button.active').textContent().catch(() => '')
if (!mobileActiveChannel?.includes('工作计划')) {
failures.push('390px search result selection must navigate to its task channel')
}
if (await page.getByRole('button', { name: '关闭全局搜索', exact: true }).count() !== 0) {
failures.push('390px search panel must close after selecting a result')
}
}
await page.screenshot({ path: 'test-results/workbench-mobile-search.png' })
await page.getByRole('button', { name: '关闭全局搜索', exact: true }).click()
await page.waitForFunction(() => {
const search = document.querySelector('.global-search')
return search && getComputedStyle(search).display === 'none'
})
}
await page.setViewportSize({ width: 1440, height: 1024 })
@@ -1193,6 +1211,16 @@ if (await inboxChannelButton.count() === 0) {
if (!await secondConfirmButton.isDisabled()) {
failures.push('a confirmed item must remain non-repeatable when its workspace refresh fails')
}
const recoveryRefreshButton = page.getByRole('button', { name: '刷新数据', exact: true })
if (!await recoveryRefreshButton.isVisible().catch(() => false)) {
failures.push('a saved write with a failed refresh must provide an actionable recovery refresh')
} else {
await recoveryRefreshButton.click()
await recoveryRefreshButton.waitFor({ state: 'hidden', timeout: 2000 }).catch(() => {})
if (await recoveryRefreshButton.isVisible().catch(() => false)) {
failures.push('a successful recovery refresh must clear its warning action')
}
}
expectingInboxRefreshError = false
if (expectedInboxRefreshConsoleErrorCount !== 1) {
failures.push(`expected one simulated Inbox refresh console error, got ${expectedInboxRefreshConsoleErrorCount}`)