1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import { GetCustomer } from "@distilled.cloud/stripe/stripe";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9import { isMissingStripeResource } from "@/Stripe/missing.ts";
10
11const { test } = Test.make({ providers: Stripe.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const waitUntilGone = (id: string) =>
19 GetCustomer({ customer: id }).pipe(
20 Effect.map((customer) =>
21 "deleted" in customer && customer.deleted
22 ? ("gone" as const)
23 : ("found" as const),
24 ),
25 Effect.catchIf(isMissingStripeResource, () =>
26 Effect.succeed("gone" as const),
27 ),
28 Effect.repeat({
29 schedule: Schedule.spaced("1 second"),
30 until: (status) => status === "gone",
31 times: 10,
32 }),
33 );
34
35test.provider(
36 "create, update, and delete a customer",
37 (stack) =>
38 Effect.gen(function* () {
39 yield* stack.destroy();
40
41 const created = yield* stack.deploy(
42 Effect.gen(function* () {
43 return yield* Stripe.Customer("CatalogCustomer", {
44 email: "alchemy.catalog.customer@example.com",
45 name: "Alchemy Catalog Customer",
46 description: "Initial description",
47 phone: "+15555550100",
48 metadata: { plan: "pro" },
49 });
50 }),
51 );
52
53 expect(created.id).toMatch(/^cus_/);
54 expect(created.email).toEqual("alchemy.catalog.customer@example.com");
55 expect(created.name).toEqual("Alchemy Catalog Customer");
56 expect(created.description).toEqual("Initial description");
57 expect(created.phone).toEqual("+15555550100");
58 expect(created.metadata).toMatchObject({ plan: "pro" });
59 expect(created.created).toEqual(expect.any(Number));
60 expect(created.livemode).toEqual(false);
61
62 const fetched = yield* GetCustomer({ customer: created.id });
63 if (!("email" in fetched)) {
64 return;
65 }
66 expect(fetched.id).toEqual(created.id);
67 expect(fetched.email).toEqual(created.email);
68 expect(fetched.name).toEqual(created.name);
69 expect(fetched.description).toEqual("Initial description");
70 expect(fetched.phone).toEqual("+15555550100");
71 expect(fetched.metadata?.plan).toEqual("pro");
72 expect(
73 fetched.metadata?.[Stripe.alchemyMetadataKeys.stack],
74 ).toBeDefined();
75 expect(
76 fetched.metadata?.[Stripe.alchemyMetadataKeys.stage],
77 ).toBeDefined();
78 expect(fetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
79
80 const updated = yield* stack.deploy(
81 Effect.gen(function* () {
82 return yield* Stripe.Customer("CatalogCustomer", {
83 email: "alchemy.catalog.customer.updated@example.com",
84 name: "Alchemy Catalog Customer Updated",
85 description: "Updated description",
86 phone: "+15555550199",
87 metadata: { plan: "enterprise", sku: "ent-1" },
88 });
89 }),
90 );
91
92 expect(updated.id).toEqual(created.id);
93 expect(updated.email).toEqual(
94 "alchemy.catalog.customer.updated@example.com",
95 );
96 expect(updated.name).toEqual("Alchemy Catalog Customer Updated");
97 expect(updated.description).toEqual("Updated description");
98 expect(updated.phone).toEqual("+15555550199");
99 expect(updated.metadata).toEqual({ plan: "enterprise", sku: "ent-1" });
100
101 const refetched = yield* GetCustomer({ customer: updated.id });
102 if (!("email" in refetched)) {
103 return;
104 }
105 expect(refetched.email).toEqual(updated.email);
106 expect(refetched.name).toEqual(updated.name);
107 expect(refetched.description).toEqual("Updated description");
108 expect(refetched.phone).toEqual("+15555550199");
109 expect(refetched.metadata?.plan).toEqual("enterprise");
110 expect(refetched.metadata?.sku).toEqual("ent-1");
111 expect(refetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
112
113 yield* stack.destroy();
114
115 const gone = yield* waitUntilGone(created.id);
116 expect(gone).toEqual("gone");
117 }).pipe(logLevel),
118 {
119 tags: ["provider:stripe", "provider:stripe:customer", "live"],
120 timeout: 120_000,
121 },
122);
123
124test.provider(
125 "list enumerates the deployed customer",
126 (stack) =>
127 Effect.gen(function* () {
128 yield* stack.destroy();
129
130 const deployed = yield* stack.deploy(
131 Effect.gen(function* () {
132 return yield* Stripe.Customer("ListCustomer", {
133 email: "alchemy.list.customer@example.com",
134 name: "Alchemy List Customer",
135 metadata: { kind: "list" },
136 });
137 }),
138 );
139
140 const provider = yield* Provider.findProvider(Stripe.Customer);
141 const all = yield* provider.list();
142 const found = all.find((customer) => customer.id === deployed.id);
143 expect(found).toBeDefined();
144 expect(found?.email).toEqual(deployed.email);
145 expect(found?.name).toEqual(deployed.name);
146 expect(found?.metadata).toMatchObject({ kind: "list" });
147
148 yield* stack.destroy();
149
150 const gone = yield* waitUntilGone(deployed.id);
151 expect(gone).toEqual("gone");
152 }).pipe(logLevel),
153 {
154 tags: ["provider:stripe", "provider:stripe:customer", "live"],
155 timeout: 120_000,
156 },
157);