| ... | ... | @@ -25,7 +25,7 @@ describe("browser target resolver", () => { |
| 25 | 25 | }); |
| 26 | 26 | }); |
| 27 | 27 | |
| 28 | | it("maps localhost URL navigation onto a remote Tailscale IPv4 host", async () => { |
| 28 | it("preserves explicit loopback URL navigation for a remote Tailscale environment", async () => { |
| 29 | 29 | readPreparedConnection.mockReturnValue({ httpBaseUrl: "http://100.65.180.100:3773" }); |
| 30 | 30 | const { resolveBrowserNavigationTarget } = await import("./browserTargetResolver"); |
| 31 | 31 | expect( |
| ... | ... | @@ -35,13 +35,29 @@ describe("browser target resolver", () => { |
| 35 | 35 | }), |
| 36 | 36 | ).toEqual({ |
| 37 | 37 | requestedUrl: "http://localhost:5173/dashboard?mode=test#results", |
| 38 | | resolvedUrl: "http://100.65.180.100:5173/dashboard?mode=test#results", |
| 39 | | resolutionKind: "direct-private-network", |
| 38 | resolvedUrl: "http://localhost:5173/dashboard?mode=test#results", |
| 39 | resolutionKind: "direct", |
| 40 | 40 | environmentId: "environment-1", |
| 41 | 41 | }); |
| 42 | 42 | }); |
| 43 | 43 | |
| 44 | | it("preserves URL credentials when mapping localhost onto a remote host", async () => { |
| 44 | it("preserves explicit IPv4 loopback URL navigation for a private network environment", async () => { |
| 45 | readPreparedConnection.mockReturnValue({ httpBaseUrl: "http://192.168.1.50:3773" }); |
| 46 | const { resolveBrowserNavigationTarget } = await import("./browserTargetResolver"); |
| 47 | expect( |
| 48 | resolveBrowserNavigationTarget(EnvironmentId.make("environment-1"), { |
| 49 | kind: "url", |
| 50 | url: "http://127.0.0.1:5999/", |
| 51 | }), |
| 52 | ).toEqual({ |
| 53 | requestedUrl: "http://127.0.0.1:5999/", |
| 54 | resolvedUrl: "http://127.0.0.1:5999/", |
| 55 | resolutionKind: "direct", |
| 56 | environmentId: "environment-1", |
| 57 | }); |
| 58 | }); |
| 59 | |
| 60 | it("preserves URL credentials on explicit loopback navigation", async () => { |
| 45 | 61 | readPreparedConnection.mockReturnValue({ httpBaseUrl: "http://100.65.180.100:3773" }); |
| 46 | 62 | const { resolveBrowserNavigationTarget } = await import("./browserTargetResolver"); |
| 47 | 63 | expect( |
| ... | ... | @@ -49,10 +65,10 @@ describe("browser target resolver", () => { |
| 49 | 65 | kind: "url", |
| 50 | 66 | url: "http://user:p%40ss@localhost:5173/dashboard", |
| 51 | 67 | }).resolvedUrl, |
| 52 | | ).toBe("http://user:p%40ss@100.65.180.100:5173/dashboard"); |
| 68 | ).toBe("http://user:p%40ss@localhost:5173/dashboard"); |
| 53 | 69 | }); |
| 54 | 70 | |
| 55 | | it("maps credentialed localhost URLs onto private IPv6 hosts", async () => { |
| 71 | it("preserves credentialed loopback URLs for private IPv6 environments", async () => { |
| 56 | 72 | readPreparedConnection.mockReturnValue({ |
| 57 | 73 | httpBaseUrl: "http://[fd7a:115c:a1e0::53]:3773", |
| 58 | 74 | }); |
| ... | ... | @@ -62,10 +78,10 @@ describe("browser target resolver", () => { |
| 62 | 78 | kind: "url", |
| 63 | 79 | url: "http://user:p%40ss@localhost:5173/dashboard?mode=test#results", |
| 64 | 80 | }).resolvedUrl, |
| 65 | | ).toBe("http://user:p%40ss@[fd7a:115c:a1e0::53]:5173/dashboard?mode=test#results"); |
| 81 | ).toBe("http://user:p%40ss@localhost:5173/dashboard?mode=test#results"); |
| 66 | 82 | }); |
| 67 | 83 | |
| 68 | | it("maps schemeless localhost navigation onto a remote environment host", async () => { |
| 84 | it("preserves schemeless localhost navigation for a remote environment", async () => { |
| 69 | 85 | readPreparedConnection.mockReturnValue({ httpBaseUrl: "http://192.168.1.25:3773" }); |
| 70 | 86 | const { resolveBrowserNavigationTarget } = await import("./browserTargetResolver"); |
| 71 | 87 | expect( |
| ... | ... | @@ -73,7 +89,7 @@ describe("browser target resolver", () => { |
| 73 | 89 | kind: "url", |
| 74 | 90 | url: "localhost:3000/app", |
| 75 | 91 | }).resolvedUrl, |
| 76 | | ).toBe("http://192.168.1.25:3000/app"); |
| 92 | ).toBe("localhost:3000/app"); |
| 77 | 93 | }); |
| 78 | 94 | |
| 79 | 95 | it("keeps localhost navigation local for a local environment", async () => { |
| ... | ... | @@ -117,12 +133,12 @@ describe("browser target resolver", () => { |
| 117 | 133 | port: 5173, |
| 118 | 134 | }), |
| 119 | 135 | ).toThrow(/authenticated preview gateway/); |
| 120 | | expect(() => |
| 136 | expect( |
| 121 | 137 | resolveBrowserNavigationTarget(EnvironmentId.make("environment-1"), { |
| 122 | 138 | kind: "url", |
| 123 | 139 | url: "http://localhost:5173", |
| 124 | 140 | }), |
| 125 | | ).toThrow(/authenticated preview gateway/); |
| 141 | ).toMatchObject({ resolvedUrl: "http://localhost:5173", resolutionKind: "direct" }); |
| 126 | 142 | }); |
| 127 | 143 | |
| 128 | 144 | it("normalizes schemeless localhost server-picker values", async () => { |
| ... | ... | @@ -136,6 +152,14 @@ describe("browser target resolver", () => { |
| 136 | 152 | ).toBe("http://localhost:3000/app"); |
| 137 | 153 | }); |
| 138 | 154 | |
| 155 | it("maps discovered loopback servers onto a remote environment host", async () => { |
| 156 | readPreparedConnection.mockReturnValue({ httpBaseUrl: "http://192.168.1.25:3773" }); |
| 157 | const { resolveDiscoveredServerUrl } = await import("./browserTargetResolver"); |
| 158 | expect( |
| 159 | resolveDiscoveredServerUrl(EnvironmentId.make("environment-1"), "localhost:3000/app"), |
| 160 | ).toBe("http://192.168.1.25:3000/app"); |
| 161 | }); |
| 162 | |
| 139 | 163 | it("preserves localhost server-picker values when the prepared base is 127.0.0.1", async () => { |
| 140 | 164 | readPreparedConnection.mockReturnValue({ httpBaseUrl: "http://127.0.0.1:3773" }); |
| 141 | 165 | const { resolveDiscoveredServerUrl } = await import("./browserTargetResolver"); |