|
|
@@ -0,0 +1,175 @@
|
|
|
+import { beforeAll, beforeEach, describe, expect, mock, test } from "bun:test"
|
|
|
+import type { Prompt } from "@/context/prompt"
|
|
|
+
|
|
|
+let createPromptSubmit: typeof import("./submit").createPromptSubmit
|
|
|
+
|
|
|
+const createdClients: string[] = []
|
|
|
+const createdSessions: string[] = []
|
|
|
+const sentShell: string[] = []
|
|
|
+const syncedDirectories: string[] = []
|
|
|
+
|
|
|
+let selected = "/repo/worktree-a"
|
|
|
+
|
|
|
+const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }]
|
|
|
+
|
|
|
+const clientFor = (directory: string) => ({
|
|
|
+ session: {
|
|
|
+ create: async () => {
|
|
|
+ createdSessions.push(directory)
|
|
|
+ return { data: { id: `session-${createdSessions.length}` } }
|
|
|
+ },
|
|
|
+ shell: async () => {
|
|
|
+ sentShell.push(directory)
|
|
|
+ return { data: undefined }
|
|
|
+ },
|
|
|
+ prompt: async () => ({ data: undefined }),
|
|
|
+ command: async () => ({ data: undefined }),
|
|
|
+ abort: async () => ({ data: undefined }),
|
|
|
+ },
|
|
|
+ worktree: {
|
|
|
+ create: async () => ({ data: { directory: `${directory}/new` } }),
|
|
|
+ },
|
|
|
+})
|
|
|
+
|
|
|
+beforeAll(async () => {
|
|
|
+ const rootClient = clientFor("/repo/main")
|
|
|
+
|
|
|
+ mock.module("@solidjs/router", () => ({
|
|
|
+ useNavigate: () => () => undefined,
|
|
|
+ useParams: () => ({}),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@opencode-ai/sdk/v2/client", () => ({
|
|
|
+ createOpencodeClient: (input: { directory: string }) => {
|
|
|
+ createdClients.push(input.directory)
|
|
|
+ return clientFor(input.directory)
|
|
|
+ },
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@opencode-ai/ui/toast", () => ({
|
|
|
+ showToast: () => 0,
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@opencode-ai/util/encode", () => ({
|
|
|
+ base64Encode: (value: string) => value,
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/local", () => ({
|
|
|
+ useLocal: () => ({
|
|
|
+ model: {
|
|
|
+ current: () => ({ id: "model", provider: { id: "provider" } }),
|
|
|
+ variant: { current: () => undefined },
|
|
|
+ },
|
|
|
+ agent: {
|
|
|
+ current: () => ({ name: "agent" }),
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/prompt", () => ({
|
|
|
+ usePrompt: () => ({
|
|
|
+ current: () => promptValue,
|
|
|
+ reset: () => undefined,
|
|
|
+ set: () => undefined,
|
|
|
+ context: {
|
|
|
+ add: () => undefined,
|
|
|
+ remove: () => undefined,
|
|
|
+ items: () => [],
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/layout", () => ({
|
|
|
+ useLayout: () => ({
|
|
|
+ handoff: {
|
|
|
+ setTabs: () => undefined,
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/sdk", () => ({
|
|
|
+ useSDK: () => ({
|
|
|
+ directory: "/repo/main",
|
|
|
+ client: rootClient,
|
|
|
+ url: "http://localhost:4096",
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/sync", () => ({
|
|
|
+ useSync: () => ({
|
|
|
+ data: { command: [] },
|
|
|
+ session: {
|
|
|
+ optimistic: {
|
|
|
+ add: () => undefined,
|
|
|
+ remove: () => undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ set: () => undefined,
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/global-sync", () => ({
|
|
|
+ useGlobalSync: () => ({
|
|
|
+ child: (directory: string) => {
|
|
|
+ syncedDirectories.push(directory)
|
|
|
+ return [{}, () => undefined]
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/platform", () => ({
|
|
|
+ usePlatform: () => ({
|
|
|
+ fetch: fetch,
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ mock.module("@/context/language", () => ({
|
|
|
+ useLanguage: () => ({
|
|
|
+ t: (key: string) => key,
|
|
|
+ }),
|
|
|
+ }))
|
|
|
+
|
|
|
+ const mod = await import("./submit")
|
|
|
+ createPromptSubmit = mod.createPromptSubmit
|
|
|
+})
|
|
|
+
|
|
|
+beforeEach(() => {
|
|
|
+ createdClients.length = 0
|
|
|
+ createdSessions.length = 0
|
|
|
+ sentShell.length = 0
|
|
|
+ syncedDirectories.length = 0
|
|
|
+ selected = "/repo/worktree-a"
|
|
|
+})
|
|
|
+
|
|
|
+describe("prompt submit worktree selection", () => {
|
|
|
+ test("reads the latest worktree accessor value per submit", async () => {
|
|
|
+ const submit = createPromptSubmit({
|
|
|
+ info: () => undefined,
|
|
|
+ imageAttachments: () => [],
|
|
|
+ commentCount: () => 0,
|
|
|
+ mode: () => "shell",
|
|
|
+ working: () => false,
|
|
|
+ editor: () => undefined,
|
|
|
+ queueScroll: () => undefined,
|
|
|
+ promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0),
|
|
|
+ addToHistory: () => undefined,
|
|
|
+ resetHistoryNavigation: () => undefined,
|
|
|
+ setMode: () => undefined,
|
|
|
+ setPopover: () => undefined,
|
|
|
+ newSessionWorktree: () => selected,
|
|
|
+ onNewSessionWorktreeReset: () => undefined,
|
|
|
+ onSubmit: () => undefined,
|
|
|
+ })
|
|
|
+
|
|
|
+ const event = { preventDefault: () => undefined } as unknown as Event
|
|
|
+
|
|
|
+ await submit.handleSubmit(event)
|
|
|
+ selected = "/repo/worktree-b"
|
|
|
+ await submit.handleSubmit(event)
|
|
|
+
|
|
|
+ expect(createdClients).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
|
|
|
+ expect(createdSessions).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
|
|
|
+ expect(sentShell).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
|
|
|
+ expect(syncedDirectories).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
|
|
|
+ })
|
|
|
+})
|