summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLuke Parker <[email protected]>2026-03-29 13:38:53 +1000
committeropencode <[email protected]>2026-03-29 03:43:00 +0000
commita5b1dc081d589598168c0e0d9346a35aeb58548b (patch)
tree7af8ffd674ab42b3597c6fa3cf0a122786c00e3b
parent0bc2f99f2d314800071426de1e27c1d17c2eff85 (diff)
downloadopencode-a5b1dc081d589598168c0e0d9346a35aeb58548b.tar.gz
opencode-a5b1dc081d589598168c0e0d9346a35aeb58548b.zip
test: add regression coverage for sync plugin hooks (#19589)
-rw-r--r--packages/opencode/test/plugin/trigger.test.ts111
1 files changed, 111 insertions, 0 deletions
diff --git a/packages/opencode/test/plugin/trigger.test.ts b/packages/opencode/test/plugin/trigger.test.ts
new file mode 100644
index 000000000..d89d930c6
--- /dev/null
+++ b/packages/opencode/test/plugin/trigger.test.ts
@@ -0,0 +1,111 @@
+import { afterAll, afterEach, describe, expect, test } from "bun:test"
+import path from "path"
+import { pathToFileURL } from "url"
+import { tmpdir } from "../fixture/fixture"
+
+const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
+process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1"
+
+const { Plugin } = await import("../../src/plugin/index")
+const { Instance } = await import("../../src/project/instance")
+
+afterEach(async () => {
+ await Instance.disposeAll()
+})
+
+afterAll(() => {
+ if (disableDefault === undefined) {
+ delete process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
+ return
+ }
+ process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault
+})
+
+async function project(source: string) {
+ return tmpdir({
+ init: async (dir) => {
+ const file = path.join(dir, "plugin.ts")
+ await Bun.write(file, source)
+ await Bun.write(
+ path.join(dir, "opencode.json"),
+ JSON.stringify(
+ {
+ $schema: "https://opencode.ai/config.json",
+ plugin: [pathToFileURL(file).href],
+ },
+ null,
+ 2,
+ ),
+ )
+ },
+ })
+}
+
+describe("plugin.trigger", () => {
+ test("runs synchronous hooks without crashing", async () => {
+ await using tmp = await project(
+ [
+ "export default async () => ({",
+ ' "experimental.chat.system.transform": (_input, output) => {',
+ ' output.system.unshift("sync")',
+ " },",
+ "})",
+ "",
+ ].join("\n"),
+ )
+
+ const out = await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const out = { system: [] as string[] }
+ await Plugin.trigger(
+ "experimental.chat.system.transform",
+ {
+ model: {
+ providerID: "anthropic",
+ modelID: "claude-sonnet-4-6",
+ } as any,
+ },
+ out,
+ )
+ return out
+ },
+ })
+
+ expect(out.system).toEqual(["sync"])
+ })
+
+ test("awaits asynchronous hooks", async () => {
+ await using tmp = await project(
+ [
+ "export default async () => ({",
+ ' "experimental.chat.system.transform": async (_input, output) => {',
+ " await Bun.sleep(1)",
+ ' output.system.unshift("async")',
+ " },",
+ "})",
+ "",
+ ].join("\n"),
+ )
+
+ const out = await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const out = { system: [] as string[] }
+ await Plugin.trigger(
+ "experimental.chat.system.transform",
+ {
+ model: {
+ providerID: "anthropic",
+ modelID: "claude-sonnet-4-6",
+ } as any,
+ },
+ out,
+ )
+ return out
+ },
+ })
+
+ expect(out.system).toEqual(["async"])
+ })
+})