test: use testEffect for plugin triggers (#25053)

This commit is contained in:
Kit Langton
2026-04-30 14:24:53 -04:00
committed by GitHub
parent f4ce240a2e
commit 87cd9446d8
+64 -78
View File
@@ -1,18 +1,18 @@
import { afterAll, afterEach, describe, expect, test } from "bun:test" import { afterAll, describe, expect } from "bun:test"
import { Effect } from "effect" import { Effect, Layer } from "effect"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import path from "path" import path from "path"
import { pathToFileURL } from "url" import { pathToFileURL } from "url"
import { tmpdir } from "../fixture/fixture" import { ModelID, ProviderID } from "../../src/provider/schema"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1" process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1"
const { Plugin } = await import("../../src/plugin/index") const { Plugin } = await import("../../src/plugin/index")
const { Instance } = await import("../../src/project/instance") const it = testEffect(Layer.mergeAll(Plugin.defaultLayer, CrossSpawnSpawner.defaultLayer))
const systemHook = "experimental.chat.system.transform"
afterEach(async () => {
await Instance.disposeAll()
})
afterAll(() => { afterAll(() => {
if (disableDefault === undefined) { if (disableDefault === undefined) {
@@ -22,95 +22,81 @@ afterAll(() => {
process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault
}) })
async function project(source: string) { function withProject<A, E, R>(source: string, self: Effect.Effect<A, E, R>) {
return tmpdir({ return provideTmpdirInstance((dir) =>
init: async (dir) => { Effect.gen(function* () {
const file = path.join(dir, "plugin.ts") const file = path.join(dir, "plugin.ts")
await Bun.write(file, source) yield* Effect.all(
await Bun.write( [
path.join(dir, "opencode.json"), Effect.promise(() => Bun.write(file, source)),
JSON.stringify( Effect.promise(() =>
{ Bun.write(
$schema: "https://opencode.ai/config.json", path.join(dir, "opencode.json"),
plugin: [pathToFileURL(file).href], JSON.stringify(
}, {
null, $schema: "https://opencode.ai/config.json",
2, plugin: [pathToFileURL(file).href],
), },
null,
2,
),
),
),
],
{ discard: true, concurrency: 2 },
) )
}, return yield* self
}) }),
)
} }
const triggerSystemTransform = Effect.fn("PluginTriggerTest.triggerSystemTransform")(function* () {
const plugin = yield* Plugin.Service
const out = { system: [] as string[] }
yield* plugin.trigger(
systemHook,
{
model: {
providerID: ProviderID.anthropic,
modelID: ModelID.make("claude-sonnet-4-6"),
},
},
out,
)
return out.system
})
describe("plugin.trigger", () => { describe("plugin.trigger", () => {
test("runs synchronous hooks without crashing", async () => { it.live("runs synchronous hooks without crashing", () =>
await using tmp = await project( withProject(
[ [
"export default async () => ({", "export default async () => ({",
' "experimental.chat.system.transform": (_input, output) => {', ` ${JSON.stringify(systemHook)}: (_input, output) => {`,
' output.system.unshift("sync")', ' output.system.unshift("sync")',
" },", " },",
"})", "})",
"", "",
].join("\n"), ].join("\n"),
) Effect.gen(function* () {
expect(yield* triggerSystemTransform()).toEqual(["sync"])
}),
),
)
const out = await Instance.provide({ it.live("awaits asynchronous hooks", () =>
directory: tmp.path, withProject(
fn: async () =>
Effect.gen(function* () {
const plugin = yield* Plugin.Service
const out = { system: [] as string[] }
yield* plugin.trigger(
"experimental.chat.system.transform",
{
model: {
providerID: "anthropic",
modelID: "claude-sonnet-4-6",
} as any,
},
out,
)
return out
}).pipe(Effect.provide(Plugin.defaultLayer), Effect.runPromise),
})
expect(out.system).toEqual(["sync"])
})
test("awaits asynchronous hooks", async () => {
await using tmp = await project(
[ [
"export default async () => ({", "export default async () => ({",
' "experimental.chat.system.transform": async (_input, output) => {', ` ${JSON.stringify(systemHook)}: async (_input, output) => {`,
" await Bun.sleep(1)", " await Bun.sleep(1)",
' output.system.unshift("async")', ' output.system.unshift("async")',
" },", " },",
"})", "})",
"", "",
].join("\n"), ].join("\n"),
) Effect.gen(function* () {
expect(yield* triggerSystemTransform()).toEqual(["async"])
const out = await Instance.provide({ }),
directory: tmp.path, ),
fn: async () => )
Effect.gen(function* () {
const plugin = yield* Plugin.Service
const out = { system: [] as string[] }
yield* plugin.trigger(
"experimental.chat.system.transform",
{
model: {
providerID: "anthropic",
modelID: "claude-sonnet-4-6",
} as any,
},
out,
)
return out
}).pipe(Effect.provide(Plugin.defaultLayer), Effect.runPromise),
})
expect(out.system).toEqual(["async"])
})
}) })