Skip to content
File

Blob: tests/worker/lib/http-entry.test.ts

typescript181 lines
1import { describe, expect, it, vi } from "vitest";
2import { handleHttpRequest, isDirectAssetRequest, isViteDevRuntimeAssetRequest } from "@/worker/lib/http-entry";
3 
4const ctx = {} as ExecutionContext;
5 
6function createResponse(label: string) {
7 return new Response(label);
8}
9 
10describe("isDirectAssetRequest", () => {
11 it("matches non-html static asset paths", () => {
12 expect(isDirectAssetRequest("/favicon.svg")).toBe(true);
13 expect(isDirectAssetRequest("/app-assets/app-123.js")).toBe(true);
14 expect(isDirectAssetRequest("/manifest.webmanifest")).toBe(true);
15 });
16 
17 it("excludes html documents and route-like paths", () => {
18 expect(isDirectAssetRequest("/index.html")).toBe(false);
19 expect(isDirectAssetRequest("/workspace/page")).toBe(false);
20 });
21});
22 
23describe("isViteDevRuntimeAssetRequest", () => {
24 it("matches Vite runtime source requests", () => {
25 expect(isViteDevRuntimeAssetRequest(new Request("http://localhost:5173/@vite/client"))).toBe(true);
26 expect(
27 isViteDevRuntimeAssetRequest(
28 new Request("http://acme.bland.localhost:5173/src/client/sites/entrypoints/browser.ts"),
29 ),
30 ).toBe(true);
31 expect(
32 isViteDevRuntimeAssetRequest(new Request("http://acme.bland.localhost:5173/node_modules/react/index.js")),
33 ).toBe(true);
34 });
35 
36 it("does not route non-read requests through the asset handler", () => {
37 expect(
38 isViteDevRuntimeAssetRequest(
39 new Request("http://localhost:5173/src/client/sites/entrypoints/browser.ts", { method: "POST" }),
40 ),
41 ).toBe(false);
42 });
43 
44 it("ignores ordinary document and asset paths", () => {
45 expect(isViteDevRuntimeAssetRequest(new Request("http://localhost:5173/workspace/page"))).toBe(false);
46 expect(isViteDevRuntimeAssetRequest(new Request("http://localhost:5173/favicon.svg"))).toBe(false);
47 });
48});
49 
50describe("handleHttpRequest", () => {
51 it("routes API and upload requests to the app handler", async () => {
52 const handlePartyRequest = vi.fn().mockResolvedValue(null);
53 const handleAppRequest = vi.fn().mockImplementation(() => Promise.resolve(createResponse("app")));
54 const handleAssetRequest = vi.fn().mockResolvedValue(createResponse("asset"));
55 const handleShellRequest = vi.fn().mockResolvedValue(createResponse("shell"));
56 const handleSiteRequest = vi.fn().mockResolvedValue(createResponse("site"));
57 
58 const apiResponse = await handleHttpRequest(new Request("https://bland.tools/api/v1/workspaces"), {}, ctx, {
59 handlePartyRequest,
60 handleAppRequest,
61 handleAssetRequest,
62 handleShellRequest,
63 handleSiteRequest,
64 });
65 const uploadResponse = await handleHttpRequest(new Request("https://bland.tools/uploads/file-1"), {}, ctx, {
66 handlePartyRequest,
67 handleAppRequest,
68 handleAssetRequest,
69 handleShellRequest,
70 handleSiteRequest,
71 });
72 
73 expect(await apiResponse.text()).toBe("app");
74 expect(await uploadResponse.text()).toBe("app");
75 expect(handleAppRequest).toHaveBeenCalledTimes(2);
76 expect(handleAssetRequest).not.toHaveBeenCalled();
77 expect(handleShellRequest).not.toHaveBeenCalled();
78 });
79 
80 it("routes direct asset GET requests to the asset handler", async () => {
81 const handlePartyRequest = vi.fn().mockResolvedValue(null);
82 const handleAppRequest = vi.fn().mockResolvedValue(createResponse("app"));
83 const handleAssetRequest = vi.fn().mockResolvedValue(createResponse("asset"));
84 const handleShellRequest = vi.fn().mockResolvedValue(createResponse("shell"));
85 const handleSiteRequest = vi.fn().mockResolvedValue(createResponse("site"));
86 
87 const response = await handleHttpRequest(new Request("https://bland.tools/favicon.svg"), {}, ctx, {
88 handlePartyRequest,
89 handleAppRequest,
90 handleAssetRequest,
91 handleShellRequest,
92 handleSiteRequest,
93 });
94 
95 expect(await response.text()).toBe("asset");
96 expect(handleAssetRequest).toHaveBeenCalledTimes(1);
97 expect(handleAppRequest).not.toHaveBeenCalled();
98 expect(handleShellRequest).not.toHaveBeenCalled();
99 });
100 
101 it("routes GET document requests to the shell handler", async () => {
102 const handlePartyRequest = vi.fn().mockResolvedValue(null);
103 const handleAppRequest = vi.fn().mockResolvedValue(createResponse("app"));
104 const handleAssetRequest = vi.fn().mockResolvedValue(createResponse("asset"));
105 const handleShellRequest = vi.fn().mockResolvedValue(createResponse("shell"));
106 const handleSiteRequest = vi.fn().mockResolvedValue(createResponse("site"));
107 
108 const response = await handleHttpRequest(new Request("https://bland.tools/acme/page-1"), {}, ctx, {
109 handlePartyRequest,
110 handleAppRequest,
111 handleAssetRequest,
112 handleShellRequest,
113 handleSiteRequest,
114 });
115 
116 expect(await response.text()).toBe("shell");
117 expect(handleShellRequest).toHaveBeenCalledTimes(1);
118 expect(handleAssetRequest).not.toHaveBeenCalled();
119 expect(handleAppRequest).not.toHaveBeenCalled();
120 });
121 
122 it("routes HEAD document requests to the asset handler", async () => {
123 const handlePartyRequest = vi.fn().mockResolvedValue(null);
124 const handleAppRequest = vi.fn().mockResolvedValue(createResponse("app"));
125 const handleAssetRequest = vi.fn().mockResolvedValue(createResponse("asset"));
126 const handleShellRequest = vi.fn().mockResolvedValue(createResponse("shell"));
127 const handleSiteRequest = vi.fn().mockResolvedValue(createResponse("site"));
128 
129 const response = await handleHttpRequest(
130 new Request("https://bland.tools/acme/page-1", { method: "HEAD" }),
131 {},
132 ctx,
133 { handlePartyRequest, handleAppRequest, handleAssetRequest, handleShellRequest, handleSiteRequest },
134 );
135 
136 expect(await response.text()).toBe("asset");
137 expect(handleAssetRequest).toHaveBeenCalledTimes(1);
138 expect(handleShellRequest).not.toHaveBeenCalled();
139 });
140 
141 it("returns the party handler response for /parties/*", async () => {
142 const handlePartyRequest = vi.fn().mockResolvedValue(createResponse("party"));
143 const handleAppRequest = vi.fn().mockResolvedValue(createResponse("app"));
144 const handleAssetRequest = vi.fn().mockResolvedValue(createResponse("asset"));
145 const handleShellRequest = vi.fn().mockResolvedValue(createResponse("shell"));
146 const handleSiteRequest = vi.fn().mockResolvedValue(createResponse("site"));
147 
148 const response = await handleHttpRequest(new Request("https://bland.tools/parties/page-1"), {}, ctx, {
149 handlePartyRequest,
150 handleAppRequest,
151 handleAssetRequest,
152 handleShellRequest,
153 handleSiteRequest,
154 });
155 
156 expect(await response.text()).toBe("party");
157 expect(handlePartyRequest).toHaveBeenCalledTimes(1);
158 expect(handleAppRequest).not.toHaveBeenCalled();
159 });
160 
161 it("falls back to the app handler when /parties/* is not handled", async () => {
162 const handlePartyRequest = vi.fn().mockResolvedValue(null);
163 const handleAppRequest = vi.fn().mockResolvedValue(createResponse("app"));
164 const handleAssetRequest = vi.fn().mockResolvedValue(createResponse("asset"));
165 const handleShellRequest = vi.fn().mockResolvedValue(createResponse("shell"));
166 const handleSiteRequest = vi.fn().mockResolvedValue(createResponse("site"));
167 
168 const response = await handleHttpRequest(new Request("https://bland.tools/parties/page-1"), {}, ctx, {
169 handlePartyRequest,
170 handleAppRequest,
171 handleAssetRequest,
172 handleShellRequest,
173 handleSiteRequest,
174 });
175 
176 expect(await response.text()).toBe("app");
177 expect(handlePartyRequest).toHaveBeenCalledTimes(1);
178 expect(handleAppRequest).toHaveBeenCalledTimes(1);
179 });
180});