workspace-routing.test.ts 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { describe, expect, test } from "bun:test"
  2. import {
  3. isLocalWorkspaceRoute,
  4. getWorkspaceRouteSessionID,
  5. workspaceProxyURL,
  6. } from "../../src/server/shared/workspace-routing"
  7. import { SessionID } from "../../src/session/schema"
  8. describe("isLocalWorkspaceRoute", () => {
  9. test("GET /session is local", () => {
  10. expect(isLocalWorkspaceRoute("GET", "/session")).toBe(true)
  11. })
  12. test("GET /session/ses_abc is local (prefix match)", () => {
  13. expect(isLocalWorkspaceRoute("GET", "/session/ses_abc")).toBe(true)
  14. })
  15. test("POST /session is not local (method mismatch)", () => {
  16. expect(isLocalWorkspaceRoute("POST", "/session")).toBe(false)
  17. })
  18. test("/session/status is forwarded regardless of method", () => {
  19. expect(isLocalWorkspaceRoute("GET", "/session/status")).toBe(false)
  20. expect(isLocalWorkspaceRoute("POST", "/session/status")).toBe(false)
  21. })
  22. test("unrecognized paths are not local", () => {
  23. expect(isLocalWorkspaceRoute("GET", "/config")).toBe(false)
  24. expect(isLocalWorkspaceRoute("POST", "/session/ses_abc/message")).toBe(false)
  25. })
  26. })
  27. describe("getWorkspaceRouteSessionID", () => {
  28. test("extracts session ID from path", () => {
  29. const url = new URL("http://localhost/session/ses_abc123/message")
  30. expect(getWorkspaceRouteSessionID(url)).toBe(SessionID.make("ses_abc123"))
  31. })
  32. test("extracts session ID without trailing path", () => {
  33. const url = new URL("http://localhost/session/ses_xyz")
  34. expect(getWorkspaceRouteSessionID(url)).toBe(SessionID.make("ses_xyz"))
  35. })
  36. test("extracts session ID from experimental background path", () => {
  37. const url = new URL("http://localhost/experimental/session/ses_bg/background")
  38. expect(getWorkspaceRouteSessionID(url)).toBe(SessionID.make("ses_bg"))
  39. })
  40. test("returns null for /session/status", () => {
  41. const url = new URL("http://localhost/session/status")
  42. expect(getWorkspaceRouteSessionID(url)).toBeNull()
  43. })
  44. test("returns null for non-session paths", () => {
  45. const url = new URL("http://localhost/config")
  46. expect(getWorkspaceRouteSessionID(url)).toBeNull()
  47. })
  48. test("returns null for bare /session path", () => {
  49. const url = new URL("http://localhost/session")
  50. expect(getWorkspaceRouteSessionID(url)).toBeNull()
  51. })
  52. })
  53. describe("workspaceProxyURL", () => {
  54. test("appends request path to target", () => {
  55. const result = workspaceProxyURL("http://remote:8080/base", new URL("http://localhost/config"))
  56. expect(result.toString()).toBe("http://remote:8080/base/config")
  57. })
  58. test("strips trailing slash on target before appending", () => {
  59. const result = workspaceProxyURL("http://remote:8080/base/", new URL("http://localhost/session/abc"))
  60. expect(result.pathname).toBe("/base/session/abc")
  61. })
  62. test("preserves query params from request but removes workspace", () => {
  63. const url = new URL("http://localhost/config?workspace=ws_123&keep=yes")
  64. const result = workspaceProxyURL("http://remote:8080/base", url)
  65. expect(result.searchParams.get("workspace")).toBeNull()
  66. expect(result.searchParams.get("keep")).toBe("yes")
  67. })
  68. test("preserves hash from request", () => {
  69. const url = new URL("http://localhost/page#section")
  70. const result = workspaceProxyURL("http://remote:8080", url)
  71. expect(result.hash).toBe("#section")
  72. })
  73. test("works with URL object as target", () => {
  74. const target = new URL("http://remote:3000/api")
  75. const result = workspaceProxyURL(target, new URL("http://localhost/users"))
  76. expect(result.toString()).toBe("http://remote:3000/api/users")
  77. })
  78. })