1import * as AWS from "@/AWS";
2import { Adapter } from "@/AWS/Textract/Adapter.ts";
3import * as Provider from "@/Provider";
4import * as Test from "@/Test/Alchemy";
5import * as textract from "@distilled.cloud/aws/textract";
6import { expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11// Deterministic name unique to this test case (same on every run).
12const adapterName = "alchemy-test-textract-adapter";
13
14const getAdapter = (adapterId: string) =>
15 textract
16 .getAdapter({ AdapterId: adapterId })
17 .pipe(
18 Effect.catchTag("ResourceNotFoundException", () =>
19 Effect.succeed(undefined),
20 ),
21 );
22
23test.provider(
24 "lifecycle: create adapter, update settings + tags, destroy",
25 (stack) =>
26 Effect.gen(function* () {
27 yield* stack.destroy();
28
29 // Create — a named QUERIES adapter with a description and user tags.
30 const deployed = yield* stack.deploy(
31 Effect.gen(function* () {
32 return yield* Adapter("TestAdapter", {
33 adapterName,
34 featureTypes: ["QUERIES"],
35 description: "alchemy adapter v1",
36 autoUpdate: "DISABLED",
37 tags: { env: "test" },
38 });
39 }),
40 );
41 expect(deployed.adapterId).toBeTruthy();
42 expect(deployed.adapterName).toBe(adapterName);
43 expect(deployed.featureTypes).toEqual(["QUERIES"]);
44 expect(deployed.adapterArn).toContain(`:/adapters/${deployed.adapterId}`);
45
46 // Out-of-band verification via distilled.
47 const created = yield* getAdapter(deployed.adapterId);
48 expect(created?.AdapterName).toBe(adapterName);
49 expect(created?.Description).toBe("alchemy adapter v1");
50 expect(created?.AutoUpdate).toBe("DISABLED");
51 expect(created?.Tags?.env).toBe("test");
52 // Internal ownership branding.
53 expect(created?.Tags?.["alchemy::id"]).toBe("TestAdapter");
54
55 // Canonical list() coverage.
56 const provider = yield* Provider.findProvider(Adapter);
57 const all = yield* provider.list();
58 expect(all.some((a) => a.adapterId === deployed.adapterId)).toBe(true);
59
60 // Update — description, autoUpdate, and tags are all mutable in place.
61 const updated = yield* stack.deploy(
62 Effect.gen(function* () {
63 return yield* Adapter("TestAdapter", {
64 adapterName,
65 featureTypes: ["QUERIES"],
66 description: "alchemy adapter v2",
67 autoUpdate: "ENABLED",
68 tags: { env: "test2", extra: "1" },
69 });
70 }),
71 );
72 // Same physical adapter (update, not replace).
73 expect(updated.adapterId).toBe(deployed.adapterId);
74
75 const observed = yield* getAdapter(deployed.adapterId);
76 expect(observed?.Description).toBe("alchemy adapter v2");
77 expect(observed?.AutoUpdate).toBe("ENABLED");
78 expect(observed?.Tags?.env).toBe("test2");
79 expect(observed?.Tags?.extra).toBe("1");
80
81 // Destroy — the adapter is gone.
82 yield* stack.destroy();
83 const after = yield* getAdapter(deployed.adapterId);
84 expect(after).toBeUndefined();
85 }),
86 { tags: ["provider:aws", "provider:aws:textract", "live"], timeout: 180_000 },
87);