1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import { GetTerminalLocation } 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 GetTerminalLocation({ location: id }).pipe(
20 Effect.map((location) =>
21 "deleted" in location && location.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
35const usAddress = {
36 line1: "123 Market Street",
37 city: "San Francisco",
38 state: "CA",
39 postalCode: "94105",
40 country: "US",
41} as const;
42
43const usAddressUpdated = {
44 line1: "125 Market Street",
45 city: "San Francisco",
46 state: "CA",
47 postalCode: "94105",
48 country: "US",
49} as const;
50
51const caAddress = {
52 line1: "100 Queen Street West",
53 city: "Toronto",
54 state: "ON",
55 postalCode: "M5H 2N2",
56 country: "CA",
57} as const;
58
59test.provider(
60 "create, update, and delete a terminal location",
61 (stack) =>
62 Effect.gen(function* () {
63 yield* stack.destroy();
64
65 const created = yield* stack.deploy(
66 Effect.gen(function* () {
67 return yield* Stripe.TerminalLocation("Storefront", {
68 displayName: "Alchemy Storefront",
69 address: { ...usAddress },
70 phone: "+14155550100",
71 metadata: { region: "west" },
72 });
73 }),
74 );
75
76 expect(created.id).toMatch(/^tml_/);
77 expect(created.displayName).toEqual("Alchemy Storefront");
78 expect(created.address).toEqual(usAddress);
79 expect(created.phone).toEqual("+14155550100");
80 expect(created.metadata).toMatchObject({ region: "west" });
81 expect(created.livemode).toEqual(false);
82
83 const fetched = yield* GetTerminalLocation({
84 location: created.id,
85 });
86 if (!("display_name" in fetched)) {
87 return;
88 }
89 expect(fetched.id).toEqual(created.id);
90 expect(fetched.display_name).toEqual("Alchemy Storefront");
91 expect(fetched.address.line1).toEqual(usAddress.line1);
92 expect(fetched.address.city).toEqual(usAddress.city);
93 expect(fetched.address.state).toEqual(usAddress.state);
94 expect(fetched.address.postal_code).toEqual(usAddress.postalCode);
95 expect(fetched.address.country).toEqual(usAddress.country);
96 expect(fetched.phone).toEqual("+14155550100");
97 expect(fetched.metadata?.region).toEqual("west");
98 expect(
99 fetched.metadata?.[Stripe.alchemyMetadataKeys.stack],
100 ).toBeDefined();
101 expect(
102 fetched.metadata?.[Stripe.alchemyMetadataKeys.stage],
103 ).toBeDefined();
104 expect(fetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
105
106 const updated = yield* stack.deploy(
107 Effect.gen(function* () {
108 return yield* Stripe.TerminalLocation("Storefront", {
109 displayName: "Alchemy Storefront Updated",
110 address: { ...usAddressUpdated },
111 phone: "+14155550199",
112 metadata: { region: "bay", sku: "loc-2" },
113 });
114 }),
115 );
116
117 expect(updated.id).toEqual(created.id);
118 expect(updated.displayName).toEqual("Alchemy Storefront Updated");
119 expect(updated.address).toEqual(usAddressUpdated);
120 expect(updated.phone).toEqual("+14155550199");
121 expect(updated.metadata).toEqual({ region: "bay", sku: "loc-2" });
122
123 const refetched = yield* GetTerminalLocation({
124 location: updated.id,
125 });
126 if (!("display_name" in refetched)) {
127 return;
128 }
129 expect(refetched.id).toEqual(updated.id);
130 expect(refetched.display_name).toEqual("Alchemy Storefront Updated");
131 expect(refetched.address.line1).toEqual(usAddressUpdated.line1);
132 expect(refetched.phone).toEqual("+14155550199");
133 expect(refetched.metadata?.region).toEqual("bay");
134 expect(refetched.metadata?.sku).toEqual("loc-2");
135 expect(refetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
136
137 yield* stack.destroy();
138
139 const gone = yield* waitUntilGone(created.id);
140 expect(gone).toEqual("gone");
141 }).pipe(logLevel),
142 {
143 tags: ["provider:stripe", "provider:stripe:terminallocation", "live"],
144 timeout: 120_000,
145 },
146);
147
148test.provider(
149 "replace when the country changes",
150 (stack) =>
151 Effect.gen(function* () {
152 yield* stack.destroy();
153
154 const created = yield* stack.deploy(
155 Effect.gen(function* () {
156 return yield* Stripe.TerminalLocation("ReplaceStore", {
157 displayName: "Alchemy Replace Store",
158 address: { ...usAddress },
159 });
160 }),
161 );
162
163 expect(created.address.country).toEqual("US");
164
165 const replaced = yield* stack.deploy(
166 Effect.gen(function* () {
167 return yield* Stripe.TerminalLocation("ReplaceStore", {
168 displayName: "Alchemy Replace Store",
169 address: { ...caAddress },
170 });
171 }),
172 );
173
174 expect(replaced.id).not.toEqual(created.id);
175 expect(replaced.address).toEqual(caAddress);
176 expect(replaced.displayName).toEqual("Alchemy Replace Store");
177
178 const fetched = yield* GetTerminalLocation({
179 location: replaced.id,
180 });
181 if (!("display_name" in fetched)) {
182 return;
183 }
184 expect(fetched.id).toEqual(replaced.id);
185 expect(fetched.address.country).toEqual("CA");
186 expect(fetched.address.city).toEqual(caAddress.city);
187 expect(fetched.address.postal_code).toEqual(caAddress.postalCode);
188
189 const oldGone = yield* waitUntilGone(created.id);
190 expect(oldGone).toEqual("gone");
191
192 yield* stack.destroy();
193
194 const gone = yield* waitUntilGone(replaced.id);
195 expect(gone).toEqual("gone");
196 }).pipe(logLevel),
197 {
198 tags: ["provider:stripe", "provider:stripe:terminallocation", "live"],
199 timeout: 120_000,
200 },
201);
202
203test.provider(
204 "list enumerates the deployed terminal location",
205 (stack) =>
206 Effect.gen(function* () {
207 yield* stack.destroy();
208
209 const deployed = yield* stack.deploy(
210 Effect.gen(function* () {
211 return yield* Stripe.TerminalLocation("ListStore", {
212 displayName: "Alchemy List Store",
213 address: { ...usAddress },
214 metadata: { kind: "list" },
215 });
216 }),
217 );
218
219 const provider = yield* Provider.findProvider(Stripe.TerminalLocation);
220 const all = yield* provider.list();
221 const found = all.find((location) => location.id === deployed.id);
222 expect(found).toBeDefined();
223 expect(found?.displayName).toEqual(deployed.displayName);
224 expect(found?.address.country).toEqual("US");
225 expect(found?.metadata).toMatchObject({ kind: "list" });
226
227 yield* stack.destroy();
228
229 const gone = yield* waitUntilGone(deployed.id);
230 expect(gone).toEqual("gone");
231 }).pipe(logLevel),
232 {
233 tags: ["provider:stripe", "provider:stripe:terminallocation", "live"],
234 timeout: 120_000,
235 },
236);