1import type { DiscoveredLocalServer } from "@t3tools/contracts";
2import { describe, expect, it } from "vite-plus/test";
3
4import { mergeServers } from "./useDiscoveredLocalServers";
5
6const scannerServer = (
7 overrides: Partial<DiscoveredLocalServer & { requestedUrl: string }>,
8): DiscoveredLocalServer & { requestedUrl: string } => ({
9 host: "localhost",
10 port: 5173,
11 url: "http://localhost:5173",
12 requestedUrl: overrides.url ?? "http://localhost:5173",
13 processName: "vite",
14 pid: 1234,
15 terminal: null,
16 ...overrides,
17});
18
19describe("mergeServers", () => {
20 it("returns scanner-only entries unchanged", () => {
21 const result = mergeServers({
22 scanner: [scannerServer({})],
23 configuredUrls: [],
24 });
25 expect(result).toHaveLength(1);
26 expect(result[0]).toMatchObject({
27 host: "localhost",
28 port: 5173,
29 requestedUrl: "http://localhost:5173",
30 source: "scanner",
31 processName: "vite",
32 });
33 });
34
35 it("enriches a configured entry with live process metadata when scanner sees it", () => {
36 const result = mergeServers({
37 scanner: [scannerServer({ port: 5173, processName: "node", pid: 9999 })],
38 configuredUrls: ["http://localhost:5173"],
39 });
40 expect(result).toHaveLength(1);
41 expect(result[0]).toMatchObject({
42 port: 5173,
43 source: "configured",
44 processName: "node",
45 pid: 9999,
46 });
47 });
48
49 it("excludes configured entries that the live scanner doesn't see", () => {
50 const result = mergeServers({
51 scanner: [],
52 configuredUrls: ["http://localhost:5173"],
53 });
54 expect(result).toHaveLength(0);
55 });
56
57 it("ignores non-loopback configured URLs", () => {
58 const result = mergeServers({
59 scanner: [scannerServer({})],
60 configuredUrls: ["https://example.com", "ws://localhost:5173"],
61 });
62 expect(result).toHaveLength(1);
63 expect(result[0]?.source).toBe("scanner");
64 });
65
66 it("sorts configured live servers before scanner-only servers", () => {
67 const result = mergeServers({
68 scanner: [scannerServer({ port: 8080 }), scannerServer({ port: 3000 })],
69 configuredUrls: ["http://localhost:8080"],
70 });
71 expect(result.map((s) => `${s.source}:${s.port}`)).toEqual(["configured:8080", "scanner:3000"]);
72 });
73
74 it("dedupes by lowercased host", () => {
75 const result = mergeServers({
76 scanner: [scannerServer({ host: "Localhost", port: 5173 })],
77 configuredUrls: ["http://localhost:5173"],
78 });
79 expect(result).toHaveLength(1);
80 expect(result[0]?.source).toBe("configured");
81 });
82
83 it.each(["127.0.0.1", "0.0.0.0", "[::1]"])(
84 "matches configured loopback alias %s to a live localhost server",
85 (host) => {
86 const result = mergeServers({
87 scanner: [
88 scannerServer({ requestedUrl: `http://localhost:5173/dashboard?mode=test#results` }),
89 ],
90 configuredUrls: [`http://${host}:5173/dashboard?mode=test#results`],
91 });
92 expect(result).toHaveLength(1);
93 expect(result[0]?.source).toBe("configured");
94 expect(result[0]?.requestedUrl).toBe("http://localhost:5173/dashboard?mode=test#results");
95 },
96 );
97
98 it("keeps the scanner-verified path and protocol", () => {
99 const result = mergeServers({
100 scanner: [
101 scannerServer({
102 url: "https://env-42.example.dev:5173/",
103 requestedUrl: "http://localhost:5173/dashboard?mode=test#results",
104 }),
105 ],
106 configuredUrls: ["https://localhost:5173/dashboard?mode=test#results"],
107 });
108 expect(result[0]?.url).toBe("https://env-42.example.dev:5173/");
109 expect(result[0]?.requestedUrl).toBe("http://localhost:5173/dashboard?mode=test#results");
110 });
111
112 it("overlays a configured path when an older server does not advertise path probing", () => {
113 const result = mergeServers({
114 scanner: [scannerServer({ requestedUrl: "http://localhost:5173/" })],
115 configuredUrls: ["https://localhost:5173/docs?mode=test#results"],
116 configuredUrlProbing: false,
117 });
118
119 expect(result[0]?.requestedUrl).toBe("https://localhost:5173/docs?mode=test#results");
120 });
121
122 it("does not overlay an unverified configured path when the server probes paths", () => {
123 const result = mergeServers({
124 scanner: [scannerServer({ requestedUrl: "http://localhost:5173/" })],
125 configuredUrls: ["http://localhost:5173/docs"],
126 configuredUrlProbing: true,
127 });
128
129 expect(result[0]?.requestedUrl).toBe("http://localhost:5173/");
130 });
131
132 it("keeps a scanner entry's pre-resolution requestedUrl distinct from a resolved url", () => {
133 const result = mergeServers({
134 scanner: [
135 scannerServer({
136 port: 5173,
137 url: "https://env-42.example.dev:5173/",
138 requestedUrl: "http://localhost:5173/",
139 }),
140 ],
141 configuredUrls: [],
142 });
143 expect(result[0]?.url).toBe("https://env-42.example.dev:5173/");
144 expect(result[0]?.requestedUrl).toBe("http://localhost:5173/");
145 });
146});