Repository: All-Hands-AI/OpenHands
File: frontend/__tests__/utils/websocket-url.test.ts (TypeScript)

Code before:
      // This test ensures the function handles URLs where the path ends with /
      const result = extractPathPrefix(
        "https://example.com/runtime/55313/api/conversations/123",
      );
      expect(result).not.toMatch(/\/$/);
    });

    it("should return empty string for relative URLs", () => {
      const result = extractPathPrefix("/api/conversations/123");
      expect(result).toBe("");
    });

    it("should return empty string for null", () => {
      const result = extractPathPrefix(null);
      expect(result).toBe("");
    });

    it("should return empty string for undefined", () => {
      const result = extractPathPrefix(undefined);
      expect(result).toBe("");
    });

    it("should return empty string for invalid URL", () => {
      const result = extractPathPrefix("not-a-valid-url");
      expect(result).toBe("");
    });

    it("should handle URL with only root path before /api/conversations", () => {
      const result = extractPathPrefix(
        "https://example.com/api/conversations/123",
      );
      expect(result).toBe("");
    });
  });

  describe("buildHttpBaseUrl", () => {
    it("should build HTTP URL without path prefix", () => {
      const result = buildHttpBaseUrl(
        "https://example.com/api/conversations/123",
      );
      expect(result).toBe("https://example.com");
    });

    it("should build HTTP URL with path prefix for proxy deployment", () => {
      const result = buildHttpBaseUrl(
        "https://openhands.example.com/runtime/55313/api/conversations/abc123",
      );
      expect(result).toBe("https://openhands.example.com/runtime/55313");
    });

    it("should use http protocol when window.location.protocol is http:", () => {

Review comment (refactor):
```suggestion
    it("should return empty string for relative URLs, null, undefined, or invalid URL", () => {
      expect(extractPathPrefix("/api/conversations/123")).toBe("");
      expect(extractPathPrefix(null)).toBe("");
      expect(extractPathPrefix(undefined)).toBe("");
      expect(extractPathPrefix("not-a-valid-url")).toBe("");
    });
```

Code after:
  describe("buildHttpBaseUrl", () => {
    it("should build HTTP URL without path prefix", () => {
      const result = buildHttpBaseUrl(
        "https://example.com/api/conversations/123",
      );
      expect(result).toBe("https://example.com");
    });

    it("should build HTTP URL with path prefix for proxy deployment", () => {
      const result = buildHttpBaseUrl(
        "https://openhands.example.com/runtime/55313/api/conversations/abc123",
      );
      expect(result).toBe("https://openhands.example.com/runtime/55313");
    });

    it("should use http protocol when window.location.protocol is http:", () => {
      vi.stubGlobal("location", {
        host: "localhost:3001",
        protocol: "http:",
      });

      const result = buildHttpBaseUrl(
        "http://localhost:3000/api/conversations/123",
      );
      expect(result).toBe("http://localhost:3000");
    });

    it("should fallback to window.location for null URL", () => {
      const result = buildHttpBaseUrl(null);
      expect(result).toBe("https://localhost:3001");
    });
  });

  describe("buildWebSocketUrl", () => {
    it("should return null when conversationId is undefined or empty", () => {
      expect(
        buildWebSocketUrl(
          undefined,
          "https://example.com/api/conversations/123",
        ),
      ).toBeNull();
      expect(
        buildWebSocketUrl("", "https://example.com/api/conversations/123"),
      ).toBeNull();
    });

    it("should build WebSocket URL without path prefix", () => {
      const result = buildWebSocketUrl(
        "conv-123",
        "https://example.com/api/conversations/conv-123",
      );