1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import { GetShippingRate } 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 isMissing = isMissingStripeResource;
19
20const waitUntilDeactivated = (id: string) =>
21 GetShippingRate({ shipping_rate_token: id }).pipe(
22 Effect.map((rate) =>
23 rate.active ? ("active" as const) : ("inactive" as const),
24 ),
25 Effect.catchIf(isMissing, () => Effect.succeed("inactive" as const)),
26 Effect.repeat({
27 schedule: Schedule.spaced("1 second"),
28 until: (status) => status === "inactive",
29 times: 10,
30 }),
31 );
32
33test.provider(
34 "create, update, and deactivate a shipping rate",
35 (stack) =>
36 Effect.gen(function* () {
37 yield* stack.destroy();
38
39 const created = yield* stack.deploy(
40 Effect.gen(function* () {
41 return yield* Stripe.ShippingRate("GroundRate", {
42 displayName: "Alchemy Ground",
43 amount: 500,
44 currency: "usd",
45 deliveryEstimate: {
46 minimum: { unit: "business_day", value: 5 },
47 maximum: { unit: "business_day", value: 7 },
48 },
49 metadata: { region: "us" },
50 });
51 }),
52 );
53
54 expect(created.id).toMatch(/^shr_/);
55 expect(created.displayName).toEqual("Alchemy Ground");
56 expect(created.type).toEqual("fixed_amount");
57 expect(created.amount).toEqual(500);
58 expect(created.currency).toEqual("usd");
59 expect(created.active).toEqual(true);
60 expect(created.deliveryEstimate).toEqual({
61 minimum: { unit: "business_day", value: 5 },
62 maximum: { unit: "business_day", value: 7 },
63 });
64 expect(created.metadata).toMatchObject({ region: "us" });
65 expect(created.livemode).toEqual(false);
66
67 const fetched = yield* GetShippingRate({
68 shipping_rate_token: created.id,
69 });
70 expect(fetched.id).toEqual(created.id);
71 expect(fetched.display_name).toEqual("Alchemy Ground");
72 expect(fetched.fixed_amount?.amount).toEqual(500);
73 expect(fetched.fixed_amount?.currency).toEqual("usd");
74 expect(fetched.active).toEqual(true);
75 expect(fetched.metadata?.region).toEqual("us");
76 expect(
77 fetched.metadata?.[Stripe.alchemyMetadataKeys.stack],
78 ).toBeDefined();
79 expect(
80 fetched.metadata?.[Stripe.alchemyMetadataKeys.stage],
81 ).toBeDefined();
82 expect(fetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
83
84 const updated = yield* stack.deploy(
85 Effect.gen(function* () {
86 return yield* Stripe.ShippingRate("GroundRate", {
87 displayName: "Alchemy Ground",
88 amount: 500,
89 currency: "usd",
90 deliveryEstimate: {
91 minimum: { unit: "business_day", value: 5 },
92 maximum: { unit: "business_day", value: 7 },
93 },
94 taxBehavior: "exclusive",
95 metadata: { region: "us", channel: "web" },
96 });
97 }),
98 );
99
100 expect(updated.id).toEqual(created.id);
101 expect(updated.active).toEqual(true);
102 expect(updated.taxBehavior).toEqual("exclusive");
103 expect(updated.metadata).toEqual({ region: "us", channel: "web" });
104
105 const refetched = yield* GetShippingRate({
106 shipping_rate_token: updated.id,
107 });
108 expect(refetched.active).toEqual(true);
109 expect(refetched.tax_behavior).toEqual("exclusive");
110 expect(refetched.metadata?.region).toEqual("us");
111 expect(refetched.metadata?.channel).toEqual("web");
112 expect(refetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
113
114 yield* stack.destroy();
115
116 const deactivated = yield* waitUntilDeactivated(created.id);
117 expect(deactivated).toEqual("inactive");
118 }).pipe(logLevel),
119 {
120 tags: ["provider:stripe", "provider:stripe:shippingrate", "live"],
121 timeout: 120_000,
122 },
123);
124
125test.provider(
126 "list enumerates the deployed shipping rate",
127 (stack) =>
128 Effect.gen(function* () {
129 yield* stack.destroy();
130
131 const deployed = yield* stack.deploy(
132 Effect.gen(function* () {
133 return yield* Stripe.ShippingRate("ListRate", {
134 displayName: "Alchemy List Rate",
135 amount: 799,
136 currency: "usd",
137 metadata: { kind: "list" },
138 });
139 }),
140 );
141
142 const provider = yield* Provider.findProvider(Stripe.ShippingRate);
143 const all = yield* provider.list();
144 const found = all.find((rate) => rate.id === deployed.id);
145 expect(found).toBeDefined();
146 expect(found?.displayName).toEqual(deployed.displayName);
147 expect(found?.metadata).toMatchObject({ kind: "list" });
148 expect(found?.amount).toEqual(799);
149
150 yield* stack.destroy();
151
152 const deactivated = yield* waitUntilDeactivated(deployed.id);
153 expect(deactivated).toEqual("inactive");
154
155 const after = yield* provider.list();
156 expect(after.find((rate) => rate.id === deployed.id)).toBeUndefined();
157 }).pipe(logLevel),
158 {
159 tags: ["provider:stripe", "provider:stripe:shippingrate", "live"],
160 timeout: 120_000,
161 },
162);
163
164test.provider(
165 "replace when amount changes",
166 (stack) =>
167 Effect.gen(function* () {
168 yield* stack.destroy();
169
170 const created = yield* stack.deploy(
171 Effect.gen(function* () {
172 return yield* Stripe.ShippingRate("ReplaceRate", {
173 displayName: "Alchemy Replace Rate",
174 amount: 1000,
175 currency: "usd",
176 metadata: { version: "v1" },
177 });
178 }),
179 );
180
181 const replaced = yield* stack.deploy(
182 Effect.gen(function* () {
183 return yield* Stripe.ShippingRate("ReplaceRate", {
184 displayName: "Alchemy Replace Rate",
185 amount: 2500,
186 currency: "usd",
187 metadata: { version: "v2" },
188 });
189 }),
190 );
191
192 expect(replaced.id).not.toEqual(created.id);
193 expect(replaced.amount).toEqual(2500);
194 expect(replaced.metadata).toMatchObject({ version: "v2" });
195
196 const newFetched = yield* GetShippingRate({
197 shipping_rate_token: replaced.id,
198 });
199 expect(newFetched.fixed_amount?.amount).toEqual(2500);
200
201 const oldFetched = yield* GetShippingRate({
202 shipping_rate_token: created.id,
203 });
204 expect(oldFetched.active).toEqual(false);
205
206 yield* stack.destroy();
207
208 const deactivated = yield* waitUntilDeactivated(replaced.id);
209 expect(deactivated).toEqual("inactive");
210 }).pipe(logLevel),
211 {
212 tags: ["provider:stripe", "provider:stripe:shippingrate", "live"],
213 timeout: 120_000,
214 },
215);