@@ -99,6 +99,262 @@ async function setupPlatformProxy(config: string, devRegistryPath?: string) {
9999 return proxy ;
100100}
101101
102+ describe ( "Dev Registry: wrangler dev <-> wrangler dev" , ( ) => {
103+ it ( "supports fetch over service binding" , async ( { devRegistryPath } ) => {
104+ const workerEntrypointWithAssets = await runWranglerDev (
105+ "wrangler.worker-entrypoint-with-assets.jsonc" ,
106+ devRegistryPath
107+ ) ;
108+
109+ // Test fallback service before module-worker is started
110+ await vi . waitFor ( async ( ) => {
111+ const searchParams = new URLSearchParams ( {
112+ "test-service" : "module-worker" ,
113+ "test-method" : "fetch" ,
114+ } ) ;
115+ const response = await fetch (
116+ `${ workerEntrypointWithAssets } ?${ searchParams } `
117+ ) ;
118+
119+ expect ( {
120+ status : response . status ,
121+ body : await response . text ( ) ,
122+ } ) . toEqual ( {
123+ status : 503 ,
124+ body : `Couldn't find a local dev session for the "default" entrypoint of service "module-worker" to proxy to` ,
125+ } ) ;
126+ } ) ;
127+
128+ const moduleWorker = await runWranglerDev (
129+ "wrangler.module-worker.jsonc" ,
130+ devRegistryPath
131+ ) ;
132+
133+ // Test module-worker -> worker-entrypoint
134+ await vi . waitFor ( async ( ) => {
135+ const searchParams = new URLSearchParams ( {
136+ "test-service" : "worker-entrypoint-with-assets" ,
137+ "test-method" : "fetch" ,
138+ } ) ;
139+ const response = await fetch ( `${ moduleWorker } ?${ searchParams } ` ) ;
140+
141+ expect ( await response . text ( ) ) . toBe ( "Hello from Worker Entrypoint!" ) ;
142+ expect ( response . status ) . toBe ( 200 ) ;
143+
144+ // Test fetching asset from "worker-entrypoint-with-assets" over service binding
145+ // Module worker has no assets, so it will hit the user worker and
146+ // forward the request to "worker-entrypoint-with-assets" with the asset path
147+ const assetResponse = await fetch (
148+ `${ moduleWorker } /example.txt?${ searchParams } `
149+ ) ;
150+ expect ( await assetResponse . text ( ) ) . toBe ( "This is an example asset file" ) ;
151+ } ) ;
152+
153+ // Test worker-entrypoint -> module-worker
154+ await vi . waitFor ( async ( ) => {
155+ const searchParams = new URLSearchParams ( {
156+ "test-service" : "module-worker" ,
157+ "test-method" : "fetch" ,
158+ } ) ;
159+ const response = await fetch (
160+ `${ workerEntrypointWithAssets } ?${ searchParams } `
161+ ) ;
162+
163+ expect ( await response . text ( ) ) . toEqual ( "Hello from Module Worker!" ) ;
164+ expect ( response . status ) . toBe ( 200 ) ;
165+ } ) ;
166+ } ) ;
167+
168+ it ( "supports RPC over service binding" , async ( { devRegistryPath } ) => {
169+ const workerEntrypoint = await runWranglerDev (
170+ "wrangler.worker-entrypoint.jsonc" ,
171+ devRegistryPath
172+ ) ;
173+
174+ await vi . waitFor ( async ( ) => {
175+ const searchParams = new URLSearchParams ( {
176+ "test-service" : "worker-entrypoint-with-assets" ,
177+ "test-method" : "rpc" ,
178+ } ) ;
179+ const response = await fetch ( `${ workerEntrypoint } ?${ searchParams } ` ) ;
180+
181+ expect ( response . status ) . toBe ( 500 ) ;
182+ expect ( await response . text ( ) ) . toEqual (
183+ `Cannot access "ping" as we couldn't find a local dev session for the "default" entrypoint of service "worker-entrypoint-with-assets" to proxy to.`
184+ ) ;
185+ } ) ;
186+
187+ const workerEntrypointWithAssets = await runWranglerDev (
188+ "wrangler.worker-entrypoint-with-assets.jsonc" ,
189+ devRegistryPath
190+ ) ;
191+
192+ await vi . waitFor ( async ( ) => {
193+ const searchParams = new URLSearchParams ( {
194+ "test-service" : "worker-entrypoint" ,
195+ "test-method" : "rpc" ,
196+ } ) ;
197+ const response = await fetch (
198+ `${ workerEntrypointWithAssets } ?${ searchParams } `
199+ ) ;
200+
201+ expect ( response . status ) . toBe ( 200 ) ;
202+ expect ( await response . text ( ) ) . toEqual ( "Pong" ) ;
203+ } ) ;
204+
205+ await vi . waitFor ( async ( ) => {
206+ const searchParams = new URLSearchParams ( {
207+ "test-service" : "worker-entrypoint-with-assets" ,
208+ "test-method" : "rpc" ,
209+ } ) ;
210+ const response = await fetch ( `${ workerEntrypoint } ?${ searchParams } ` ) ;
211+
212+ expect ( response . status ) . toBe ( 200 ) ;
213+ expect ( await response . text ( ) ) . toEqual ( "Pong" ) ;
214+ } ) ;
215+ } ) ;
216+
217+ it ( "supports fetch over durable object binding" , async ( {
218+ devRegistryPath,
219+ } ) => {
220+ const externalDurableObject = await runWranglerDev (
221+ "wrangler.external-durable-object.jsonc" ,
222+ devRegistryPath
223+ ) ;
224+
225+ // Test fallback before internal durable object is started
226+ await vi . waitFor ( async ( ) => {
227+ const searchParams = new URLSearchParams ( {
228+ "test-service" : "durable-object" ,
229+ "test-method" : "fetch" ,
230+ } ) ;
231+ const response = await fetch ( `${ externalDurableObject } ?${ searchParams } ` ) ;
232+
233+ expect ( response . status ) . toBe ( 503 ) ;
234+ expect ( await response . text ( ) ) . toEqual ( "Service Unavailable" ) ;
235+ } ) ;
236+
237+ await runWranglerDev (
238+ "wrangler.internal-durable-object.jsonc" ,
239+ devRegistryPath
240+ ) ;
241+
242+ await vi . waitFor ( async ( ) => {
243+ const searchParams = new URLSearchParams ( {
244+ "test-service" : "durable-object" ,
245+ "test-method" : "fetch" ,
246+ } ) ;
247+ const response = await fetch ( `${ externalDurableObject } ?${ searchParams } ` ) ;
248+
249+ expect ( response . status ) . toBe ( 200 ) ;
250+ expect ( await response . text ( ) ) . toEqual ( "Hello from Durable Object!" ) ;
251+ } ) ;
252+ } ) ;
253+
254+ it ( "supports RPC over durable object binding" , async ( {
255+ devRegistryPath,
256+ } ) => {
257+ const externalDurableObject = await runWranglerDev (
258+ "wrangler.external-durable-object.jsonc" ,
259+ devRegistryPath
260+ ) ;
261+
262+ // Test RPC fallback before internal durable object is started
263+ await vi . waitFor ( async ( ) => {
264+ const searchParams = new URLSearchParams ( {
265+ "test-service" : "durable-object" ,
266+ "test-method" : "rpc" ,
267+ } ) ;
268+ const response = await fetch ( `${ externalDurableObject } ?${ searchParams } ` ) ;
269+
270+ expect ( {
271+ status : response . status ,
272+ body : await response . text ( ) ,
273+ } ) . toEqual ( {
274+ status : 500 ,
275+ body : 'Cannot access "TestObject#ping" as Durable Object RPC is not yet supported between multiple dev sessions.' ,
276+ } ) ;
277+ } ) ;
278+
279+ await runWranglerDev (
280+ "wrangler.internal-durable-object.jsonc" ,
281+ devRegistryPath
282+ ) ;
283+
284+ // Test RPC after internal durable object is started (should still fail)
285+ await vi . waitFor ( async ( ) => {
286+ const searchParams = new URLSearchParams ( {
287+ "test-service" : "durable-object" ,
288+ "test-method" : "rpc" ,
289+ } ) ;
290+ const response = await fetch ( `${ externalDurableObject } ?${ searchParams } ` ) ;
291+
292+ expect ( response . status ) . toBe ( 500 ) ;
293+ expect ( await response . text ( ) ) . toEqual (
294+ 'Cannot access "TestObject#ping" as Durable Object RPC is not yet supported between multiple dev sessions.'
295+ ) ;
296+ } ) ;
297+ } ) ;
298+
299+ it ( "supports tail handler" , async ( { devRegistryPath } ) => {
300+ const moduleWorkerWithAssets = await runWranglerDev (
301+ "wrangler.module-worker-with-assets.jsonc" ,
302+ devRegistryPath
303+ ) ;
304+ const workerEntrypoint = await runWranglerDev (
305+ "wrangler.worker-entrypoint.jsonc" ,
306+ devRegistryPath
307+ ) ;
308+
309+ const searchParams = new URLSearchParams ( {
310+ "test-method" : "tail" ,
311+ } ) ;
312+
313+ await vi . waitFor ( async ( ) => {
314+ // Trigger tail handler of worker-entrypoint via module-worker
315+ await fetch ( `${ moduleWorkerWithAssets } ?${ searchParams } ` , {
316+ method : "POST" ,
317+ body : JSON . stringify ( [ "hello world" , "this is the 2nd log" ] ) ,
318+ } ) ;
319+ await fetch ( `${ moduleWorkerWithAssets } ?${ searchParams } ` , {
320+ method : "POST" ,
321+ body : JSON . stringify ( [ "some other log" ] ) ,
322+ } ) ;
323+
324+ const response = await fetch ( `${ workerEntrypoint } ?${ searchParams } ` ) ;
325+
326+ expect ( await response . json ( ) ) . toEqual ( {
327+ worker : "Worker Entrypoint" ,
328+ tailEvents : expect . arrayContaining ( [
329+ [ [ "[Module Worker]" ] , [ "hello world" , "this is the 2nd log" ] ] ,
330+ [ [ "[Module Worker]" ] , [ "some other log" ] ] ,
331+ ] ) ,
332+ } ) ;
333+ } ) ;
334+
335+ await vi . waitFor ( async ( ) => {
336+ // Trigger tail handler of module-worker via worker-entrypoint
337+ await fetch ( `${ workerEntrypoint } ?${ searchParams } ` , {
338+ method : "POST" ,
339+ body : JSON . stringify ( [ "hello from test" ] ) ,
340+ } ) ;
341+ await fetch ( `${ workerEntrypoint } ?${ searchParams } ` , {
342+ method : "POST" ,
343+ body : JSON . stringify ( [ "yet another log" , "and another one" ] ) ,
344+ } ) ;
345+ const response = await fetch ( `${ moduleWorkerWithAssets } ?${ searchParams } ` ) ;
346+
347+ expect ( await response . json ( ) ) . toEqual ( {
348+ worker : "Module Worker" ,
349+ tailEvents : expect . arrayContaining ( [
350+ [ [ "[Worker Entrypoint]" ] , [ "hello from test" ] ] ,
351+ [ [ "[Worker Entrypoint]" ] , [ "yet another log" , "and another one" ] ] ,
352+ ] ) ,
353+ } ) ;
354+ } ) ;
355+ } ) ;
356+ } ) ;
357+
102358describe ( "Dev Registry: vite dev <-> vite dev" , ( ) => {
103359 it ( "supports module worker fetch over service binding" , async ( {
104360 devRegistryPath,
@@ -244,10 +500,10 @@ describe("Dev Registry: vite dev <-> vite dev", () => {
244500
245501 expect ( await response . json ( ) ) . toEqual ( {
246502 worker : "Worker Entrypoint" ,
247- tailEvents : [
503+ tailEvents : expect . arrayContaining ( [
248504 [ [ "[Module Worker]" ] , [ "hello world" , "this is the 2nd log" ] ] ,
249505 [ [ "[Module Worker]" ] , [ "some other log" ] ] ,
250- ] ,
506+ ] ) ,
251507 } ) ;
252508 } ) ;
253509
@@ -266,10 +522,10 @@ describe("Dev Registry: vite dev <-> vite dev", () => {
266522
267523 expect ( await response . json ( ) ) . toEqual ( {
268524 worker : "Module Worker" ,
269- tailEvents : [
525+ tailEvents : expect . arrayContaining ( [
270526 [ [ "[Worker Entrypoint]" ] , [ "hello from test" ] ] ,
271527 [ [ "[Worker Entrypoint]" ] , [ "yet another log" , "and another one" ] ] ,
272- ] ,
528+ ] ) ,
273529 } ) ;
274530 } ) ;
275531 } ) ;
@@ -466,10 +722,10 @@ describe("Dev Registry: vite dev <-> wrangler dev", () => {
466722
467723 expect ( await response . json ( ) ) . toEqual ( {
468724 worker : "Worker Entrypoint" ,
469- tailEvents : [
725+ tailEvents : expect . arrayContaining ( [
470726 [ [ "[Module Worker]" ] , [ "hello world" , "this is the 2nd log" ] ] ,
471727 [ [ "[Module Worker]" ] , [ "some other log" ] ] ,
472- ] ,
728+ ] ) ,
473729 } ) ;
474730 } ) ;
475731
@@ -490,10 +746,10 @@ describe("Dev Registry: vite dev <-> wrangler dev", () => {
490746
491747 expect ( await response . json ( ) ) . toEqual ( {
492748 worker : "Module Worker" ,
493- tailEvents : [
749+ tailEvents : expect . arrayContaining ( [
494750 [ [ "[Worker Entrypoint]" ] , [ "hello from test" ] ] ,
495751 [ [ "[Worker Entrypoint]" ] , [ "yet another log" , "and another one" ] ] ,
496- ] ,
752+ ] ) ,
497753 } ) ;
498754 } ) ;
499755 } ) ;
@@ -642,15 +898,15 @@ describe("Dev Registry: getPlatformProxy -> wrangler / vite dev", () => {
642898 const stub = env . DURABLE_OBJECT . get ( id ) ;
643899
644900 expect ( ( ) => stub . ping ( ) ) . toThrowErrorMatchingInlineSnapshot (
645- `[Error: Cannot access "ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
901+ `[Error: Cannot access "TestObject# ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
646902 ) ;
647903 await runWranglerDev (
648904 "wrangler.internal-durable-object.jsonc" ,
649905 devRegistryPath
650906 ) ;
651907
652908 expect ( ( ) => stub . ping ( ) ) . toThrowErrorMatchingInlineSnapshot (
653- `[Error: Cannot access "ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
909+ `[Error: Cannot access "TestObject# ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
654910 ) ;
655911 } ) ;
656912} ) ;
0 commit comments