1import { describe, expect, it } from "vite-plus/test";
2
3import { NETWORK_BLOCKING_HINT } from "./network.ts";
4import { isTransportConnectionErrorMessage, sanitizeThreadErrorMessage } from "./transport.ts";
5
6describe("isTransportConnectionErrorMessage", () => {
7 it("returns true for SocketCloseError", () => {
8 expect(isTransportConnectionErrorMessage("SocketCloseError: connection reset")).toBe(true);
9 });
10
11 it("returns true for SocketOpenError", () => {
12 expect(isTransportConnectionErrorMessage("SocketOpenError: ECONNREFUSED")).toBe(true);
13 });
14
15 it("returns true for React Native disconnected socket errors", () => {
16 expect(
17 isTransportConnectionErrorMessage(
18 "The operation couldn't be completed. Socket is not connected",
19 ),
20 ).toBe(true);
21 });
22
23 it("recognizes connection errors emitted by the Effect RPC session", () => {
24 expect(isTransportConnectionErrorMessage("Test environment disconnected.")).toBe(true);
25 expect(isTransportConnectionErrorMessage("Test environment stopped responding.")).toBe(true);
26 expect(
27 isTransportConnectionErrorMessage(
28 "Test environment could not establish a WebSocket connection.",
29 ),
30 ).toBe(true);
31 expect(isTransportConnectionErrorMessage("Test environment is not connected.")).toBe(true);
32 expect(isTransportConnectionErrorMessage("ClientProtocolError: socket closed")).toBe(true);
33 });
34
35 it("recognizes relay connection errors that carry the network hint", () => {
36 for (const sentence of [
37 "Relay environment disconnected.",
38 "Relay environment stopped responding.",
39 "Relay environment could not establish a WebSocket connection.",
40 ]) {
41 expect(isTransportConnectionErrorMessage(`${sentence} ${NETWORK_BLOCKING_HINT}`)).toBe(true);
42 }
43 expect(
44 isTransportConnectionErrorMessage(
45 "Your ChatGPT connection expired or was disconnected. Sign in again.",
46 ),
47 ).toBe(false);
48 });
49
50 it("returns true for the T3 server WebSocket message", () => {
51 expect(isTransportConnectionErrorMessage("Unable to connect to the T3 server WebSocket.")).toBe(
52 true,
53 );
54 });
55
56 it("returns true for ping timeout", () => {
57 expect(isTransportConnectionErrorMessage("ping timeout")).toBe(true);
58 });
59
60 it("returns false for business logic errors", () => {
61 expect(isTransportConnectionErrorMessage("Thread not found")).toBe(false);
62 expect(isTransportConnectionErrorMessage("Invalid model selection")).toBe(false);
63 });
64
65 it("returns false for null, undefined, and empty strings", () => {
66 expect(isTransportConnectionErrorMessage(null)).toBe(false);
67 expect(isTransportConnectionErrorMessage(undefined)).toBe(false);
68 expect(isTransportConnectionErrorMessage("")).toBe(false);
69 expect(isTransportConnectionErrorMessage(" ")).toBe(false);
70 });
71});
72
73describe("sanitizeThreadErrorMessage", () => {
74 it("strips transport errors", () => {
75 expect(sanitizeThreadErrorMessage("SocketCloseError: oops")).toBeNull();
76 });
77
78 it("preserves non-transport errors", () => {
79 expect(sanitizeThreadErrorMessage("Thread not found")).toBe("Thread not found");
80 expect(sanitizeThreadErrorMessage("Select a base branch before sending.")).toBe(
81 "Select a base branch before sending.",
82 );
83 });
84
85 it("returns null for null/undefined", () => {
86 expect(sanitizeThreadErrorMessage(null)).toBeNull();
87 expect(sanitizeThreadErrorMessage(undefined)).toBeNull();
88 });
89});