1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import {
5 GetTerminalConfiguration,
6 type DeletedTerminalConfiguration,
7 type TerminalConfiguration as StripeTerminalConfiguration,
8} from "@distilled.cloud/stripe/stripe";
9import { expect } from "alchemy-test";
10import * as Effect from "effect/Effect";
11import { MinimumLogLevel } from "effect/References";
12import * as Schedule from "effect/Schedule";
13import { isMissingStripeResource } from "@/Stripe/missing.ts";
14
15const { test } = Test.make({ providers: Stripe.providers() });
16
17const logLevel = Effect.provideService(
18 MinimumLogLevel,
19 process.env.DEBUG ? "Debug" : "Info",
20);
21
22const isMissing = isMissingStripeResource;
23
24const isDeletedConfiguration = (
25 value: StripeTerminalConfiguration | DeletedTerminalConfiguration,
26): value is DeletedTerminalConfiguration =>
27 "deleted" in value && value.deleted === true;
28
29const waitUntilGone = (id: string) =>
30 GetTerminalConfiguration({ configuration: id }).pipe(
31 Effect.map((configuration) =>
32 "deleted" in configuration && configuration.deleted === true
33 ? ("gone" as const)
34 : ("found" as const),
35 ),
36 Effect.catchIf(isMissing, () => Effect.succeed("gone" as const)),
37 Effect.repeat({
38 schedule: Schedule.spaced("1 second"),
39 until: (status) => status === "gone",
40 times: 10,
41 }),
42 );
43
44test.provider(
45 "create, update, and delete a terminal configuration",
46 (stack) =>
47 Effect.gen(function* () {
48 yield* stack.destroy();
49
50 const created = yield* stack.deploy(
51 Effect.gen(function* () {
52 return yield* Stripe.TerminalConfiguration("Storefront", {
53 name: "Alchemy Terminal Config",
54 offline: { enabled: true },
55 tipping: {
56 usd: {
57 fixedAmounts: [100, 200, 300],
58 percentages: [15, 20, 25],
59 smartTipThreshold: 1000,
60 },
61 },
62 rebootWindow: { startHour: 2, endHour: 4 },
63 });
64 }),
65 );
66
67 expect(created.id).toMatch(/^tmc_/);
68 expect(created.name).toEqual("Alchemy Terminal Config");
69 expect(created.isAccountDefault).toEqual(false);
70 expect(created.offline).toEqual({ enabled: true });
71 expect(created.tipping?.usd?.fixedAmounts).toEqual([100, 200, 300]);
72 expect(created.tipping?.usd?.percentages).toEqual([15, 20, 25]);
73 expect(created.tipping?.usd?.smartTipThreshold).toEqual(1000);
74 expect(created.rebootWindow).toEqual({ startHour: 2, endHour: 4 });
75 expect(created.livemode).toEqual(false);
76
77 const fetched = yield* GetTerminalConfiguration({
78 configuration: created.id,
79 });
80 expect(isDeletedConfiguration(fetched)).toEqual(false);
81 if (isDeletedConfiguration(fetched)) {
82 return;
83 }
84 expect(fetched.id).toEqual(created.id);
85 expect(fetched.name).toEqual("Alchemy Terminal Config");
86 expect(fetched.is_account_default).toEqual(false);
87 expect(fetched.offline?.enabled).toEqual(true);
88 expect(fetched.tipping?.usd?.fixed_amounts).toEqual([100, 200, 300]);
89 expect(fetched.tipping?.usd?.percentages).toEqual([15, 20, 25]);
90 expect(fetched.tipping?.usd?.smart_tip_threshold).toEqual(1000);
91 expect(fetched.reboot_window?.start_hour).toEqual(2);
92 expect(fetched.reboot_window?.end_hour).toEqual(4);
93
94 const updated = yield* stack.deploy(
95 Effect.gen(function* () {
96 return yield* Stripe.TerminalConfiguration("Storefront", {
97 name: "Alchemy Terminal Config Updated",
98 offline: { enabled: false },
99 tipping: {
100 usd: {
101 fixedAmounts: [200, 300, 400],
102 percentages: [10, 15, 20],
103 smartTipThreshold: 2000,
104 },
105 },
106 rebootWindow: { startHour: 3, endHour: 5 },
107 });
108 }),
109 );
110
111 expect(updated.id).toEqual(created.id);
112 expect(updated.name).toEqual("Alchemy Terminal Config Updated");
113 expect(updated.isAccountDefault).toEqual(false);
114 expect(updated.offline).toEqual({ enabled: false });
115 expect(updated.tipping?.usd?.fixedAmounts).toEqual([200, 300, 400]);
116 expect(updated.tipping?.usd?.percentages).toEqual([10, 15, 20]);
117 expect(updated.tipping?.usd?.smartTipThreshold).toEqual(2000);
118 expect(updated.rebootWindow).toEqual({ startHour: 3, endHour: 5 });
119
120 const refetched = yield* GetTerminalConfiguration({
121 configuration: updated.id,
122 });
123 expect(isDeletedConfiguration(refetched)).toEqual(false);
124 if (isDeletedConfiguration(refetched)) {
125 return;
126 }
127 expect(refetched.id).toEqual(updated.id);
128 expect(refetched.name).toEqual("Alchemy Terminal Config Updated");
129 expect(refetched.offline?.enabled).toEqual(false);
130 expect(refetched.tipping?.usd?.fixed_amounts).toEqual([200, 300, 400]);
131 expect(refetched.tipping?.usd?.percentages).toEqual([10, 15, 20]);
132 expect(refetched.tipping?.usd?.smart_tip_threshold).toEqual(2000);
133 expect(refetched.reboot_window?.start_hour).toEqual(3);
134 expect(refetched.reboot_window?.end_hour).toEqual(5);
135
136 yield* stack.destroy();
137
138 const gone = yield* waitUntilGone(created.id);
139 expect(gone).toEqual("gone");
140 }).pipe(logLevel),
141 {
142 tags: ["provider:stripe", "provider:stripe:terminalconfiguration", "live"],
143 timeout: 120_000,
144 },
145);
146
147test.provider(
148 "list enumerates the deployed terminal configuration",
149 (stack) =>
150 Effect.gen(function* () {
151 yield* stack.destroy();
152
153 const deployed = yield* stack.deploy(
154 Effect.gen(function* () {
155 return yield* Stripe.TerminalConfiguration("ListStorefront", {
156 name: "Alchemy List Terminal Config",
157 offline: { enabled: true },
158 });
159 }),
160 );
161
162 const provider = yield* Provider.findProvider(
163 Stripe.TerminalConfiguration,
164 );
165 const all = yield* provider.list();
166 const found = all.find(
167 (configuration) => configuration.id === deployed.id,
168 );
169 expect(found).toBeDefined();
170 expect(found?.name).toEqual(deployed.name);
171 expect(found?.isAccountDefault).toEqual(false);
172 expect(found?.offline).toEqual({ enabled: true });
173
174 yield* stack.destroy();
175
176 const gone = yield* waitUntilGone(deployed.id);
177 expect(gone).toEqual("gone");
178
179 const after = yield* provider.list();
180 expect(
181 after.find((configuration) => configuration.id === deployed.id),
182 ).toBeUndefined();
183 }).pipe(logLevel),
184 {
185 tags: ["provider:stripe", "provider:stripe:terminalconfiguration", "live"],
186 timeout: 120_000,
187 },
188);