opencode/packages/app/test-browser/prompt-attachments.test.ts

90 lines
3.3 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { createRoot } from "solid-js"
import { createPromptAttachmentsCore } from "@/components/prompt-input/attachments"
import { createPromptState } from "@/context/prompt"
describe("prompt attachment session ownership", () => {
test("adds an asynchronously read image to the session where the read started", async () => {
await createRoot(async (dispose) => {
const sessions = { A: createPromptState(), B: createPromptState() }
let active: "A" | "B" = "A"
const attachments = createPromptAttachmentsCore({
capture: () => sessions[active].capture(),
editor: () => document.createElement("div"),
})
const pending = attachments.addAttachment(new File([new Uint8Array(1024 * 1024)], "a.png", { type: "image/png" }))
active = "B"
await pending
expect(images(sessions.A)).toHaveLength(1)
expect(images(sessions.B)).toHaveLength(0)
dispose()
})
})
test("finishes the captured attachment after the active editor is removed", async () => {
await createRoot(async (dispose) => {
const prompt = createPromptState()
let editor: HTMLDivElement | undefined = document.createElement("div")
const attachments = createPromptAttachmentsCore({
capture: prompt.capture,
editor: () => editor,
})
const pending = attachments.addAttachment(new File([new Uint8Array(1024 * 1024)], "a.png", { type: "image/png" }))
editor = undefined
await pending
expect(images(prompt)).toHaveLength(1)
dispose()
})
})
test("keeps every file in a batch on the session where the batch started", async () => {
await createRoot(async (dispose) => {
const sessions = { A: createPromptState(), B: createPromptState() }
let active: "A" | "B" = "A"
const attachments = createPromptAttachmentsCore({
capture: () => sessions[active].capture(),
editor: () => document.createElement("div"),
})
const pending = attachments.addAttachments([
new File([new Uint8Array(1024 * 1024)], "first.png", { type: "image/png" }),
new File([new Uint8Array(1024 * 1024)], "second.png", { type: "image/png" }),
])
active = "B"
await pending
expect(images(sessions.A)).toHaveLength(2)
expect(images(sessions.B)).toHaveLength(0)
dispose()
})
})
test("keeps a delayed native clipboard image on the session where paste started", async () => {
await createRoot(async (dispose) => {
const sessions = { A: createPromptState(), B: createPromptState() }
const read = Promise.withResolvers<File | null>()
let active: "A" | "B" = "A"
const attachments = createPromptAttachmentsCore({
capture: () => sessions[active].capture(),
editor: () => document.createElement("div"),
})
const pending = attachments.addClipboardAttachment(read.promise)
active = "B"
read.resolve(new File([new Uint8Array(1024 * 1024)], "clipboard.png", { type: "image/png" }))
await pending
expect(images(sessions.A)).toHaveLength(1)
expect(images(sessions.B)).toHaveLength(0)
dispose()
})
})
})
function images(prompt: ReturnType<typeof createPromptState>) {
return prompt.current().filter((part) => part.type === "image")
}