|
1 | 1 | import { test, expect } from "../fixtures" |
2 | | -import { openSidebar, toggleSidebar, withSession } from "../actions" |
| 2 | +import { openSidebar, toggleSidebar, withSession, seedMessage } from "../actions" |
3 | 3 | import { sessionItemSelector } from "../selectors" |
4 | 4 |
|
5 | 5 | test("sidebar can be collapsed and expanded", async ({ page, gotoSession }) => { |
@@ -109,23 +109,6 @@ test("root session has no back arrow or subagent indicator", async ({ page, sdk, |
109 | 109 | }) |
110 | 110 | }) |
111 | 111 |
|
112 | | -async function seedMessage(sdk: Parameters<typeof withSession>[0], sessionID: string) { |
113 | | - await sdk.session.promptAsync({ |
114 | | - sessionID, |
115 | | - noReply: true, |
116 | | - parts: [{ type: "text", text: "e2e seed" }], |
117 | | - }) |
118 | | - await expect |
119 | | - .poll( |
120 | | - async () => { |
121 | | - const messages = await sdk.session.messages({ sessionID, limit: 1 }).then((r) => r.data ?? []) |
122 | | - return messages.length |
123 | | - }, |
124 | | - { timeout: 30_000 }, |
125 | | - ) |
126 | | - .toBeGreaterThan(0) |
127 | | -} |
128 | | - |
129 | 112 | test("subagent session shows back arrow and subagent indicator, and navigates to parent", async ({ |
130 | 113 | page, |
131 | 114 | sdk, |
@@ -208,3 +191,96 @@ test("navigating to parent session shows background only on parent", async ({ pa |
208 | 191 | } |
209 | 192 | }) |
210 | 193 | }) |
| 194 | + |
| 195 | +test("deeply nested sessions can be expanded and collapsed at each level", async ({ page, sdk, gotoSession }) => { |
| 196 | + await withSession(sdk, "grandparent session", async (grandparent) => { |
| 197 | + const parent = await sdk.session.create({ title: "parent session", parentID: grandparent.id }).then((r) => r.data) |
| 198 | + if (!parent?.id) throw new Error("Failed to create parent session") |
| 199 | + |
| 200 | + const child = await sdk.session.create({ title: "child session", parentID: parent.id }).then((r) => r.data) |
| 201 | + if (!child?.id) throw new Error("Failed to create child session") |
| 202 | + |
| 203 | + const grandchild = await sdk.session.create({ title: "grandchild session", parentID: child.id }).then((r) => r.data) |
| 204 | + if (!grandchild?.id) throw new Error("Failed to create grandchild session") |
| 205 | + |
| 206 | + try { |
| 207 | + await gotoSession(grandparent.id) |
| 208 | + await openSidebar(page) |
| 209 | + |
| 210 | + const grandparentItem = page.locator(sessionItemSelector(grandparent.id)) |
| 211 | + const parentItem = page.locator(sessionItemSelector(parent.id)) |
| 212 | + const childItem = page.locator(sessionItemSelector(child.id)) |
| 213 | + const grandchildItem = page.locator(sessionItemSelector(grandchild.id)) |
| 214 | + |
| 215 | + await expect(grandparentItem).toBeVisible() |
| 216 | + await expect(parentItem).not.toBeVisible() |
| 217 | + |
| 218 | + const grandparentChevron = grandparentItem.locator('[data-slot="collapsible-trigger"]').first() |
| 219 | + await grandparentChevron.click() |
| 220 | + await expect(parentItem).toBeVisible() |
| 221 | + await expect(childItem).not.toBeVisible() |
| 222 | + |
| 223 | + const parentChevron = parentItem.locator('[data-slot="collapsible-trigger"]').first() |
| 224 | + await parentChevron.click() |
| 225 | + await expect(childItem).toBeVisible() |
| 226 | + await expect(grandchildItem).not.toBeVisible() |
| 227 | + |
| 228 | + const childChevron = childItem.locator('[data-slot="collapsible-trigger"]').first() |
| 229 | + await childChevron.click() |
| 230 | + await expect(grandchildItem).toBeVisible() |
| 231 | + |
| 232 | + await childChevron.click() |
| 233 | + await expect(grandchildItem).not.toBeVisible() |
| 234 | + |
| 235 | + await parentChevron.click() |
| 236 | + await expect(childItem).not.toBeVisible() |
| 237 | + await expect(grandchildItem).not.toBeVisible() |
| 238 | + |
| 239 | + await grandparentChevron.click() |
| 240 | + await expect(parentItem).not.toBeVisible() |
| 241 | + } finally { |
| 242 | + await sdk.session.delete({ sessionID: grandchild.id }).catch(() => undefined) |
| 243 | + await sdk.session.delete({ sessionID: child.id }).catch(() => undefined) |
| 244 | + await sdk.session.delete({ sessionID: parent.id }).catch(() => undefined) |
| 245 | + } |
| 246 | + }) |
| 247 | +}) |
| 248 | + |
| 249 | +test("parent with archived child has no chevron", async ({ page, sdk, gotoSession }) => { |
| 250 | + await withSession(sdk, "parent session", async (parent) => { |
| 251 | + const child = await sdk.session.create({ title: "child session", parentID: parent.id }).then((r) => r.data) |
| 252 | + if (!child?.id) throw new Error("Failed to create child session") |
| 253 | + |
| 254 | + try { |
| 255 | + await seedMessage(sdk, child.id) |
| 256 | + await gotoSession(parent.id) |
| 257 | + await openSidebar(page) |
| 258 | + |
| 259 | + const parentItem = page.locator(sessionItemSelector(parent.id)) |
| 260 | + const childItem = page.locator(sessionItemSelector(child.id)) |
| 261 | + const chevron = parentItem.locator('[data-slot="collapsible-trigger"]') |
| 262 | + |
| 263 | + await expect(chevron).toBeVisible() |
| 264 | + |
| 265 | + await chevron.click() |
| 266 | + await expect(childItem).toBeVisible() |
| 267 | + |
| 268 | + await sdk.session.update({ sessionID: child.id, time: { archived: Date.now() } }) |
| 269 | + |
| 270 | + await page.reload() |
| 271 | + await openSidebar(page) |
| 272 | + |
| 273 | + await expect(parentItem).toBeVisible() |
| 274 | + await expect(chevron).not.toBeVisible() |
| 275 | + |
| 276 | + await gotoSession(child.id) |
| 277 | + await expect(page).toHaveURL(new RegExp(`/session/${child.id}`)) |
| 278 | + |
| 279 | + const navigateParent = page.getByTestId("navigate-parent-button") |
| 280 | + await expect(navigateParent).toBeVisible() |
| 281 | + } finally { |
| 282 | + await sdk.session.update({ sessionID: child.id, time: { archived: undefined } }).catch(() => undefined) |
| 283 | + await sdk.session.delete({ sessionID: child.id }).catch(() => undefined) |
| 284 | + } |
| 285 | + }) |
| 286 | +}) |
0 commit comments