refactor(core): move more tests to nodes (#34248)

This commit is contained in:
James Long
2026-06-27 18:10:07 +00:00
committed by GitHub
parent 6248542c49
commit a31698f99b
10 changed files with 56 additions and 52 deletions
@@ -6,9 +6,10 @@ import { Effect, Exit, Stream } from "effect"
import type * as PlatformError from "effect/PlatformError" import type * as PlatformError from "effect/PlatformError"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const live = CrossSpawnSpawner.defaultLayer const live = LayerNode.compile(CrossSpawnSpawner.node)
const fx = testEffect(live) const fx = testEffect(live)
function js(code: string, opts?: ChildProcess.CommandOptions) { function js(code: string, opts?: ChildProcess.CommandOptions) {
+2 -1
View File
@@ -2,12 +2,13 @@ import { describe, expect } from "bun:test"
import fs from "fs/promises" import fs from "fs/promises"
import path from "path" import path from "path"
import { Effect } from "effect" import { Effect } from "effect"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Ripgrep } from "@opencode-ai/core/ripgrep" import { Ripgrep } from "@opencode-ai/core/ripgrep"
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema" import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
import { tmpdir } from "../fixture/tmpdir" import { tmpdir } from "../fixture/tmpdir"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const it = testEffect(Ripgrep.defaultLayer) const it = testEffect(LayerNode.compile(Ripgrep.node))
const withTmp = <A, E, R>(f: (directory: AbsolutePath) => Effect.Effect<A, E, R>) => const withTmp = <A, E, R>(f: (directory: AbsolutePath) => Effect.Effect<A, E, R>) =>
Effect.acquireRelease( Effect.acquireRelease(
+2 -1
View File
@@ -3,13 +3,14 @@ import { $ } from "bun"
import fs from "fs/promises" import fs from "fs/promises"
import path from "path" import path from "path"
import { Effect } from "effect" import { Effect } from "effect"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Git } from "@opencode-ai/core/git" import { Git } from "@opencode-ai/core/git"
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema" import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
import { branch, commit, gitRemote } from "./fixture/git" import { branch, commit, gitRemote } from "./fixture/git"
import { tmpdir } from "./fixture/tmpdir" import { tmpdir } from "./fixture/tmpdir"
import { testEffect } from "./lib/effect" import { testEffect } from "./lib/effect"
const it = testEffect(Git.defaultLayer) const it = testEffect(LayerNode.compile(Git.node))
describe("Git", () => { describe("Git", () => {
it.live("clones a remote and reads checkout metadata", () => it.live("clones a remote and reads checkout metadata", () =>
+5 -5
View File
@@ -1,14 +1,14 @@
import { describe, expect } from "bun:test" import { describe, expect } from "bun:test"
import { Duration, Effect, Exit, Fiber, Layer, Scope, Stream } from "effect" import { Duration, Effect, Exit, Fiber, Scope, Stream } from "effect"
import * as TestClock from "effect/testing/TestClock" import * as TestClock from "effect/testing/TestClock"
import { Integration } from "@opencode-ai/core/integration"
import { Credential } from "@opencode-ai/core/credential" import { Credential } from "@opencode-ai/core/credential"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { EventV2 } from "@opencode-ai/core/event" import { EventV2 } from "@opencode-ai/core/event"
import { Integration } from "@opencode-ai/core/integration"
import { testEffect } from "./lib/effect" import { testEffect } from "./lib/effect"
const it = testEffect( const it = testEffect(AppNodeBuilder.build(LayerNode.group([Integration.node, Credential.node, EventV2.node])))
Integration.locationLayer.pipe(Layer.provideMerge(Credential.defaultLayer), Layer.provideMerge(EventV2.defaultLayer)),
)
describe("Integration", () => { describe("Integration", () => {
it.effect("registers integrations through the editor", () => it.effect("registers integrations through the editor", () =>
+11 -9
View File
@@ -2,10 +2,10 @@ import fs from "fs/promises"
import path from "path" import path from "path"
import { describe, expect } from "bun:test" import { describe, expect } from "bun:test"
import { Effect, Exit, Layer } from "effect" import { Effect, Exit, Layer } from "effect"
import { makeLocationNode } from "@opencode-ai/core/effect/app-node"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { FileSystem } from "@opencode-ai/core/filesystem" import { FileSystem } from "@opencode-ai/core/filesystem"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { Location } from "@opencode-ai/core/location" import { Location } from "@opencode-ai/core/location"
import { Ripgrep } from "@opencode-ai/core/ripgrep"
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema" import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
import { location } from "./fixture/location" import { location } from "./fixture/location"
import { tmpdir } from "./fixture/tmpdir" import { tmpdir } from "./fixture/tmpdir"
@@ -13,13 +13,15 @@ import { it } from "./lib/effect"
const provide = (directory: string) => const provide = (directory: string) =>
Effect.provide( Effect.provide(
FileSystem.layer.pipe( LayerNode.compile(
Layer.provide( LayerNode.bind(
Layer.mergeAll( FileSystem.node,
FSUtil.defaultLayer, Location.node,
Ripgrep.defaultLayer, makeLocationNode({
Layer.succeed(Location.Service, Location.Service.of(location({ directory: AbsolutePath.make(directory) }))), service: Location.Service,
), layer: Layer.succeed(Location.Service, Location.Service.of(location({ directory: AbsolutePath.make(directory) }))),
deps: [],
}),
), ),
), ),
) )
+11 -7
View File
@@ -2,7 +2,8 @@ import fs from "fs/promises"
import path from "path" import path from "path"
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { Effect, Layer, Schema } from "effect" import { Effect, Layer, Schema } from "effect"
import { FSUtil } from "@opencode-ai/core/fs-util" import { makeLocationNode } from "@opencode-ai/core/effect/app-node"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Location } from "@opencode-ai/core/location" import { Location } from "@opencode-ai/core/location"
import { LocationMutation } from "@opencode-ai/core/location-mutation" import { LocationMutation } from "@opencode-ai/core/location-mutation"
import { AbsolutePath } from "@opencode-ai/core/schema" import { AbsolutePath } from "@opencode-ai/core/schema"
@@ -12,12 +13,15 @@ import { it } from "./lib/effect"
function provide(directory: string) { function provide(directory: string) {
return Effect.provide( return Effect.provide(
LocationMutation.layer.pipe( LayerNode.compile(
Layer.provide( LayerNode.bind(
Layer.mergeAll( LocationMutation.node,
FSUtil.defaultLayer, Location.node,
Layer.succeed(Location.Service, Location.Service.of(location({ directory: AbsolutePath.make(directory) }))), makeLocationNode({
), service: Location.Service,
layer: Layer.succeed(Location.Service, Location.Service.of(location({ directory: AbsolutePath.make(directory) }))),
deps: [],
}),
), ),
), ),
) )
+3 -11
View File
@@ -1,20 +1,12 @@
import { describe, expect } from "bun:test" import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect" import { Effect } from "effect"
import { AgentV2 } from "@opencode-ai/core/agent" import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { SkillPlugin } from "@opencode-ai/core/plugin/skill" import { SkillPlugin } from "@opencode-ai/core/plugin/skill"
import { SkillV2 } from "@opencode-ai/core/skill" import { SkillV2 } from "@opencode-ai/core/skill"
import { SkillDiscovery } from "@opencode-ai/core/skill/discovery"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
import { host } from "./host" import { host } from "./host"
const it = testEffect( const it = testEffect(AppNodeBuilder.build(SkillV2.node))
SkillV2.layer.pipe(
Layer.provide(FSUtil.defaultLayer),
Layer.provide(SkillDiscovery.defaultLayer),
Layer.provideMerge(AgentV2.locationLayer),
),
)
describe("SkillPlugin.Plugin", () => { describe("SkillPlugin.Plugin", () => {
it.effect("registers the built-in customize-opencode skill", () => it.effect("registers the built-in customize-opencode skill", () =>
+2 -1
View File
@@ -2,12 +2,13 @@ import { describe, expect } from "bun:test"
import fs from "fs/promises" import fs from "fs/promises"
import path from "path" import path from "path"
import { Effect } from "effect" import { Effect } from "effect"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Ripgrep } from "@opencode-ai/core/ripgrep" import { Ripgrep } from "@opencode-ai/core/ripgrep"
import { RelativePath } from "@opencode-ai/core/schema" import { RelativePath } from "@opencode-ai/core/schema"
import { tmpdir } from "./fixture/tmpdir" import { tmpdir } from "./fixture/tmpdir"
import { testEffect } from "./lib/effect" import { testEffect } from "./lib/effect"
const it = testEffect(Ripgrep.defaultLayer) const it = testEffect(LayerNode.compile(Ripgrep.node))
describe("Ripgrep", () => { describe("Ripgrep", () => {
it.live("keeps ignored files out of catch-all find results", () => it.live("keeps ignored files out of catch-all find results", () =>
+3 -5
View File
@@ -3,6 +3,8 @@ import path from "path"
import { describe, expect } from "bun:test" import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect" import { Effect, Layer } from "effect"
import { AgentV2 } from "@opencode-ai/core/agent" import { AgentV2 } from "@opencode-ai/core/agent"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { FSUtil } from "@opencode-ai/core/fs-util" import { FSUtil } from "@opencode-ai/core/fs-util"
import { AbsolutePath } from "@opencode-ai/core/schema" import { AbsolutePath } from "@opencode-ai/core/schema"
import { SkillV2 } from "@opencode-ai/core/skill" import { SkillV2 } from "@opencode-ai/core/skill"
@@ -22,11 +24,7 @@ const discovery = Layer.succeed(
}), }),
) )
const it = testEffect( const it = testEffect(
SkillV2.layer.pipe( AppNodeBuilder.build(LayerNode.group([SkillV2.node, AgentV2.node]), [LayerNode.replace(SkillDiscovery.layer, discovery)]),
Layer.provide(discovery),
Layer.provide(FSUtil.defaultLayer),
Layer.provideMerge(AgentV2.locationLayer),
),
) )
function write(directory: string, name: string, description: string) { function write(directory: string, name: string, description: string) {
@@ -1,6 +1,9 @@
import { describe, expect } from "bun:test" import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect" import { Effect, Layer } from "effect"
import * as TestClock from "effect/testing/TestClock" import * as TestClock from "effect/testing/TestClock"
import { makeLocationNode } from "@opencode-ai/core/effect/app-node"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Location } from "@opencode-ai/core/location" import { Location } from "@opencode-ai/core/location"
import { FSUtil } from "@opencode-ai/core/fs-util" import { FSUtil } from "@opencode-ai/core/fs-util"
import { Global } from "@opencode-ai/core/global" import { Global } from "@opencode-ai/core/global"
@@ -25,12 +28,14 @@ const locationLayer = Layer.succeed(
), ),
), ),
) )
const locationNode = makeLocationNode({ service: Location.Service, layer: locationLayer, deps: [] })
const builtInsNode = LayerNode.bind(
LayerNode.group([SystemContextBuiltIns.node, SystemContextRegistry.node]),
Location.node,
locationNode,
)
const it = testEffect( const it = testEffect(
SystemContextBuiltIns.locationLayer.pipe( AppNodeBuilder.build(builtInsNode, [LayerNode.replace(Global.layer, Global.layerWith({ config: "/global" }))]),
Layer.provide(FSUtil.defaultLayer),
Layer.provide(Global.layerWith({ config: "/global" })),
Layer.provide(locationLayer),
),
) )
const instructionFS = Layer.effect( const instructionFS = Layer.effect(
FSUtil.Service, FSUtil.Service,
@@ -43,13 +48,12 @@ const instructionFS = Layer.effect(
}), }),
), ),
), ),
).pipe(Layer.provide(FSUtil.defaultLayer)) ).pipe(Layer.provide(LayerNode.compile(FSUtil.node)))
const itWithInstructions = testEffect( const itWithInstructions = testEffect(
SystemContextBuiltIns.locationLayer.pipe( AppNodeBuilder.build(builtInsNode, [
Layer.provide(instructionFS), LayerNode.replace(FSUtil.layer, instructionFS),
Layer.provide(Global.layerWith({ config: "/global" })), LayerNode.replace(Global.layer, Global.layerWith({ config: "/global" })),
Layer.provide(locationLayer), ]),
),
) )
describe("SystemContextBuiltIns", () => { describe("SystemContextBuiltIns", () => {