import { describe, expect, test, vi } from "vitest"; import { normalizeAppUrl, requestActivityCheck } from "../extensions/thank-you-activity/src/activity-api"; describe("checkout extension activity api", () => { test("normalizes only HTTPS app URLs", () => { expect(normalizeAppUrl("https://app.example.com/")).toBe("https://app.example.com"); expect(normalizeAppUrl(" https://app.example.com/path/ ")).toBe("https://app.example.com/path"); expect(normalizeAppUrl("http://localhost:3000")).toBeNull(); expect(normalizeAppUrl("")).toBeNull(); }); test("posts order context with a fresh checkout session token", async () => { const fetchImpl = vi.fn(async () => new Response( JSON.stringify({ success: true, redirectUrl: "https://activity.example.com", buttonText: "Claim", }), { status: 200 }, ), ); const getSessionToken = vi.fn(async () => "checkout-token"); const result = await requestActivityCheck({ appUrl: "https://app.example.com/", order: { id: "gid://shopify/Order/123", name: "#1001", }, locale: "en", getSessionToken, fetchImpl, timeoutMs: 100, }); expect(result).toEqual({ success: true, redirectUrl: "https://activity.example.com", buttonText: "Claim", }); expect(getSessionToken).toHaveBeenCalledOnce(); expect(fetchImpl).toHaveBeenCalledWith( "https://app.example.com/api/action/activity/check", expect.objectContaining({ method: "POST", cache: "no-store", headers: { Authorization: "Bearer checkout-token", "Content-Type": "application/json", }, body: JSON.stringify({ orderId: "gid://shopify/Order/123", orderNumber: "#1001", locale: "en", }), signal: expect.any(AbortSignal), }), ); }); test("returns hidden state for non-2xx and invalid JSON responses", async () => { const nonOk = await requestActivityCheck({ appUrl: "https://app.example.com", order: { id: "gid://shopify/Order/123" }, locale: "en", getSessionToken: async () => "checkout-token", fetchImpl: async () => new Response(JSON.stringify({ success: true }), { status: 500 }), timeoutMs: 100, }); const invalidJson = await requestActivityCheck({ appUrl: "https://app.example.com", order: { id: "gid://shopify/Order/123" }, locale: "en", getSessionToken: async () => "checkout-token", fetchImpl: async () => new Response("not json", { status: 200 }), timeoutMs: 100, }); expect(nonOk).toEqual({ success: false }); expect(invalidJson).toEqual({ success: false }); }); test("does not call the backend when app URL or order ID is unavailable", async () => { const fetchImpl = vi.fn(); const invalidUrl = await requestActivityCheck({ appUrl: "http://localhost:3000", order: { id: "gid://shopify/Order/123" }, locale: "en", getSessionToken: async () => "checkout-token", fetchImpl, timeoutMs: 100, }); const missingOrder = await requestActivityCheck({ appUrl: "https://app.example.com", order: undefined, locale: "en", getSessionToken: async () => "checkout-token", fetchImpl, timeoutMs: 100, }); expect(invalidUrl).toEqual({ success: false }); expect(missingOrder).toEqual({ success: false }); expect(fetchImpl).not.toHaveBeenCalled(); }); });