1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import { GetPromotionCode } 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 waitUntilInactive = (id: string) =>
19 GetPromotionCode({ promotion_code: id }).pipe(
20 Effect.map((promo) =>
21 promo.active ? ("active" as const) : ("inactive" as const),
22 ),
23 Effect.catchIf(isMissingStripeResource, () =>
24 Effect.succeed("gone" as const),
25 ),
26 Effect.repeat({
27 schedule: Schedule.spaced("1 second"),
28 until: (status) => status === "inactive" || status === "gone",
29 times: 8,
30 }),
31 );
32
33test.provider(
34 "create, update, and deactivate a promotion code",
35 (stack) =>
36 Effect.gen(function* () {
37 yield* stack.destroy();
38
39 const created = yield* stack.deploy(
40 Effect.gen(function* () {
41 const coupon = yield* Stripe.Coupon("WelcomeCoupon", {
42 percentOff: 15,
43 duration: "once",
44 name: "Alchemy Promo CRUD",
45 });
46 return yield* Stripe.PromotionCode("WelcomeCode", {
47 coupon: coupon.id,
48 metadata: { env: "test" },
49 });
50 }),
51 );
52
53 expect(created.id).toEqual(expect.any(String));
54 expect(created.code).toEqual(expect.any(String));
55 expect(created.active).toEqual(true);
56 expect(created.couponId).toEqual(expect.any(String));
57 expect(created.metadata).toMatchObject({ env: "test" });
58 expect(created.livemode).toEqual(false);
59
60 const fetched = yield* GetPromotionCode({
61 promotion_code: created.id,
62 });
63 expect(fetched.id).toEqual(created.id);
64 expect(fetched.code).toEqual(created.code);
65 expect(fetched.active).toEqual(true);
66 expect(fetched.metadata?.env).toEqual("test");
67 expect(
68 fetched.metadata?.[Stripe.alchemyMetadataKeys.stack],
69 ).toBeDefined();
70 expect(
71 fetched.metadata?.[Stripe.alchemyMetadataKeys.stage],
72 ).toBeDefined();
73 expect(fetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
74
75 const updated = yield* stack.deploy(
76 Effect.gen(function* () {
77 const coupon = yield* Stripe.Coupon("WelcomeCoupon", {
78 percentOff: 15,
79 duration: "once",
80 name: "Alchemy Promo CRUD",
81 });
82 return yield* Stripe.PromotionCode("WelcomeCode", {
83 coupon: coupon.id,
84 metadata: { env: "prod", campaign: "spring" },
85 });
86 }),
87 );
88
89 expect(updated.id).toEqual(created.id);
90 expect(updated.metadata).toMatchObject({
91 env: "prod",
92 campaign: "spring",
93 });
94
95 const refetched = yield* GetPromotionCode({
96 promotion_code: updated.id,
97 });
98 expect(refetched.metadata?.env).toEqual("prod");
99 expect(refetched.metadata?.campaign).toEqual("spring");
100 expect(refetched.active).toEqual(true);
101
102 yield* stack.destroy();
103
104 const inactive = yield* waitUntilInactive(created.id);
105 expect(inactive === "inactive" || inactive === "gone").toEqual(true);
106 if (inactive === "inactive") {
107 const deactivated = yield* GetPromotionCode({
108 promotion_code: created.id,
109 });
110 expect(deactivated.active).toEqual(false);
111 }
112 }).pipe(logLevel),
113 {
114 tags: [
115 "provider:stripe",
116 "provider:stripe:coupon",
117 "provider:stripe:promotioncode",
118 "live",
119 ],
120 timeout: 120_000,
121 },
122);
123
124test.provider(
125 "list enumerates the deployed promotion code",
126 (stack) =>
127 Effect.gen(function* () {
128 yield* stack.destroy();
129
130 const deployed = yield* stack.deploy(
131 Effect.gen(function* () {
132 const coupon = yield* Stripe.Coupon("ListCoupon", {
133 percentOff: 10,
134 duration: "once",
135 name: "Alchemy Promo List",
136 });
137 return yield* Stripe.PromotionCode("ListCode", {
138 coupon: coupon.id,
139 });
140 }),
141 );
142
143 const provider = yield* Provider.findProvider(Stripe.PromotionCode);
144 const all = yield* provider.list();
145 const found = all.find((item) => item.id === deployed.id);
146 expect(found).toBeDefined();
147 expect(found?.code).toEqual(deployed.code);
148 expect(found?.active).toEqual(true);
149
150 yield* stack.destroy();
151 }).pipe(logLevel),
152 {
153 tags: [
154 "provider:stripe",
155 "provider:stripe:coupon",
156 "provider:stripe:promotioncode",
157 "live",
158 ],
159 timeout: 120_000,
160 },
161);