1import * as AWS from "@/AWS";
2import { UserPool, UserPoolDomain } from "@/AWS/Cognito";
3import * as Test from "@/Test/Alchemy";
4import * as cip from "@distilled.cloud/aws/cognito-identity-provider";
5import { expect } from "alchemy-test";
6import * as Data from "effect/Data";
7import * as Effect from "effect/Effect";
8import * as Schedule from "effect/Schedule";
9
10const { test } = Test.make({ providers: AWS.providers() });
11
12class DomainStillExists extends Data.TaggedError("DomainStillExists")<{
13 readonly domain: string;
14}> {}
15
16const assertDomainDeleted = (domain: string) =>
17 cip.describeUserPoolDomain({ Domain: domain }).pipe(
18 Effect.flatMap((r) =>
19 r.DomainDescription?.UserPoolId === undefined
20 ? Effect.void
21 : Effect.fail(new DomainStillExists({ domain })),
22 ),
23 Effect.retry({
24 while: (e) => e._tag === "DomainStillExists",
25 schedule: Schedule.max([Schedule.exponential(500), Schedule.recurs(8)]),
26 }),
27 );
28
29test.provider(
30 "cognito-prefix domain lifecycle",
31 (stack) =>
32 Effect.gen(function* () {
33 yield* stack.destroy();
34
35 const outputs = yield* stack.deploy(
36 Effect.gen(function* () {
37 const pool = yield* UserPool("DomainTestPool", {});
38 const domain = yield* UserPoolDomain("AuthDomain", {
39 userPoolId: pool.userPoolId,
40 });
41 return { pool, domain };
42 }),
43 );
44
45 expect(outputs.domain.domain).toMatch(/^[a-z0-9-]+$/);
46 expect(outputs.domain.domain).not.toContain("cognito");
47 expect(outputs.domain.domain).not.toContain("aws");
48 expect(outputs.domain.userPoolId).toBe(outputs.pool.userPoolId);
49 expect(outputs.domain.cloudFrontDomain).toBeTruthy();
50
51 // out-of-band verification via distilled
52 const described = yield* cip.describeUserPoolDomain({
53 Domain: outputs.domain.domain,
54 });
55 expect(described.DomainDescription?.UserPoolId).toBe(
56 outputs.pool.userPoolId,
57 );
58 expect(described.DomainDescription?.Status).toBe("ACTIVE");
59
60 // no-op deploy converges without error
61 const noop = yield* stack.deploy(
62 Effect.gen(function* () {
63 const pool = yield* UserPool("DomainTestPool", {});
64 const domain = yield* UserPoolDomain("AuthDomain", {
65 userPoolId: pool.userPoolId,
66 });
67 return { pool, domain };
68 }),
69 );
70 expect(noop.domain.domain).toBe(outputs.domain.domain);
71
72 yield* stack.destroy();
73 yield* assertDomainDeleted(outputs.domain.domain);
74 }),
75 { tags: ["provider:aws", "provider:aws:cognito", "live"], timeout: 180_000 },
76);