1import { AuthError } from "@/Auth/AuthProvider.ts";
2import { StackEntrypointError } from "@/Alchemist/Session.ts";
3import { handleCliErrors } from "@/Cli/commands/errors.ts";
4import * as Console from "effect/Console";
5import * as Effect from "effect/Effect";
6import * as Result from "effect/Result";
7import { expect, it } from "alchemy-test";
8import { format } from "node:util";
9
10it.effect(
11 "renders auth failures as user-facing CLI errors",
12 () =>
13 Effect.gen(function* () {
14 const errors: string[] = [];
15 const capturedConsole = {
16 ...globalThis.console,
17 error: (...args: ReadonlyArray<unknown>) =>
18 errors.push(format(...args)),
19 } as Console.Console;
20
21 const result = yield* handleCliErrors(
22 Effect.fail(
23 new AuthError({
24 message:
25 "Cloudflare credentials need refreshing. Run: alchemy profile refresh --profile admin --provider Cloudflare",
26 }),
27 ),
28 ).pipe(
29 Effect.result,
30 Effect.provideService(Console.Console, capturedConsole),
31 );
32
33 expect(Result.isFailure(result)).toBe(true);
34 expect(errors).toHaveLength(1);
35 expect(errors[0]).toContain("error:");
36 expect(errors[0]).toContain("alchemy profile refresh --profile admin");
37 expect(errors[0]).not.toContain("at Effect.fn");
38 }),
39 { tags: ["unit", "local"] },
40);
41
42it.effect(
43 "renders missing stack entrypoints without a resolver stack",
44 () =>
45 Effect.gen(function* () {
46 const errors: string[] = [];
47 const capturedConsole = {
48 ...globalThis.console,
49 error: (...args: ReadonlyArray<unknown>) =>
50 errors.push(format(...args)),
51 } as Console.Console;
52
53 const result = yield* handleCliErrors(
54 Effect.fail(
55 new StackEntrypointError({
56 message:
57 "Stack entrypoint 'alchemy.run.ts' does not exist. Run this command from an Alchemy project or pass --config <path>.",
58 }),
59 ),
60 ).pipe(
61 Effect.result,
62 Effect.provideService(Console.Console, capturedConsole),
63 );
64
65 expect(Result.isFailure(result)).toBe(true);
66 expect(errors).toHaveLength(1);
67 expect(errors[0]).toContain("error:");
68 expect(errors[0]).toContain("alchemy.run.ts");
69 expect(errors[0]).toContain("--config <path>");
70 expect(errors[0]).not.toContain("at Effect.fn");
71 }),
72 { tags: ["unit", "local"] },
73);