@@ -6,10 +6,11 @@ import { globby } from 'globby'
66import { $fetch } from 'ofetch'
77import { exec } from 'tinyexec'
88import { afterAll , beforeAll , describe , expect , it } from 'vitest'
9- import { extractOgImageUrl , setupImageSnapshots , SNAPSHOT_STRICT } from '../utils'
9+ import { ensureLocalModuleStub , extractOgImageUrl , getWranglerTestEnv , isWranglerRuntimeUnsupportedError , readLatestWranglerLog , setupImageSnapshots , SNAPSHOT_STRICT } from '../utils'
1010
1111const { resolve } = createResolver ( import . meta. url )
1212const fixtureDir = resolve ( '../fixtures/cloudflare-satori' )
13+ const wranglerEnvName = 'cloudflare-satori'
1314
1415setupImageSnapshots ( SNAPSHOT_STRICT )
1516
@@ -27,7 +28,11 @@ catch {
2728// Check if wrangler is available
2829let hasWrangler = false
2930try {
30- await exec ( 'wrangler' , [ '--version' ] )
31+ await exec ( 'wrangler' , [ '--version' ] , {
32+ nodeOptions : {
33+ env : getWranglerTestEnv ( process . env , wranglerEnvName ) ,
34+ } ,
35+ } )
3136 hasWrangler = true
3237}
3338catch {
@@ -36,11 +41,14 @@ catch {
3641
3742const canRunTests = hasSatoriDeps && hasWrangler
3843const isCI = ! ! process . env . CI
44+ const hasSandboxedRuntime = ! ! process . env . CODEX_SANDBOX_NETWORK_DISABLED || ! ! process . env . NUXT_OG_IMAGE_SKIP_EDGE_RUNTIME
3945
4046let wranglerProcess : ChildProcess | null = null
4147let serverUrl = ''
48+ let skipWranglerRuntime = false
4249
4350async function buildFixture ( ) {
51+ await ensureLocalModuleStub ( )
4452 await exec ( 'nuxt' , [ 'build' ] , {
4553 nodeOptions : {
4654 cwd : fixtureDir ,
@@ -51,28 +59,48 @@ async function buildFixture() {
5159
5260async function startWrangler ( ) : Promise < string > {
5361 return new Promise ( ( resolve , reject ) => {
62+ let settled = false
5463 const proc = spawn ( 'wrangler' , [ 'dev' , '--port' , '8789' ] , {
5564 cwd : fixtureDir ,
65+ env : {
66+ ...getWranglerTestEnv ( process . env , wranglerEnvName ) ,
67+ CI : '1' ,
68+ } ,
5669 stdio : [ 'ignore' , 'pipe' , 'pipe' ] ,
5770 } )
5871
5972 wranglerProcess = proc
6073 let output = ''
74+ const finish = ( value : string ) => {
75+ if ( settled )
76+ return
77+ settled = true
78+ resolve ( value )
79+ }
80+ const fail = ( message : string ) => {
81+ if ( settled )
82+ return
83+ settled = true
84+ reject ( new Error ( `Wrangler failed to start: ${ message } ` ) )
85+ }
6186
6287 proc . stdout ?. on ( 'data' , ( data ) => {
6388 output += data . toString ( )
6489 const match = output . match ( / R e a d y o n ( h t t p : \/ \/ \S + ) / )
65- if ( match ?. [ 1 ] ) {
66- resolve ( match [ 1 ] )
67- }
90+ if ( match ?. [ 1 ] )
91+ finish ( match [ 1 ] )
6892 } )
6993
7094 proc . stderr ?. on ( 'data' , ( data ) => {
7195 output += data . toString ( )
7296 } )
7397
74- proc . on ( 'error' , reject )
75- setTimeout ( ( ) => reject ( new Error ( `Wrangler failed to start: ${ output } ` ) ) , 30000 )
98+ proc . on ( 'error' , error => fail ( `${ output } \n${ error . message } ` . trim ( ) ) )
99+ proc . on ( 'close' , async ( code ) => {
100+ if ( ! settled && code )
101+ fail ( [ output , await readLatestWranglerLog ( wranglerEnvName ) ] . filter ( Boolean ) . join ( '\n' ) )
102+ } )
103+ setTimeout ( fail , 30000 , output )
76104 } )
77105}
78106
@@ -111,17 +139,29 @@ describe('cloudflare-satori', () => {
111139 } )
112140 } )
113141
114- // Skip wrangler runtime in CI - inspector port 9229 conflicts with other processes
115- describe . runIf ( canRunTests && ! isCI ) ( 'wrangler runtime' , ( ) => {
142+ // Skip wrangler runtime in CI or sandboxed environments where local interfaces are unavailable
143+ describe . runIf ( canRunTests && ! isCI && ! hasSandboxedRuntime ) ( 'wrangler runtime' , ( ) => {
116144 beforeAll ( async ( ) => {
117- serverUrl = await startWrangler ( )
145+ try {
146+ serverUrl = await startWrangler ( )
147+ }
148+ catch ( error ) {
149+ if ( isWranglerRuntimeUnsupportedError ( error ) ) {
150+ skipWranglerRuntime = true
151+ return
152+ }
153+ throw error
154+ }
118155 } , 60000 )
119156
120157 afterAll ( ( ) => {
121158 stopWrangler ( )
122159 } )
123160
124161 it ( 'serves prerendered og images via wrangler' , async ( ) => {
162+ if ( skipWranglerRuntime )
163+ return
164+
125165 const html = await $fetch < string > ( serverUrl )
126166 const ogImagePath = extractOgImageUrl ( html )
127167 expect ( ogImagePath ) . toBeTruthy ( )
@@ -136,6 +176,9 @@ describe('cloudflare-satori', () => {
136176 } , 30000 )
137177
138178 it ( 'generates og images dynamically at runtime via wrangler' , async ( ) => {
179+ if ( skipWranglerRuntime )
180+ return
181+
139182 const image = await $fetch ( `${ serverUrl } /_og/d/image?path=/` , {
140183 responseType : 'arrayBuffer' as const ,
141184 } )
0 commit comments