1import { afterEach, describe, expect, it, vi } from "vite-plus/test";
2
3import {
4 buildHostedChannelSelectionUrl,
5 buildHostedPairingUrl,
6 hasHostedPairingRequest,
7 isHostedStaticApp,
8 readHostedPairingRequest,
9} from "./hostedPairing";
10
11describe("hostedPairing", () => {
12 afterEach(() => {
13 vi.unstubAllEnvs();
14 });
15
16 it("reads hosted pairing host and query token parameters", () => {
17 const url = new URL("https://app.t3.codes/pair?host=100.64.1.2:3773&token=ABCD1234");
18
19 expect(readHostedPairingRequest(url)).toEqual({
20 host: "100.64.1.2:3773",
21 token: "ABCD1234",
22 label: "",
23 });
24 expect(hasHostedPairingRequest(url)).toBe(true);
25 });
26
27 it("prefers hash tokens so generated hosted links do not put credentials in search params", () => {
28 vi.stubEnv("VITE_HOSTED_APP_URL", "https://preview.t3.codes");
29
30 const url = new URL(
31 buildHostedPairingUrl({
32 host: "https://backend.example.com:3773",
33 token: "pairing-token",
34 label: "Workstation",
35 }),
36 );
37
38 expect(url.origin).toBe("https://preview.t3.codes");
39 expect(url.pathname).toBe("/pair");
40 expect(url.searchParams.get("host")).toBe("https://backend.example.com:3773");
41 expect(url.searchParams.get("label")).toBe("Workstation");
42 expect(url.searchParams.has("token")).toBe(false);
43 expect(url.hash).toBe("#token=pairing-token");
44 });
45
46 it("builds hosted channel selection URLs through the configured router origin", () => {
47 vi.stubEnv("VITE_HOSTED_APP_URL", "https://app.t3.codes");
48
49 const url = new URL(
50 buildHostedChannelSelectionUrl({
51 channel: "nightly",
52 }),
53 );
54
55 expect(url.origin).toBe("https://app.t3.codes");
56 expect(url.pathname).toBe("/__t3code/channel");
57 expect(url.searchParams.get("channel")).toBe("nightly");
58 expect(url.searchParams.has("next")).toBe(false);
59 });
60
61 it("ignores incomplete hosted pairing requests", () => {
62 expect(
63 hasHostedPairingRequest(new URL("https://app.t3.codes/pair?host=backend.example.com")),
64 ).toBe(false);
65 expect(hasHostedPairingRequest(new URL("https://app.t3.codes/pair?token=ABCD1234"))).toBe(
66 false,
67 );
68 });
69
70 it("detects the hosted static app only when no backend URL is configured", () => {
71 vi.stubEnv("VITE_HOSTED_APP_URL", "https://preview.t3.codes");
72 vi.stubEnv("VITE_HTTP_URL", "");
73 vi.stubEnv("VITE_WS_URL", "");
74
75 expect(isHostedStaticApp(new URL("https://preview.t3.codes/"))).toBe(true);
76 expect(isHostedStaticApp(new URL("https://preview.t3.codes/pair"))).toBe(true);
77 expect(isHostedStaticApp(new URL("https://backend.example.com/"))).toBe(false);
78
79 vi.stubEnv("VITE_HTTP_URL", "https://backend.example.com");
80 expect(isHostedStaticApp(new URL("https://preview.t3.codes/"))).toBe(false);
81 });
82
83 it("detects hosted channel aliases as static apps", () => {
84 vi.stubEnv("VITE_HOSTED_APP_URL", "https://app.t3.codes");
85 vi.stubEnv("VITE_HOSTED_APP_CHANNEL", "nightly");
86 vi.stubEnv("VITE_HTTP_URL", "");
87 vi.stubEnv("VITE_WS_URL", "");
88
89 expect(isHostedStaticApp(new URL("https://nightly.app.t3.codes/"))).toBe(true);
90
91 vi.stubEnv("VITE_HTTP_URL", "https://backend.example.com");
92 expect(isHostedStaticApp(new URL("https://nightly.app.t3.codes/"))).toBe(false);
93 });
94});