|
|
@@ -463,9 +463,8 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
|
|
}, 60_000)
|
|
|
|
|
|
/**
|
|
|
- * Expand Ungrouped and return its seeded session row. The only visible child
|
|
|
- * is the non-blank persisted Session; the blank Session created while
|
|
|
- * adopting the Workspace stays hidden.
|
|
|
+ * Expand Ungrouped and return its only non-blank session row. A selected
|
|
|
+ * blank Session from a deleted Workspace may also be visible, without actions.
|
|
|
* @returns the session row locator, already present.
|
|
|
*/
|
|
|
async function seededSessionRow() {
|
|
|
@@ -480,9 +479,11 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
|
|
}
|
|
|
return await ungroupedRow.getAttribute('aria-expanded')
|
|
|
}, { timeout: 5_000 }).toBe('true')
|
|
|
- const row = ungroupedSection.locator('[role="treeitem"]').nth(1)
|
|
|
- await row.waitFor({ timeout: 10_000 })
|
|
|
- return row
|
|
|
+ // CSS includes the actions button while it is hidden until row hover.
|
|
|
+ const rows = ungroupedSection.locator('[role="treeitem"]')
|
|
|
+ .filter({ has: page.locator('button[aria-label^="Session actions for "]') })
|
|
|
+ await expect.poll(() => rows.count(), { timeout: 10_000 }).toBe(1)
|
|
|
+ return rows.first()
|
|
|
}
|
|
|
|
|
|
it('shows the session hover card after a dwell on the row', async () => {
|
|
|
@@ -552,26 +553,13 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
|
|
|
|
|
it('archives the seeded session from its row menu, hiding it durably across reload', async () => {
|
|
|
onTestFailed(() => saveFailureShot(page, 'web-e2e-ws-archive'))
|
|
|
- // The seeded session lives under Ungrouped (expanded by the hover-card
|
|
|
- // test's gesture; converge again for order independence).
|
|
|
- const ungroupedRow = page.getByText('Ungrouped', { exact: true }).locator('..').locator('..')
|
|
|
- const ungroupedSection = ungroupedRow.locator('..')
|
|
|
- await expect.poll(async () => {
|
|
|
- if (await ungroupedRow.getAttribute('aria-expanded') !== 'true') {
|
|
|
- await page.getByText('Ungrouped', { exact: true }).click()
|
|
|
- await page.waitForTimeout(50)
|
|
|
- }
|
|
|
- return await ungroupedRow.getAttribute('aria-expanded')
|
|
|
- }, { timeout: 5_000 }).toBe('true')
|
|
|
- // Anchor on session rows (the rows carrying a session actions button),
|
|
|
- // not a positional index, and assert the single-stray assumption loudly
|
|
|
- // so a fixture gaining a second stray fails here instead of archiving
|
|
|
- // the wrong row. CSS attribute match, not getByRole: the button is
|
|
|
- // display:none until its row hovers, and role queries skip hidden nodes.
|
|
|
- const sessionRows = ungroupedSection.locator('[role="treeitem"]')
|
|
|
- .filter({ has: page.locator('button[aria-label^="Session actions for "]') })
|
|
|
- await expect.poll(() => sessionRows.count(), { timeout: 10_000 }).toBe(1)
|
|
|
- const sessionRow = sessionRows.first()
|
|
|
+ const sessionRow = await seededSessionRow()
|
|
|
+ // Selecting the seed hides any blank stray left by Workspace deletion,
|
|
|
+ // so archiving this last visible Ungrouped Session must remove the bucket.
|
|
|
+ await sessionRow.click()
|
|
|
+ await expect.poll(() => sessionRow.getAttribute('aria-selected'), { timeout: 10_000 }).toBe('true')
|
|
|
+ const ungroupedSection = page.getByText('Ungrouped', { exact: true }).locator('..').locator('..').locator('..')
|
|
|
+ await expect.poll(() => ungroupedSection.locator('[role="treeitem"]').count(), { timeout: 10_000 }).toBe(2)
|
|
|
const rowTitle = await sessionRow.locator('[class*="title"]').innerText()
|
|
|
// Row menu: hover reveals the actions button; Archive session commits
|
|
|
// without a confirmation dialog (non-destructive: log + accounting stay).
|