1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as androidenterprise from "@distilled.cloud/gcp/androidenterprise_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import * as Schedule from "effect/Schedule";
7import {
8 enterpriseId,
9 logLevel,
10 probeEnterpriseId,
11 runLifecycle,
12} from "./common.ts";
13
14const { test } = Test.make({ providers: GCP.providers() });
15
16const waitUntilGone = (accountId: string, pageId: string) =>
17 androidenterprise
18 .getStorelayoutpages({ enterpriseId: accountId, pageId })
19 .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(!runLifecycle)(
30 "getStorelayoutpages on a missing page fails with a typed tag",
31 (stack) =>
32 Effect.gen(function* () {
33 yield* stack.destroy();
34
35 const error = yield* Effect.flip(
36 androidenterprise.getStorelayoutpages({
37 enterpriseId: probeEnterpriseId,
38 pageId: "alchemy-missing-page",
39 }),
40 );
41 expect(error._tag).toEqual("NotFound");
42
43 yield* stack.destroy();
44 }).pipe(logLevel),
45 {
46 tags: ["provider:gcp", "provider:gcp:androidenterprise", "live"],
47 timeout: 90_000,
48 },
49);
50
51test.provider.skipIf(runLifecycle)(
52 "insertStorelayoutpages without the EMM OAuth scope fails with InsufficientAuthenticationScopes",
53 (stack) =>
54 Effect.gen(function* () {
55 yield* stack.destroy();
56
57 const error = yield* Effect.flip(
58 androidenterprise.insertStorelayoutpages({
59 enterpriseId: probeEnterpriseId,
60 body: {
61 name: [{ locale: "en-US", text: "Alchemy Probe Page" }],
62 },
63 }),
64 );
65 expect(error._tag).toEqual("InsufficientAuthenticationScopes");
66
67 yield* stack.destroy();
68 }).pipe(logLevel),
69 {
70 tags: ["provider:gcp", "provider:gcp:androidenterprise", "live"],
71 timeout: 90_000,
72 },
73);
74
75test.provider.skipIf(!runLifecycle)(
76 "create, update, and delete a store layout page",
77 (stack) =>
78 Effect.gen(function* () {
79 yield* stack.destroy();
80
81 const created = yield* stack.deploy(
82 Effect.gen(function* () {
83 return yield* GCP.AndroidEnterprise.Storelayoutpage("Home", {
84 enterpriseId: enterpriseId!,
85 name: [{ locale: "en-US", text: "Home" }],
86 });
87 }),
88 );
89
90 expect(created.pageId.length).toBeGreaterThan(0);
91 expect(created.enterpriseId).toEqual(enterpriseId);
92 expect(created.name?.[0]?.text).toEqual("Home");
93
94 const fetched = yield* androidenterprise.getStorelayoutpages({
95 enterpriseId: created.enterpriseId,
96 pageId: created.pageId,
97 });
98 expect(fetched.id).toEqual(created.pageId);
99 expect(fetched.name?.[0]?.text).toEqual("Home");
100
101 const updated = yield* stack.deploy(
102 Effect.gen(function* () {
103 return yield* GCP.AndroidEnterprise.Storelayoutpage("Home", {
104 enterpriseId: created.enterpriseId,
105 pageId: created.pageId,
106 name: [{ locale: "en-US", text: "Featured" }],
107 });
108 }),
109 );
110
111 expect(updated.pageId).toEqual(created.pageId);
112 expect(updated.name?.[0]?.text).toEqual("Featured");
113
114 yield* stack.destroy();
115
116 const gone = yield* waitUntilGone(created.enterpriseId, created.pageId);
117 expect(gone).toEqual("gone");
118 }).pipe(logLevel),
119 {
120 tags: ["provider:gcp", "provider:gcp:androidenterprise", "live"],
121 timeout: 90_000,
122 },
123);