refactor: migrate installation tests to testEffect (#27342)
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect } from "bun:test"
|
||||||
import { Effect, Layer, Stream } from "effect"
|
import { Effect, Layer, Stream } from "effect"
|
||||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
||||||
import { Installation } from "../../src/installation"
|
import { Installation } from "../../src/installation"
|
||||||
import { InstallationChannel } from "@opencode-ai/core/installation/version"
|
import { InstallationChannel } from "@opencode-ai/core/installation/version"
|
||||||
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const encoder = new TextEncoder()
|
const encoder = new TextEncoder()
|
||||||
|
|
||||||
@@ -51,86 +52,84 @@ function testLayer(
|
|||||||
|
|
||||||
describe("installation", () => {
|
describe("installation", () => {
|
||||||
describe("latest", () => {
|
describe("latest", () => {
|
||||||
test("reads release version from GitHub releases", async () => {
|
testEffect(testLayer(() => jsonResponse({ tag_name: "v1.2.3" }))).effect(
|
||||||
const layer = testLayer(() => jsonResponse({ tag_name: "v1.2.3" }))
|
"reads release version from GitHub releases",
|
||||||
|
() =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const result = yield* Installation.Service.use((svc) => svc.latest("unknown"))
|
||||||
|
expect(result).toBe("1.2.3")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
testEffect(testLayer(() => jsonResponse({ tag_name: "v4.0.0-beta.1" }))).effect(
|
||||||
Installation.Service.use((svc) => svc.latest("unknown")).pipe(Effect.provide(layer)),
|
"strips v prefix from GitHub release tag",
|
||||||
)
|
() =>
|
||||||
expect(result).toBe("1.2.3")
|
Effect.gen(function* () {
|
||||||
})
|
const result = yield* Installation.Service.use((svc) => svc.latest("curl"))
|
||||||
|
expect(result).toBe("4.0.0-beta.1")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
test("strips v prefix from GitHub release tag", async () => {
|
const npmCalls: string[] = []
|
||||||
const layer = testLayer(() => jsonResponse({ tag_name: "v4.0.0-beta.1" }))
|
testEffect(
|
||||||
|
testLayer((request) => {
|
||||||
const result = await Effect.runPromise(
|
npmCalls.push(request.url)
|
||||||
Installation.Service.use((svc) => svc.latest("curl")).pipe(Effect.provide(layer)),
|
|
||||||
)
|
|
||||||
expect(result).toBe("4.0.0-beta.1")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("reads npm versions via registry", async () => {
|
|
||||||
const calls: string[] = []
|
|
||||||
const layer = testLayer((request) => {
|
|
||||||
calls.push(request.url)
|
|
||||||
return jsonResponse({ version: "1.5.0" })
|
return jsonResponse({ version: "1.5.0" })
|
||||||
})
|
}),
|
||||||
|
).effect("reads npm versions via registry", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const result = yield* Installation.Service.use((svc) => svc.latest("npm"))
|
||||||
|
expect(result).toBe("1.5.0")
|
||||||
|
expect(npmCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
const bunCalls: string[] = []
|
||||||
Installation.Service.use((svc) => svc.latest("npm")).pipe(Effect.provide(layer)),
|
testEffect(
|
||||||
)
|
testLayer((request) => {
|
||||||
expect(result).toBe("1.5.0")
|
bunCalls.push(request.url)
|
||||||
expect(calls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("reads bun versions via registry", async () => {
|
|
||||||
const calls: string[] = []
|
|
||||||
const layer = testLayer((request) => {
|
|
||||||
calls.push(request.url)
|
|
||||||
return jsonResponse({ version: "1.6.0" })
|
return jsonResponse({ version: "1.6.0" })
|
||||||
})
|
}),
|
||||||
|
).effect("reads bun versions via registry", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const result = yield* Installation.Service.use((svc) => svc.latest("bun"))
|
||||||
|
expect(result).toBe("1.6.0")
|
||||||
|
expect(bunCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
const pnpmCalls: string[] = []
|
||||||
Installation.Service.use((svc) => svc.latest("bun")).pipe(Effect.provide(layer)),
|
testEffect(
|
||||||
)
|
testLayer((request) => {
|
||||||
expect(result).toBe("1.6.0")
|
pnpmCalls.push(request.url)
|
||||||
expect(calls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("reads pnpm versions via registry", async () => {
|
|
||||||
const calls: string[] = []
|
|
||||||
const layer = testLayer((request) => {
|
|
||||||
calls.push(request.url)
|
|
||||||
return jsonResponse({ version: "1.7.0" })
|
return jsonResponse({ version: "1.7.0" })
|
||||||
})
|
}),
|
||||||
|
).effect("reads pnpm versions via registry", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const result = yield* Installation.Service.use((svc) => svc.latest("pnpm"))
|
||||||
|
expect(result).toBe("1.7.0")
|
||||||
|
expect(pnpmCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
testEffect(testLayer(() => jsonResponse({ version: "2.3.4" }))).effect("reads scoop manifest versions", () =>
|
||||||
Installation.Service.use((svc) => svc.latest("pnpm")).pipe(Effect.provide(layer)),
|
Effect.gen(function* () {
|
||||||
)
|
const result = yield* Installation.Service.use((svc) => svc.latest("scoop"))
|
||||||
expect(result).toBe("1.7.0")
|
expect(result).toBe("2.3.4")
|
||||||
expect(calls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`)
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("reads scoop manifest versions", async () => {
|
testEffect(testLayer(() => jsonResponse({ d: { results: [{ Version: "3.4.5" }] } }))).effect(
|
||||||
const layer = testLayer(() => jsonResponse({ version: "2.3.4" }))
|
"reads chocolatey feed versions",
|
||||||
|
() =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const result = yield* Installation.Service.use((svc) => svc.latest("choco"))
|
||||||
|
expect(result).toBe("3.4.5")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
testEffect(
|
||||||
Installation.Service.use((svc) => svc.latest("scoop")).pipe(Effect.provide(layer)),
|
testLayer(
|
||||||
)
|
|
||||||
expect(result).toBe("2.3.4")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("reads chocolatey feed versions", async () => {
|
|
||||||
const layer = testLayer(() => jsonResponse({ d: { results: [{ Version: "3.4.5" }] } }))
|
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
|
||||||
Installation.Service.use((svc) => svc.latest("choco")).pipe(Effect.provide(layer)),
|
|
||||||
)
|
|
||||||
expect(result).toBe("3.4.5")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("reads brew formulae API versions", async () => {
|
|
||||||
const layer = testLayer(
|
|
||||||
() => jsonResponse({ versions: { stable: "2.0.0" } }),
|
() => jsonResponse({ versions: { stable: "2.0.0" } }),
|
||||||
(cmd, args) => {
|
(cmd, args) => {
|
||||||
// getBrewFormula: return core formula (no tap)
|
// getBrewFormula: return core formula (no tap)
|
||||||
@@ -138,31 +137,31 @@ describe("installation", () => {
|
|||||||
if (cmd === "brew" && args.includes("--formula") && args.includes("opencode")) return "opencode"
|
if (cmd === "brew" && args.includes("--formula") && args.includes("opencode")) return "opencode"
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
).effect("reads brew formulae API versions", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const result = yield* Installation.Service.use((svc) => svc.latest("brew"))
|
||||||
|
expect(result).toBe("2.0.0")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const result = await Effect.runPromise(
|
const brewInfoJson = JSON.stringify({
|
||||||
Installation.Service.use((svc) => svc.latest("brew")).pipe(Effect.provide(layer)),
|
formulae: [{ versions: { stable: "2.1.0" } }],
|
||||||
)
|
|
||||||
expect(result).toBe("2.0.0")
|
|
||||||
})
|
})
|
||||||
|
testEffect(
|
||||||
test("reads brew tap info JSON via CLI", async () => {
|
testLayer(
|
||||||
const brewInfoJson = JSON.stringify({
|
|
||||||
formulae: [{ versions: { stable: "2.1.0" } }],
|
|
||||||
})
|
|
||||||
const layer = testLayer(
|
|
||||||
() => jsonResponse({}), // HTTP not used for tap formula
|
() => jsonResponse({}), // HTTP not used for tap formula
|
||||||
(cmd, args) => {
|
(cmd, args) => {
|
||||||
if (cmd === "brew" && args.includes("anomalyco/tap/opencode") && args.includes("--formula")) return "opencode"
|
if (cmd === "brew" && args.includes("anomalyco/tap/opencode") && args.includes("--formula")) return "opencode"
|
||||||
if (cmd === "brew" && args.includes("--json=v2")) return brewInfoJson
|
if (cmd === "brew" && args.includes("--json=v2")) return brewInfoJson
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
).effect("reads brew tap info JSON via CLI", () =>
|
||||||
const result = await Effect.runPromise(
|
Effect.gen(function* () {
|
||||||
Installation.Service.use((svc) => svc.latest("brew")).pipe(Effect.provide(layer)),
|
const result = yield* Installation.Service.use((svc) => svc.latest("brew"))
|
||||||
)
|
expect(result).toBe("2.1.0")
|
||||||
expect(result).toBe("2.1.0")
|
}),
|
||||||
})
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user