1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as reviews from "@distilled.cloud/gcp/merchantapi_reviews_v1beta";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import * as Schedule from "effect/Schedule";
7import {
8 accountId,
9 logLevel,
10 merchantReviewDataSource,
11 probeAccount,
12 probeDataSource,
13 runMerchantReviewLifecycle,
14} from "./common.ts";
15
16const { test } = Test.make({ providers: GCP.providers() });
17
18const waitUntilGone = (name: string) =>
19 reviews.getAccountsMerchantReviews({ name }).pipe(
20 Effect.as("found" as const),
21 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
22 Effect.repeat({
23 schedule: Schedule.spaced("1 second"),
24 until: (status) => status === "gone",
25 times: 10,
26 }),
27 );
28
29test.provider.skipIf(!runMerchantReviewLifecycle)(
30 "getAccountsMerchantReviews on a missing review fails with a typed tag",
31 (stack) =>
32 Effect.gen(function* () {
33 yield* stack.destroy();
34
35 const error = yield* Effect.flip(
36 reviews.getAccountsMerchantReviews({
37 name: `accounts/${probeAccount}/merchantReviews/alchemy-missing-merchant-review`,
38 }),
39 );
40 expect(error._tag).toEqual("NotFound");
41
42 yield* stack.destroy();
43 }).pipe(logLevel),
44 {
45 tags: ["provider:gcp", "provider:gcp:merchantapireviews", "live"],
46 timeout: 90_000,
47 },
48);
49
50test.provider.skipIf(runMerchantReviewLifecycle)(
51 "insertAccountsMerchantReviews without Merchant Reviews access fails with InsufficientScopes",
52 (stack) =>
53 Effect.gen(function* () {
54 yield* stack.destroy();
55
56 const error = yield* Effect.flip(
57 reviews.insertAccountsMerchantReviews({
58 parent: `accounts/${probeAccount}`,
59 dataSource: probeDataSource(merchantReviewDataSource),
60 body: {
61 merchantReviewId: "alchemy-probe-merchant-review",
62 merchantReviewAttributes: {
63 merchantId: probeAccount,
64 reviewTime: "2020-01-01T00:00:00Z",
65 content: "probe",
66 title: "Alchemy Probe Merchant Review",
67 },
68 },
69 }),
70 );
71 expect(error._tag).toEqual("InsufficientScopes");
72
73 yield* stack.destroy();
74 }).pipe(logLevel),
75 {
76 tags: ["provider:gcp", "provider:gcp:merchantapireviews", "live"],
77 timeout: 90_000,
78 },
79);
80
81test.provider.skipIf(!runMerchantReviewLifecycle)(
82 "create, update, and delete a merchant review",
83 (stack) =>
84 Effect.gen(function* () {
85 yield* stack.destroy();
86
87 const created = yield* stack.deploy(
88 Effect.gen(function* () {
89 return yield* GCP.MerchantApiReviews.MerchantReview("Storefront", {
90 account: accountId!,
91 dataSource: merchantReviewDataSource!,
92 merchantReviewAttributes: {
93 title: "Great shop",
94 content: "Fast shipping",
95 rating: 5,
96 },
97 });
98 }),
99 );
100
101 expect(created.merchantReviewId.length).toBeGreaterThan(0);
102 expect(created.name).toContain("/merchantReviews/");
103 expect(created.account).toEqual(accountId);
104 expect(created.merchantReviewAttributes?.title).toEqual("Great shop");
105 expect(created.merchantReviewAttributes?.content).toEqual(
106 "Fast shipping",
107 );
108
109 const fetched = yield* reviews.getAccountsMerchantReviews({
110 name: created.name,
111 });
112 expect(fetched.merchantReviewId).toEqual(created.merchantReviewId);
113 // Review text is shown to shoppers: no ownership marker.
114 expect(fetched.merchantReviewAttributes?.content).toEqual(
115 created.merchantReviewAttributes?.content,
116 );
117 expect(fetched.merchantReviewAttributes?.title).toEqual("Great shop");
118
119 const updated = yield* stack.deploy(
120 Effect.gen(function* () {
121 return yield* GCP.MerchantApiReviews.MerchantReview("Storefront", {
122 account: created.account,
123 dataSource: merchantReviewDataSource!,
124 merchantReviewId: created.merchantReviewId,
125 merchantReviewAttributes: {
126 title: "Even better",
127 content: "Fast shipping and packing",
128 rating: 5,
129 },
130 });
131 }),
132 );
133
134 expect(updated.merchantReviewId).toEqual(created.merchantReviewId);
135 expect(updated.merchantReviewAttributes?.title).toEqual("Even better");
136 expect(updated.merchantReviewAttributes?.content).toEqual(
137 "Fast shipping and packing",
138 );
139
140 yield* stack.destroy();
141
142 const gone = yield* waitUntilGone(created.name);
143 expect(gone).toEqual("gone");
144 }).pipe(logLevel),
145 {
146 tags: ["provider:gcp", "provider:gcp:merchantapireviews", "live"],
147 timeout: 90_000,
148 },
149);