t3-code-android-nightly/.repos/alchemy-effect/packages/alchemy/test/AWS/ApiGatewayV2/Bindings.test.ts
Julius Marminge 6f9cea00ae
chore(refs): sync Effect and Alchemy references to 4.0.1 and beta.80 (#16170)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 13:22:30 -07:00

90 lines
2.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as AWS from "@/AWS";
import * as Test from "@/Test/Alchemy";
import { expect } from "alchemy-test";
import * as Duration from "effect/Duration";
import * as Effect from "effect/Effect";
import * as Schedule from "effect/Schedule";
import * as HttpClient from "effect/http/HttpClient";
import * as HttpClientRequest from "effect/http/HttpClientRequest";
import ApiGatewayV2BindingsFunctionLive, {
ApiGatewayV2BindingsFunction,
} from "./bindings-handler.ts";
const { test } = Test.make({ providers: AWS.providers() });
// Fresh Lambda function URLs return transient errors for the first
// 30–90s (DNS, IAM propagation, cold init). Poll at a steady cadence.
const readinessSchedule = Schedule.max([
Schedule.exponential(500).pipe(
Schedule.modifyDelay(({ duration: d }) =>
Effect.succeed(
Duration.isGreaterThan(d, Duration.seconds(10))
? Duration.seconds(10)
: d,
),
),
),
Schedule.recurs(20),
]);
const getJson = (url: string) =>
HttpClient.get(url).pipe(
Effect.flatMap((response) =>
response.status === 200
? response.json
: Effect.fail(new Error(`GET ${url} returned ${response.status}`)),
),
);
const postJson = (url: string) =>
HttpClient.execute(HttpClientRequest.post(url)).pipe(
Effect.flatMap((response) =>
response.status === 200
? response.json
: Effect.fail(new Error(`POST ${url} returned ${response.status}`)),
),
);
test.provider.skipIf(!!process.env.FAST)(
"ApiGatewayV2 bindings export the API and reset authorizer caches from a Lambda",
(stack) =>
Effect.gen(function* () {
yield* stack.destroy();
const { functionUrl } = yield* stack.deploy(
Effect.gen(function* () {
return yield* ApiGatewayV2BindingsFunction;
}).pipe(Effect.provide(ApiGatewayV2BindingsFunctionLive)),
);
expect(functionUrl).toBeTruthy();
const baseUrl = functionUrl!.replace(/\/+$/, "");
// ExportApi — the live OpenAPI 3.0 document includes the fixture's
// route (retried through cold start).
const exported = (yield* getJson(`${baseUrl}/export`).pipe(
Effect.retry({ schedule: readinessSchedule }),
)) as { openapi?: string; paths: string[] };
expect(exported.openapi ?? "").toContain("3.0");
expect(exported.paths).toContain("/ping");
// ResetAuthorizersCache — the stage has no authorizer cache, so the
// API answers 200 (or a typed NotFound the route reports as
// flushed:false). A missing IAM grant would 500 the route instead.
const reset = (yield* postJson(`${baseUrl}/reset-authorizers`)) as {
flushed: boolean;
};
expect(typeof reset.flushed).toBe("boolean");
yield* stack.destroy();
}),
{
tags: [
"provider:aws",
"provider:aws:apigatewayv2",
"provider:aws:lambda",
"live",
],
timeout: 600_000,
},
);