mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-09 22:25:02 +03:00
99 lines
3.7 KiB
TypeScript
99 lines
3.7 KiB
TypeScript
import type { SessionMessageInfo } from "@opencode/client/promise"
|
|
import type { MotionKnob } from "@opencode/ui/motion-tuning"
|
|
import { expect, sourceURL, story } from "../../stories/playwright/story"
|
|
|
|
const source = (path: string) => sourceURL(new URL(path, import.meta.url))
|
|
|
|
const modules = {
|
|
fixture: source("./plugin-host.fixture.tsx"),
|
|
definition: source("../../gui-plugins/src/sources/index.ts"),
|
|
renderer: source("../../gui-plugins/src/sources/renderer.tsx"),
|
|
tuning: source("../../ui/src/motion-tuning.ts"),
|
|
}
|
|
|
|
// One turn: the user message the panel's tab is keyed by, and a reply that searched the web.
|
|
const messages: SessionMessageInfo[] = [
|
|
{ id: "main", type: "user", text: "Who made One Million Checkboxes?", time: { created: 1 } },
|
|
{
|
|
id: "msg_reply",
|
|
type: "assistant",
|
|
agent: "build",
|
|
model: { id: "claude-sonnet-4", providerID: "anthropic" },
|
|
time: { created: 2, completed: 3 },
|
|
content: [
|
|
{
|
|
type: "tool",
|
|
id: "call_search",
|
|
name: "websearch",
|
|
state: {
|
|
status: "completed",
|
|
input: { query: "one million checkboxes" },
|
|
content: [
|
|
{ type: "text", text: "## [One Million Checkboxes](https://eieio.games/blog/one-million-checkboxes)" },
|
|
],
|
|
},
|
|
time: { created: 2, ran: 2, completed: 3 },
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
story.beforeEach(async ({ mount }) => {
|
|
// Any story loads the app; the fixture mounts the real host beside it.
|
|
await mount("ui-line-comment--editor")
|
|
})
|
|
|
|
story("turning the Sources experiment off closes its open panel and loads no more site icons", async ({ page }) => {
|
|
// Site icons stay off the network, and load, so each stays an image until the experiment turns off.
|
|
await page.route("**/favicon.ico", (route) =>
|
|
route.fulfill({
|
|
contentType: "image/png",
|
|
body: Buffer.from(
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
|
|
"base64",
|
|
),
|
|
}),
|
|
)
|
|
|
|
const result = await page.evaluate(
|
|
async (input) => {
|
|
const [{ mountSessionRegion, until }, { default: definition }, { default: renderer }, { motionTuning }] =
|
|
await Promise.all([
|
|
import(input.modules.fixture),
|
|
import(input.modules.definition),
|
|
import(input.modules.renderer),
|
|
import(input.modules.tuning),
|
|
])
|
|
|
|
const knob = (id: string) => motionTuning.list().find((item: MotionKnob) => item.id === id)
|
|
motionTuning.set(knob("sources.enabled"), true)
|
|
motionTuning.set(knob("sources.icons"), "site")
|
|
|
|
const host: { container: HTMLElement; unmount: () => void } = mountSessionRegion({
|
|
active: "sources:main",
|
|
messages: JSON.parse(input.messages),
|
|
definitions: [{ ...definition, id: "sources", windowEntry: async () => ({ default: renderer }) }],
|
|
})
|
|
|
|
const panel = () => host.container.querySelector('[data-slot="session-sources-panel"]')
|
|
const icons = () => host.container.querySelectorAll('[data-slot="site-icon-image"]').length
|
|
|
|
await until(() => !!panel()?.querySelector('[data-slot="sources-step-row"]'))
|
|
panel()?.querySelector<HTMLButtonElement>('[data-slot="sources-step-row"]')?.click()
|
|
await until(() => icons() > 0)
|
|
const open = { panel: !!panel(), icons: icons() }
|
|
|
|
motionTuning.set(knob("sources.enabled"), false)
|
|
await until(() => !panel())
|
|
const off = { panel: !!panel(), icons: icons() }
|
|
host.unmount()
|
|
|
|
return { open, off }
|
|
},
|
|
// As JSON: the messages' type is too deep for `evaluate`'s serializable argument check.
|
|
{ modules, messages: JSON.stringify(messages) },
|
|
)
|
|
|
|
expect(result).toEqual({ open: { panel: true, icons: 1 }, off: { panel: false, icons: 0 } })
|
|
})
|