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
+51 -65
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,12 +22,15 @@ 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( [
Effect.promise(() => Bun.write(file, source)),
Effect.promise(() =>
Bun.write(
path.join(dir, "opencode.json"), path.join(dir, "opencode.json"),
JSON.stringify( JSON.stringify(
{ {
@@ -37,80 +40,63 @@ async function project(source: string) {
null, null,
2, 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"),
)
const out = await Instance.provide({
directory: tmp.path,
fn: async () =>
Effect.gen(function* () { Effect.gen(function* () {
const plugin = yield* Plugin.Service expect(yield* triggerSystemTransform()).toEqual(["sync"])
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"]) it.live("awaits asynchronous hooks", () =>
}) withProject(
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"),
)
const out = await Instance.provide({
directory: tmp.path,
fn: async () =>
Effect.gen(function* () { Effect.gen(function* () {
const plugin = yield* Plugin.Service expect(yield* triggerSystemTransform()).toEqual(["async"])
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"])
})
}) })