summaryrefslogtreecommitdiffhomepage
path: root/packages/app/e2e/session
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-01 13:15:42 -0400
committerGitHub <[email protected]>2026-04-01 13:15:42 -0400
commitc559af51ced7c47ccb55ece0de1bfee37a74e552 (patch)
treedb85d2ccf556b9266ac4f1a24c47f3e5e9795f70 /packages/app/e2e/session
parentd1e0a4640c5d10a689f242ad6a811b8c8e7a5fe8 (diff)
downloadopencode-c559af51ced7c47ccb55ece0de1bfee37a74e552.tar.gz
opencode-c559af51ced7c47ccb55ece0de1bfee37a74e552.zip
test(app): migrate more e2e suites to isolated backend (#20505)
Diffstat (limited to 'packages/app/e2e/session')
-rw-r--r--packages/app/e2e/session/session-child-navigation.spec.ts46
-rw-r--r--packages/app/e2e/session/session-composer-dock.spec.ts570
-rw-r--r--packages/app/e2e/session/session-undo-redo.spec.ts18
-rw-r--r--packages/app/e2e/session/session.spec.ts236
4 files changed, 452 insertions, 418 deletions
diff --git a/packages/app/e2e/session/session-child-navigation.spec.ts b/packages/app/e2e/session/session-child-navigation.spec.ts
index ac2dca33c..616f694a3 100644
--- a/packages/app/e2e/session/session-child-navigation.spec.ts
+++ b/packages/app/e2e/session/session-child-navigation.spec.ts
@@ -1,7 +1,7 @@
import { seedSessionTask, withSession } from "../actions"
import { test, expect } from "../fixtures"
-test("task tool child-session link does not trigger stale show errors", async ({ page, sdk, gotoSession }) => {
+test("task tool child-session link does not trigger stale show errors", async ({ page, withBackendProject }) => {
test.setTimeout(120_000)
const errs: string[] = []
@@ -10,28 +10,32 @@ test("task tool child-session link does not trigger stale show errors", async ({
}
page.on("pageerror", onError)
- await withSession(sdk, `e2e child nav ${Date.now()}`, async (session) => {
- const child = await seedSessionTask(sdk, {
- sessionID: session.id,
- description: "Open child session",
- prompt: "Search the repository for AssistantParts and then reply with exactly CHILD_OK.",
- })
+ await withBackendProject(async ({ gotoSession, trackSession, sdk }) => {
+ await withSession(sdk, `e2e child nav ${Date.now()}`, async (session) => {
+ trackSession(session.id)
+ const child = await seedSessionTask(sdk, {
+ sessionID: session.id,
+ description: "Open child session",
+ prompt: "Search the repository for AssistantParts and then reply with exactly CHILD_OK.",
+ })
+ trackSession(child.sessionID)
- try {
- await gotoSession(session.id)
+ try {
+ await gotoSession(session.id)
- const link = page
- .locator("a.subagent-link")
- .filter({ hasText: /open child session/i })
- .first()
- await expect(link).toBeVisible({ timeout: 30_000 })
- await link.click()
+ const link = page
+ .locator("a.subagent-link")
+ .filter({ hasText: /open child session/i })
+ .first()
+ await expect(link).toBeVisible({ timeout: 30_000 })
+ await link.click()
- await expect(page).toHaveURL(new RegExp(`/session/${child.sessionID}(?:[/?#]|$)`), { timeout: 30_000 })
- await page.waitForTimeout(1000)
- expect(errs).toEqual([])
- } finally {
- page.off("pageerror", onError)
- }
+ await expect(page).toHaveURL(new RegExp(`/session/${child.sessionID}(?:[/?#]|$)`), { timeout: 30_000 })
+ await page.waitForTimeout(1000)
+ expect(errs).toEqual([])
+ } finally {
+ page.off("pageerror", onError)
+ }
+ })
})
})
diff --git a/packages/app/e2e/session/session-composer-dock.spec.ts b/packages/app/e2e/session/session-composer-dock.spec.ts
index c56079337..9d44683c8 100644
--- a/packages/app/e2e/session/session-composer-dock.spec.ts
+++ b/packages/app/e2e/session/session-composer-dock.spec.ts
@@ -256,350 +256,372 @@ async function withMockPermission<T>(
}
}
-test("default dock shows prompt input", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock default", async (session) => {
- await gotoSession(session.id)
-
- await expect(page.locator(sessionComposerDockSelector)).toBeVisible()
- await expect(page.locator(promptSelector)).toBeVisible()
- await expect(page.locator(questionDockSelector)).toHaveCount(0)
- await expect(page.locator(permissionDockSelector)).toHaveCount(0)
-
- await page.locator(promptSelector).click()
- await expect(page.locator(promptSelector)).toBeFocused()
+test("default dock shows prompt input", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock default", async (session) => {
+ await project.gotoSession(session.id)
+
+ await expect(page.locator(sessionComposerDockSelector)).toBeVisible()
+ await expect(page.locator(promptSelector)).toBeVisible()
+ await expect(page.locator(questionDockSelector)).toHaveCount(0)
+ await expect(page.locator(permissionDockSelector)).toHaveCount(0)
+
+ await page.locator(promptSelector).click()
+ await expect(page.locator(promptSelector)).toBeFocused()
+ })
})
})
-test("auto-accept toggle works before first submit", async ({ page, gotoSession }) => {
- await gotoSession()
+test("auto-accept toggle works before first submit", async ({ page, withBackendProject }) => {
+ await withBackendProject(async ({ gotoSession }) => {
+ await gotoSession()
- const button = page.locator('[data-action="prompt-permissions"]').first()
- await expect(button).toBeVisible()
- await expect(button).toHaveAttribute("aria-pressed", "false")
+ const button = page.locator('[data-action="prompt-permissions"]').first()
+ await expect(button).toBeVisible()
+ await expect(button).toHaveAttribute("aria-pressed", "false")
- await setAutoAccept(page, true)
- await setAutoAccept(page, false)
+ await setAutoAccept(page, true)
+ await setAutoAccept(page, false)
+ })
})
-test("blocked question flow unblocks after submit", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock question", async (session) => {
- await withDockSeed(sdk, session.id, async () => {
- await gotoSession(session.id)
+test("blocked question flow unblocks after submit", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock question", async (session) => {
+ await withDockSeed(project.sdk, session.id, async () => {
+ await project.gotoSession(session.id)
- await seedSessionQuestion(sdk, {
- sessionID: session.id,
- questions: [
- {
- header: "Need input",
- question: "Pick one option",
- options: [
- { label: "Continue", description: "Continue now" },
- { label: "Stop", description: "Stop here" },
- ],
- },
- ],
- })
+ await seedSessionQuestion(project.sdk, {
+ sessionID: session.id,
+ questions: [
+ {
+ header: "Need input",
+ question: "Pick one option",
+ options: [
+ { label: "Continue", description: "Continue now" },
+ { label: "Stop", description: "Stop here" },
+ ],
+ },
+ ],
+ })
- const dock = page.locator(questionDockSelector)
- await expectQuestionBlocked(page)
+ const dock = page.locator(questionDockSelector)
+ await expectQuestionBlocked(page)
- await dock.locator('[data-slot="question-option"]').first().click()
- await dock.getByRole("button", { name: /submit/i }).click()
+ await dock.locator('[data-slot="question-option"]').first().click()
+ await dock.getByRole("button", { name: /submit/i }).click()
- await expectQuestionOpen(page)
+ await expectQuestionOpen(page)
+ })
})
})
})
-test("blocked question flow supports keyboard shortcuts", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock question keyboard", async (session) => {
- await withDockSeed(sdk, session.id, async () => {
- await gotoSession(session.id)
-
- await seedSessionQuestion(sdk, {
- sessionID: session.id,
- questions: [
- {
- header: "Need input",
- question: "Pick one option",
- options: [
- { label: "Continue", description: "Continue now" },
- { label: "Stop", description: "Stop here" },
- ],
- },
- ],
- })
-
- const dock = page.locator(questionDockSelector)
- const first = dock.locator('[data-slot="question-option"]').first()
- const second = dock.locator('[data-slot="question-option"]').nth(1)
+test("blocked question flow supports keyboard shortcuts", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock question keyboard", async (session) => {
+ await withDockSeed(project.sdk, session.id, async () => {
+ await project.gotoSession(session.id)
- await expectQuestionBlocked(page)
- await expect(first).toBeFocused()
+ await seedSessionQuestion(project.sdk, {
+ sessionID: session.id,
+ questions: [
+ {
+ header: "Need input",
+ question: "Pick one option",
+ options: [
+ { label: "Continue", description: "Continue now" },
+ { label: "Stop", description: "Stop here" },
+ ],
+ },
+ ],
+ })
- await page.keyboard.press("ArrowDown")
- await expect(second).toBeFocused()
+ const dock = page.locator(questionDockSelector)
+ const first = dock.locator('[data-slot="question-option"]').first()
+ const second = dock.locator('[data-slot="question-option"]').nth(1)
- await page.keyboard.press("Space")
- await page.keyboard.press(`${modKey}+Enter`)
- await expectQuestionOpen(page)
- })
- })
-})
+ await expectQuestionBlocked(page)
+ await expect(first).toBeFocused()
-test("blocked question flow supports escape dismiss", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock question escape", async (session) => {
- await withDockSeed(sdk, session.id, async () => {
- await gotoSession(session.id)
+ await page.keyboard.press("ArrowDown")
+ await expect(second).toBeFocused()
- await seedSessionQuestion(sdk, {
- sessionID: session.id,
- questions: [
- {
- header: "Need input",
- question: "Pick one option",
- options: [
- { label: "Continue", description: "Continue now" },
- { label: "Stop", description: "Stop here" },
- ],
- },
- ],
+ await page.keyboard.press("Space")
+ await page.keyboard.press(`${modKey}+Enter`)
+ await expectQuestionOpen(page)
})
-
- const dock = page.locator(questionDockSelector)
- const first = dock.locator('[data-slot="question-option"]').first()
-
- await expectQuestionBlocked(page)
- await expect(first).toBeFocused()
-
- await page.keyboard.press("Escape")
- await expectQuestionOpen(page)
})
})
})
-test("blocked permission flow supports allow once", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock permission once", async (session) => {
- await gotoSession(session.id)
- await setAutoAccept(page, false)
- await withMockPermission(
- page,
- {
- id: "per_e2e_once",
- sessionID: session.id,
- permission: "bash",
- patterns: ["/tmp/opencode-e2e-perm-once"],
- metadata: { description: "Need permission for command" },
- },
- undefined,
- async (state) => {
- await page.goto(page.url())
- await expectPermissionBlocked(page)
-
- await clearPermissionDock(page, /allow once/i)
- await state.resolved()
- await page.goto(page.url())
- await expectPermissionOpen(page)
- },
- )
- })
-})
-
-test("blocked permission flow supports reject", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock permission reject", async (session) => {
- await gotoSession(session.id)
- await setAutoAccept(page, false)
- await withMockPermission(
- page,
- {
- id: "per_e2e_reject",
- sessionID: session.id,
- permission: "bash",
- patterns: ["/tmp/opencode-e2e-perm-reject"],
- },
- undefined,
- async (state) => {
- await page.goto(page.url())
- await expectPermissionBlocked(page)
-
- await clearPermissionDock(page, /deny/i)
- await state.resolved()
- await page.goto(page.url())
- await expectPermissionOpen(page)
- },
- )
- })
-})
-
-test("blocked permission flow supports allow always", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock permission always", async (session) => {
- await gotoSession(session.id)
- await setAutoAccept(page, false)
- await withMockPermission(
- page,
- {
- id: "per_e2e_always",
- sessionID: session.id,
- permission: "bash",
- patterns: ["/tmp/opencode-e2e-perm-always"],
- metadata: { description: "Need permission for command" },
- },
- undefined,
- async (state) => {
- await page.goto(page.url())
- await expectPermissionBlocked(page)
-
- await clearPermissionDock(page, /allow always/i)
- await state.resolved()
- await page.goto(page.url())
- await expectPermissionOpen(page)
- },
- )
- })
-})
-
-test("child session question request blocks parent dock and unblocks after submit", async ({
- page,
- sdk,
- gotoSession,
-}) => {
- await withDockSession(sdk, "e2e composer dock child question parent", async (session) => {
- await gotoSession(session.id)
-
- const child = await sdk.session
- .create({
- title: "e2e composer dock child question",
- parentID: session.id,
- })
- .then((r) => r.data)
- if (!child?.id) throw new Error("Child session create did not return an id")
+test("blocked question flow supports escape dismiss", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock question escape", async (session) => {
+ await withDockSeed(project.sdk, session.id, async () => {
+ await project.gotoSession(session.id)
- try {
- await withDockSeed(sdk, child.id, async () => {
- await seedSessionQuestion(sdk, {
- sessionID: child.id,
+ await seedSessionQuestion(project.sdk, {
+ sessionID: session.id,
questions: [
{
- header: "Child input",
- question: "Pick one child option",
+ header: "Need input",
+ question: "Pick one option",
options: [
- { label: "Continue", description: "Continue child" },
- { label: "Stop", description: "Stop child" },
+ { label: "Continue", description: "Continue now" },
+ { label: "Stop", description: "Stop here" },
],
},
],
})
const dock = page.locator(questionDockSelector)
- await expectQuestionBlocked(page)
+ const first = dock.locator('[data-slot="question-option"]').first()
- await dock.locator('[data-slot="question-option"]').first().click()
- await dock.getByRole("button", { name: /submit/i }).click()
+ await expectQuestionBlocked(page)
+ await expect(first).toBeFocused()
+ await page.keyboard.press("Escape")
await expectQuestionOpen(page)
})
- } finally {
- await cleanupSession({ sdk, sessionID: child.id })
- }
+ })
})
})
-test("child session permission request blocks parent dock and supports allow once", async ({
- page,
- sdk,
- gotoSession,
-}) => {
- await withDockSession(sdk, "e2e composer dock child permission parent", async (session) => {
- await gotoSession(session.id)
- await setAutoAccept(page, false)
+test("blocked permission flow supports allow once", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock permission once", async (session) => {
+ await project.gotoSession(session.id)
+ await setAutoAccept(page, false)
+ await withMockPermission(
+ page,
+ {
+ id: "per_e2e_once",
+ sessionID: session.id,
+ permission: "bash",
+ patterns: ["/tmp/opencode-e2e-perm-once"],
+ metadata: { description: "Need permission for command" },
+ },
+ undefined,
+ async (state) => {
+ await page.goto(page.url())
+ await expectPermissionBlocked(page)
- const child = await sdk.session
- .create({
- title: "e2e composer dock child permission",
- parentID: session.id,
- })
- .then((r) => r.data)
- if (!child?.id) throw new Error("Child session create did not return an id")
+ await clearPermissionDock(page, /allow once/i)
+ await state.resolved()
+ await page.goto(page.url())
+ await expectPermissionOpen(page)
+ },
+ )
+ })
+ })
+})
- try {
+test("blocked permission flow supports reject", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock permission reject", async (session) => {
+ await project.gotoSession(session.id)
+ await setAutoAccept(page, false)
await withMockPermission(
page,
{
- id: "per_e2e_child",
- sessionID: child.id,
+ id: "per_e2e_reject",
+ sessionID: session.id,
permission: "bash",
- patterns: ["/tmp/opencode-e2e-perm-child"],
- metadata: { description: "Need child permission" },
+ patterns: ["/tmp/opencode-e2e-perm-reject"],
},
- { child },
+ undefined,
async (state) => {
await page.goto(page.url())
await expectPermissionBlocked(page)
- await clearPermissionDock(page, /allow once/i)
+ await clearPermissionDock(page, /deny/i)
await state.resolved()
await page.goto(page.url())
+ await expectPermissionOpen(page)
+ },
+ )
+ })
+ })
+})
+
+test("blocked permission flow supports allow always", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock permission always", async (session) => {
+ await project.gotoSession(session.id)
+ await setAutoAccept(page, false)
+ await withMockPermission(
+ page,
+ {
+ id: "per_e2e_always",
+ sessionID: session.id,
+ permission: "bash",
+ patterns: ["/tmp/opencode-e2e-perm-always"],
+ metadata: { description: "Need permission for command" },
+ },
+ undefined,
+ async (state) => {
+ await page.goto(page.url())
+ await expectPermissionBlocked(page)
+ await clearPermissionDock(page, /allow always/i)
+ await state.resolved()
+ await page.goto(page.url())
await expectPermissionOpen(page)
},
)
- } finally {
- await cleanupSession({ sdk, sessionID: child.id })
- }
+ })
})
})
-test("todo dock transitions and collapse behavior", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock todo", async (session) => {
- const dock = await todoDock(page, session.id)
- await gotoSession(session.id)
- await expect(page.locator(sessionComposerDockSelector)).toBeVisible()
-
- try {
- await dock.open([
- { content: "first task", status: "pending", priority: "high" },
- { content: "second task", status: "in_progress", priority: "medium" },
- ])
- await dock.expectOpen(["pending", "in_progress"])
-
- await dock.collapse()
- await dock.expectCollapsed(["pending", "in_progress"])
-
- await dock.expand()
- await dock.expectOpen(["pending", "in_progress"])
-
- await dock.finish([
- { content: "first task", status: "completed", priority: "high" },
- { content: "second task", status: "cancelled", priority: "medium" },
- ])
- await dock.expectClosed()
- } finally {
- await dock.clear()
- }
+test("child session question request blocks parent dock and unblocks after submit", async ({
+ page,
+ withBackendProject,
+}) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock child question parent", async (session) => {
+ await project.gotoSession(session.id)
+
+ const child = await project.sdk.session
+ .create({
+ title: "e2e composer dock child question",
+ parentID: session.id,
+ })
+ .then((r) => r.data)
+ if (!child?.id) throw new Error("Child session create did not return an id")
+
+ try {
+ await withDockSeed(project.sdk, child.id, async () => {
+ await seedSessionQuestion(project.sdk, {
+ sessionID: child.id,
+ questions: [
+ {
+ header: "Child input",
+ question: "Pick one child option",
+ options: [
+ { label: "Continue", description: "Continue child" },
+ { label: "Stop", description: "Stop child" },
+ ],
+ },
+ ],
+ })
+
+ const dock = page.locator(questionDockSelector)
+ await expectQuestionBlocked(page)
+
+ await dock.locator('[data-slot="question-option"]').first().click()
+ await dock.getByRole("button", { name: /submit/i }).click()
+
+ await expectQuestionOpen(page)
+ })
+ } finally {
+ await cleanupSession({ sdk: project.sdk, sessionID: child.id })
+ }
+ })
})
})
-test("keyboard focus stays off prompt while blocked", async ({ page, sdk, gotoSession }) => {
- await withDockSession(sdk, "e2e composer dock keyboard", async (session) => {
- await withDockSeed(sdk, session.id, async () => {
- await gotoSession(session.id)
+test("child session permission request blocks parent dock and supports allow once", async ({
+ page,
+ withBackendProject,
+}) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock child permission parent", async (session) => {
+ await project.gotoSession(session.id)
+ await setAutoAccept(page, false)
+
+ const child = await project.sdk.session
+ .create({
+ title: "e2e composer dock child permission",
+ parentID: session.id,
+ })
+ .then((r) => r.data)
+ if (!child?.id) throw new Error("Child session create did not return an id")
- await seedSessionQuestion(sdk, {
- sessionID: session.id,
- questions: [
+ try {
+ await withMockPermission(
+ page,
{
- header: "Need input",
- question: "Pick one option",
- options: [{ label: "Continue", description: "Continue now" }],
+ id: "per_e2e_child",
+ sessionID: child.id,
+ permission: "bash",
+ patterns: ["/tmp/opencode-e2e-perm-child"],
+ metadata: { description: "Need child permission" },
},
- ],
- })
+ { child },
+ async (state) => {
+ await page.goto(page.url())
+ await expectPermissionBlocked(page)
+
+ await clearPermissionDock(page, /allow once/i)
+ await state.resolved()
+ await page.goto(page.url())
- await expectQuestionBlocked(page)
+ await expectPermissionOpen(page)
+ },
+ )
+ } finally {
+ await cleanupSession({ sdk: project.sdk, sessionID: child.id })
+ }
+ })
+ })
+})
+
+test("todo dock transitions and collapse behavior", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock todo", async (session) => {
+ const dock = await todoDock(page, session.id)
+ await project.gotoSession(session.id)
+ await expect(page.locator(sessionComposerDockSelector)).toBeVisible()
+
+ try {
+ await dock.open([
+ { content: "first task", status: "pending", priority: "high" },
+ { content: "second task", status: "in_progress", priority: "medium" },
+ ])
+ await dock.expectOpen(["pending", "in_progress"])
+
+ await dock.collapse()
+ await dock.expectCollapsed(["pending", "in_progress"])
+
+ await dock.expand()
+ await dock.expectOpen(["pending", "in_progress"])
+
+ await dock.finish([
+ { content: "first task", status: "completed", priority: "high" },
+ { content: "second task", status: "cancelled", priority: "medium" },
+ ])
+ await dock.expectClosed()
+ } finally {
+ await dock.clear()
+ }
+ })
+ })
+})
- await page.locator("main").click({ position: { x: 5, y: 5 } })
- await page.keyboard.type("abc")
- await expect(page.locator(promptSelector)).toHaveCount(0)
+test("keyboard focus stays off prompt while blocked", async ({ page, withBackendProject }) => {
+ await withBackendProject(async (project) => {
+ await withDockSession(project.sdk, "e2e composer dock keyboard", async (session) => {
+ await withDockSeed(project.sdk, session.id, async () => {
+ await project.gotoSession(session.id)
+
+ await seedSessionQuestion(project.sdk, {
+ sessionID: session.id,
+ questions: [
+ {
+ header: "Need input",
+ question: "Pick one option",
+ options: [{ label: "Continue", description: "Continue now" }],
+ },
+ ],
+ })
+
+ await expectQuestionBlocked(page)
+
+ await page.locator("main").click({ position: { x: 5, y: 5 } })
+ await page.keyboard.type("abc")
+ await expect(page.locator(promptSelector)).toHaveCount(0)
+ })
})
})
})
diff --git a/packages/app/e2e/session/session-undo-redo.spec.ts b/packages/app/e2e/session/session-undo-redo.spec.ts
index eb0840f7c..b3a75e0dd 100644
--- a/packages/app/e2e/session/session-undo-redo.spec.ts
+++ b/packages/app/e2e/session/session-undo-redo.spec.ts
@@ -49,13 +49,13 @@ async function seedConversation(input: {
return { prompt, userMessageID }
}
-test("slash undo sets revert and restores prior prompt", async ({ page, withProject }) => {
+test("slash undo sets revert and restores prior prompt", async ({ page, withBackendProject }) => {
test.setTimeout(120_000)
const token = `undo_${Date.now()}`
- await withProject(async (project) => {
- const sdk = createSdk(project.directory)
+ await withBackendProject(async (project) => {
+ const sdk = project.sdk
await withSession(sdk, `e2e undo ${Date.now()}`, async (session) => {
await project.gotoSession(session.id)
@@ -81,13 +81,13 @@ test("slash undo sets revert and restores prior prompt", async ({ page, withProj
})
})
-test("slash redo clears revert and restores latest state", async ({ page, withProject }) => {
+test("slash redo clears revert and restores latest state", async ({ page, withBackendProject }) => {
test.setTimeout(120_000)
const token = `redo_${Date.now()}`
- await withProject(async (project) => {
- const sdk = createSdk(project.directory)
+ await withBackendProject(async (project) => {
+ const sdk = project.sdk
await withSession(sdk, `e2e redo ${Date.now()}`, async (session) => {
await project.gotoSession(session.id)
@@ -128,14 +128,14 @@ test("slash redo clears revert and restores latest state", async ({ page, withPr
})
})
-test("slash undo/redo traverses multi-step revert stack", async ({ page, withProject }) => {
+test("slash undo/redo traverses multi-step revert stack", async ({ page, withBackendProject }) => {
test.setTimeout(120_000)
const firstToken = `undo_redo_first_${Date.now()}`
const secondToken = `undo_redo_second_${Date.now()}`
- await withProject(async (project) => {
- const sdk = createSdk(project.directory)
+ await withBackendProject(async (project) => {
+ const sdk = project.sdk
await withSession(sdk, `e2e undo redo stack ${Date.now()}`, async (session) => {
await project.gotoSession(session.id)
diff --git a/packages/app/e2e/session/session.spec.ts b/packages/app/e2e/session/session.spec.ts
index 68d992949..d56e83f2f 100644
--- a/packages/app/e2e/session/session.spec.ts
+++ b/packages/app/e2e/session/session.spec.ts
@@ -31,144 +31,152 @@ async function seedMessage(sdk: Sdk, sessionID: string) {
.toBeGreaterThan(0)
}
-test("session can be renamed via header menu", async ({ page, sdk, gotoSession }) => {
+test("session can be renamed via header menu", async ({ page, withBackendProject }) => {
const stamp = Date.now()
const originalTitle = `e2e rename test ${stamp}`
const renamedTitle = `e2e renamed ${stamp}`
- await withSession(sdk, originalTitle, async (session) => {
- await seedMessage(sdk, session.id)
- await gotoSession(session.id)
- await expect(page.getByRole("heading", { level: 1 }).first()).toHaveText(originalTitle)
-
- const menu = await openSessionMoreMenu(page, session.id)
- await clickMenuItem(menu, /rename/i)
-
- const input = page.locator(".scroll-view__viewport").locator(inlineInputSelector).first()
- await expect(input).toBeVisible()
- await expect(input).toBeFocused()
- await input.fill(renamedTitle)
- await expect(input).toHaveValue(renamedTitle)
- await input.press("Enter")
-
- await expect
- .poll(
- async () => {
- const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
- return data?.title
- },
- { timeout: 30_000 },
- )
- .toBe(renamedTitle)
-
- await expect(page.getByRole("heading", { level: 1 }).first()).toHaveText(renamedTitle)
+ await withBackendProject(async (project) => {
+ await withSession(project.sdk, originalTitle, async (session) => {
+ await seedMessage(project.sdk, session.id)
+ await project.gotoSession(session.id)
+ await expect(page.getByRole("heading", { level: 1 }).first()).toHaveText(originalTitle)
+
+ const menu = await openSessionMoreMenu(page, session.id)
+ await clickMenuItem(menu, /rename/i)
+
+ const input = page.locator(".scroll-view__viewport").locator(inlineInputSelector).first()
+ await expect(input).toBeVisible()
+ await expect(input).toBeFocused()
+ await input.fill(renamedTitle)
+ await expect(input).toHaveValue(renamedTitle)
+ await input.press("Enter")
+
+ await expect
+ .poll(
+ async () => {
+ const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
+ return data?.title
+ },
+ { timeout: 30_000 },
+ )
+ .toBe(renamedTitle)
+
+ await expect(page.getByRole("heading", { level: 1 }).first()).toHaveText(renamedTitle)
+ })
})
})
-test("session can be archived via header menu", async ({ page, sdk, gotoSession }) => {
+test("session can be archived via header menu", async ({ page, withBackendProject }) => {
const stamp = Date.now()
const title = `e2e archive test ${stamp}`
- await withSession(sdk, title, async (session) => {
- await seedMessage(sdk, session.id)
- await gotoSession(session.id)
- const menu = await openSessionMoreMenu(page, session.id)
- await clickMenuItem(menu, /archive/i)
-
- await expect
- .poll(
- async () => {
- const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
- return data?.time?.archived
- },
- { timeout: 30_000 },
- )
- .not.toBeUndefined()
-
- await openSidebar(page)
- await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
+ await withBackendProject(async (project) => {
+ await withSession(project.sdk, title, async (session) => {
+ await seedMessage(project.sdk, session.id)
+ await project.gotoSession(session.id)
+ const menu = await openSessionMoreMenu(page, session.id)
+ await clickMenuItem(menu, /archive/i)
+
+ await expect
+ .poll(
+ async () => {
+ const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
+ return data?.time?.archived
+ },
+ { timeout: 30_000 },
+ )
+ .not.toBeUndefined()
+
+ await openSidebar(page)
+ await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
+ })
})
})
-test("session can be deleted via header menu", async ({ page, sdk, gotoSession }) => {
+test("session can be deleted via header menu", async ({ page, withBackendProject }) => {
const stamp = Date.now()
const title = `e2e delete test ${stamp}`
- await withSession(sdk, title, async (session) => {
- await seedMessage(sdk, session.id)
- await gotoSession(session.id)
- const menu = await openSessionMoreMenu(page, session.id)
- await clickMenuItem(menu, /delete/i)
- await confirmDialog(page, /delete/i)
-
- await expect
- .poll(
- async () => {
- const data = await sdk.session
- .get({ sessionID: session.id })
- .then((r) => r.data)
- .catch(() => undefined)
- return data?.id
- },
- { timeout: 30_000 },
- )
- .toBeUndefined()
-
- await openSidebar(page)
- await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
+ await withBackendProject(async (project) => {
+ await withSession(project.sdk, title, async (session) => {
+ await seedMessage(project.sdk, session.id)
+ await project.gotoSession(session.id)
+ const menu = await openSessionMoreMenu(page, session.id)
+ await clickMenuItem(menu, /delete/i)
+ await confirmDialog(page, /delete/i)
+
+ await expect
+ .poll(
+ async () => {
+ const data = await project.sdk.session
+ .get({ sessionID: session.id })
+ .then((r) => r.data)
+ .catch(() => undefined)
+ return data?.id
+ },
+ { timeout: 30_000 },
+ )
+ .toBeUndefined()
+
+ await openSidebar(page)
+ await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
+ })
})
})
-test("session can be shared and unshared via header button", async ({ page, sdk, gotoSession }) => {
+test("session can be shared and unshared via header button", async ({ page, withBackendProject }) => {
test.skip(shareDisabled, "Share is disabled in this environment (OPENCODE_DISABLE_SHARE).")
const stamp = Date.now()
const title = `e2e share test ${stamp}`
- await withSession(sdk, title, async (session) => {
- await seedMessage(sdk, session.id)
- await gotoSession(session.id)
-
- const shared = await openSharePopover(page)
- const publish = shared.popoverBody.getByRole("button", { name: "Publish" }).first()
- await expect(publish).toBeVisible({ timeout: 30_000 })
- await publish.click()
-
- await expect(shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()).toBeVisible({
- timeout: 30_000,
- })
-
- await expect
- .poll(
- async () => {
- const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
- return data?.share?.url || undefined
- },
- { timeout: 30_000 },
- )
- .not.toBeUndefined()
-
- const unpublish = shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()
- await expect(unpublish).toBeVisible({ timeout: 30_000 })
- await unpublish.click()
-
- await expect(shared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
- timeout: 30_000,
- })
-
- await expect
- .poll(
- async () => {
- const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
- return data?.share?.url || undefined
- },
- { timeout: 30_000 },
- )
- .toBeUndefined()
-
- const unshared = await openSharePopover(page)
- await expect(unshared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
- timeout: 30_000,
+ await withBackendProject(async (project) => {
+ await withSession(project.sdk, title, async (session) => {
+ await seedMessage(project.sdk, session.id)
+ await project.gotoSession(session.id)
+
+ const shared = await openSharePopover(page)
+ const publish = shared.popoverBody.getByRole("button", { name: "Publish" }).first()
+ await expect(publish).toBeVisible({ timeout: 30_000 })
+ await publish.click()
+
+ await expect(shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()).toBeVisible({
+ timeout: 30_000,
+ })
+
+ await expect
+ .poll(
+ async () => {
+ const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
+ return data?.share?.url || undefined
+ },
+ { timeout: 30_000 },
+ )
+ .not.toBeUndefined()
+
+ const unpublish = shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()
+ await expect(unpublish).toBeVisible({ timeout: 30_000 })
+ await unpublish.click()
+
+ await expect(shared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
+ timeout: 30_000,
+ })
+
+ await expect
+ .poll(
+ async () => {
+ const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
+ return data?.share?.url || undefined
+ },
+ { timeout: 30_000 },
+ )
+ .toBeUndefined()
+
+ const unshared = await openSharePopover(page)
+ await expect(unshared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
+ timeout: 30_000,
+ })
})
})
})