import { expect, it } from "@effect/vitest"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner"; import * as ProcessRunner from "../processRunner.ts"; import { ensureDeviceHub, isDeviceHubInstalled } from "./DeviceToolchain.ts"; it.effect("failed installation cleans staging and exposes only a safe failure message", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-device-install-" }); const result = { code: ChildProcessSpawner.ExitCode(1), stdout: "", stderr: "registry rejected https://private:credential@example.test/package", timedOut: false, stdoutTruncated: false, stderrTruncated: false, stdoutInvalidUtf8: false, stderrInvalidUtf8: false, }; const error = yield* ensureDeviceHub(baseDir).pipe( Effect.provideService(ProcessRunner.ProcessRunner, { run: () => Effect.succeed(result), }), Effect.flip, ); expect(error.message).toBe( "Installing expo-device-hub failed while running npm install (exit code 1).", ); expect(error.cause).toBe(result); expect(yield* isDeviceHubInstalled(baseDir)).toBe(false); expect(yield* fs.readDirectory(path.join(baseDir, "tools", "expo-device-hub"))).toEqual([]); }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), );