import { expect, it } from "@effect/vitest"; import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import { vi } from "vite-plus/test"; import { remoteHttpClientLayer } from "@t3tools/client-runtime/rpc"; import { withRelayClientTracing } from "@t3tools/shared/relayTracing"; import { makeTracingLayer } from "./tracing"; vi.mock("expo-constants", () => ({ default: { expoConfig: { extra: {}, }, }, })); it.effect("exports spans through the scoped mobile OTLP layer", () => { const fetchFn = vi.fn(async () => new Response(null, { status: 202 })); const tracingLayer = makeTracingLayer( { tracesUrl: "https://api.axiom.test/v1/traces", tracesDataset: "mobile-traces", tracesToken: "public-ingest-token", }, { appVariant: "test", serviceVersion: "1.2.3", }, ).pipe(Layer.provide(remoteHttpClientLayer(fetchFn))); const tracedApplication = Layer.effectDiscard( Effect.void.pipe(Effect.withSpan("mobile.test.span"), withRelayClientTracing), ).pipe(Layer.provide(tracingLayer)); return Effect.gen(function* () { yield* Layer.build(tracedApplication); expect(fetchFn).not.toHaveBeenCalled(); }).pipe( Effect.scoped, Effect.andThen( Effect.sync(() => { expect(fetchFn).toHaveBeenCalledOnce(); const [url, init] = fetchFn.mock.calls[0]!; expect(String(url)).toBe("https://api.axiom.test/v1/traces"); expect(new Headers(init?.headers).get("authorization")).toBe("Bearer public-ingest-token"); expect(new Headers(init?.headers).get("x-axiom-dataset")).toBe("mobile-traces"); expect(new TextDecoder().decode(init?.body as Uint8Array)).toContain("mobile.test.span"); }), ), ); }); it.effect("does not let OTLP serialization failures alter application effects", () => { const fetchFn = vi.fn(async () => new Response(null, { status: 202 })); const tracingLayer = makeTracingLayer( { tracesUrl: "https://api.axiom.test/v1/traces", tracesDataset: "mobile-traces", tracesToken: "public-ingest-token", }, { appVariant: "test", serviceVersion: "1.2.3", }, ).pipe(Layer.provide(remoteHttpClientLayer(fetchFn))); const failure = { durationNanos: 1n }; const tracedApplication = Layer.effectDiscard( Effect.fail(failure).pipe( Effect.withSpan("mobile.test.failed-span"), withRelayClientTracing, Effect.exit, Effect.flatMap((exit) => { const reason = exit._tag === "Failure" ? exit.cause.reasons[0] : undefined; return reason && Cause.isFailReason(reason) ? Effect.sync(() => { expect(reason.error).toBe(failure); }) : Effect.die(new Error("Expected the original typed failure.")); }), ), ).pipe(Layer.provide(tracingLayer)); return Layer.build(tracedApplication).pipe( Effect.scoped, Effect.andThen( Effect.sync(() => { expect(fetchFn).toHaveBeenCalledOnce(); expect(new TextDecoder().decode(fetchFn.mock.calls[0]?.[1]?.body as Uint8Array)).toContain( "mobile.test.failed-span", ); }), ), ); });