diff --git a/src/app/api/referrals/code/route.test.ts b/src/app/api/referrals/code/route.test.ts index 3a7524e4..a3ceda46 100644 --- a/src/app/api/referrals/code/route.test.ts +++ b/src/app/api/referrals/code/route.test.ts @@ -7,13 +7,35 @@ vi.mock("@/lib/auth/get-user", () => ({ getAuthContext: (...args: unknown[]) => mockGetAuthContext(...args), })); -function makeRequest() { - return new NextRequest("http://localhost/api/referrals/code", { method: "GET" }); +function makeRequest(origin = "http://localhost") { + return new NextRequest(`${origin}/api/referrals/code`, { method: "GET" }); +} + +function mockProfile(profile: { referral_code: string | null; username: string }) { + const mockSupabase = { + from: () => ({ + select: () => ({ + eq: () => ({ + single: () => + Promise.resolve({ + data: profile, + error: null, + }), + }), + }), + }), + }; + + mockGetAuthContext.mockResolvedValue({ + user: { id: "user1" }, + supabase: mockSupabase, + }); } describe("GET /api/referrals/code", () => { beforeEach(() => { vi.clearAllMocks(); + vi.unstubAllEnvs(); }); it("should return 401 when not authenticated", async () => { @@ -23,30 +45,24 @@ describe("GET /api/referrals/code", () => { }); it("should return referral code and link", async () => { - const mockSupabase = { - from: () => ({ - select: () => ({ - eq: () => ({ - single: () => - Promise.resolve({ - data: { referral_code: "johndoe", username: "johndoe" }, - error: null, - }), - }), - }), - }), - }; - - mockGetAuthContext.mockResolvedValue({ - user: { id: "user1" }, - supabase: mockSupabase, - }); + mockProfile({ referral_code: "johndoe", username: "johndoe" }); - const res = await GET(makeRequest()); + const res = await GET(makeRequest("https://preview.ugig.example")); expect(res.status).toBe(200); const body = await res.json(); expect(body.code).toBe("johndoe"); - expect(body.link).toBe("https://ugig.net/?ref=johndoe"); + expect(body.link).toBe("https://preview.ugig.example/?ref=johndoe"); + }); + + it("should prefer configured app URL and encode referral code", async () => { + vi.stubEnv("NEXT_PUBLIC_APP_URL", "https://staging.ugig.example/"); + mockProfile({ referral_code: "code/with space", username: "johndoe" }); + + const res = await GET(makeRequest("https://preview.ugig.example")); + expect(res.status).toBe(200); + const body = await res.json(); + expect(body.code).toBe("code/with space"); + expect(body.link).toBe("https://staging.ugig.example/?ref=code%2Fwith%20space"); }); it("should return 404 when profile not found", async () => { @@ -54,8 +70,7 @@ describe("GET /api/referrals/code", () => { from: () => ({ select: () => ({ eq: () => ({ - single: () => - Promise.resolve({ data: null, error: { message: "Not found" } }), + single: () => Promise.resolve({ data: null, error: { message: "Not found" } }), }), }), }), diff --git a/src/app/api/referrals/code/route.ts b/src/app/api/referrals/code/route.ts index 53bfc186..21cb78f5 100644 --- a/src/app/api/referrals/code/route.ts +++ b/src/app/api/referrals/code/route.ts @@ -1,6 +1,10 @@ import { NextRequest, NextResponse } from "next/server"; import { getAuthContext } from "@/lib/auth/get-user"; +function getReferralBaseUrl(request: NextRequest) { + return (process.env.NEXT_PUBLIC_APP_URL?.trim() || request.nextUrl.origin).replace(/\/+$/, ""); +} + // GET /api/referrals/code - Get my referral link/code export async function GET(request: NextRequest) { try { @@ -22,15 +26,13 @@ export async function GET(request: NextRequest) { } const code = profile.referral_code || profile.username; + const baseUrl = getReferralBaseUrl(request); return NextResponse.json({ code, - link: `https://ugig.net/?ref=${code}`, + link: `${baseUrl}/?ref=${encodeURIComponent(code)}`, }); } catch { - return NextResponse.json( - { error: "An unexpected error occurred" }, - { status: 500 } - ); + return NextResponse.json({ error: "An unexpected error occurred" }, { status: 500 }); } }