1import { Linking } from "react-native";
2import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
3
4import { tryOpenExternalUrl } from "./openExternalUrl";
5
6vi.mock("react-native", () => ({
7 Linking: { openURL: vi.fn() },
8}));
9
10const openURL = vi.mocked(Linking.openURL);
11
12beforeEach(() => {
13 vi.clearAllMocks();
14});
15
16afterEach(() => {
17 vi.restoreAllMocks();
18});
19
20describe("tryOpenExternalUrl", () => {
21 it("opens supported URLs", async () => {
22 openURL.mockResolvedValue(undefined);
23
24 await expect(
25 tryOpenExternalUrl("https://github.com/pingdotgg/t3code", "pull-request"),
26 ).resolves.toBe(true);
27 });
28
29 it("logs stable URL context without exposing the opening failure", async () => {
30 const cause = new Error("browser-unavailable-secret-sentinel");
31 openURL.mockRejectedValue(cause);
32 const consoleError = vi.spyOn(console, "error").mockImplementation(() => undefined);
33
34 await expect(
35 tryOpenExternalUrl("https://github.com/pingdotgg/t3code/pull/1?token=secret", "pull-request"),
36 ).resolves.toBe(false);
37
38 expect(consoleError).toHaveBeenCalledTimes(1);
39 const [message, attributes] = consoleError.mock.calls[0] ?? [];
40 expect(message).toBe("Failed to open pull-request URL with the https scheme.");
41 expect(attributes).toEqual(
42 expect.objectContaining({
43 _tag: "ExternalUrlOpenError",
44 target: "pull-request",
45 scheme: "https",
46 host: "github.com",
47 stack: expect.stringContaining("ExternalUrlOpenError"),
48 }),
49 );
50 expect(attributes).not.toHaveProperty("url");
51 expect(attributes).not.toHaveProperty("cause");
52 const diagnosticText = [message, ...Object.values(attributes as Record<string, unknown>)]
53 .map(String)
54 .join("\n");
55 expect(diagnosticText).not.toContain("token=secret");
56 expect(diagnosticText).not.toContain("browser-unavailable-secret-sentinel");
57 });
58
59 it("keeps provider sign-in URLs unchanged and out of failure logs", async () => {
60 const url =
61 "https://accounts.google.com/o/oauth2/v2/auth?state=private-state&code_challenge=private-challenge&redirect_uri=http%3A%2F%2F127.0.0.1%3A43123%2F";
62 openURL.mockRejectedValue(new Error(`Cannot open ${url}`));
63 const consoleError = vi.spyOn(console, "error").mockImplementation(() => undefined);
64
65 await expect(tryOpenExternalUrl(url, "provider-auth")).resolves.toBe(false);
66
67 expect(openURL).toHaveBeenCalledWith(url);
68 const diagnostics = JSON.stringify(consoleError.mock.calls);
69 expect(diagnostics).toContain("accounts.google.com");
70 expect(diagnostics).not.toContain("private-state");
71 expect(diagnostics).not.toContain("private-challenge");
72 expect(diagnostics).not.toContain("43123");
73 });
74});