Skip to content

Commit d05718d

Browse files
committed
test: isolate runtime e2e ports in dev tests and fix force-kill
1 parent f668b74 commit d05718d

1 file changed

Lines changed: 35 additions & 8 deletions

File tree

‎packages/nuxt-cli/test/e2e/runtimes.spec.ts‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { rm } from 'node:fs/promises'
77
import{join,resolve}from'node:path'
88

99
import{fileURLToPath}from'node:url'
10-
import{getPort,waitForPort}from'get-port-please'
10+
import{checkPort,getPort,waitForPort}from'get-port-please'
1111
import{isCI}from'std-env'
1212
import{WebSocket}from'undici'
1313
import{itas_it,afterAll,beforeAll,describe,expect,vi}from'vitest'
@@ -108,6 +108,7 @@ describe.sequential.each(runtimes)('dev server (%s)', (runtimeName) => {
108108
server=awaitstartDevServer({
109109
cwd,
110110
runtime: runtimeName,
111+
basePort: 3100+runtimes.indexOf(runtimeName)*10,
111112
})
112113
})
113114

@@ -261,11 +262,13 @@ interface DevServerInstance {
261262
asyncfunctionstartDevServer(options: {
262263
cwd: string
263264
port?: number
265+
/** Port to prefer, if free. Each runtime gets its own range so a server that is slow to release its listener cannot collide with the next one. */
266+
basePort?: number
264267
runtime?: 'node'|'bun'|'deno'
265268
env?: Record<string,string>
266269
}): Promise<DevServerInstance>{
267-
const{ cwd,port: preferredPort, runtime ='node', env ={}}=options
268-
constport=preferredPort||awaitgetPort({port: 3100})
270+
const{ cwd,port: preferredPort,basePort =3100,runtime ='node', env ={}}=options
271+
constport=preferredPort||awaitgetPort({port: basePort,host: '127.0.0.1'})
269272
consthost='127.0.0.1'
270273
consturl=`http://${host}:${port}`
271274

@@ -328,19 +331,43 @@ async function startDevServer(options: {
328331
url,
329332
port,
330333
close: async()=>{
331-
returnnewPromise<void>((resolve)=>{
332-
child.kill('SIGTERM')
333-
setTimeout(()=>{
334-
if(!child.killed){
334+
awaitnewPromise<void>((resolve)=>{
335+
if(child.exitCode!==null||child.signalCode!==null){
336+
resolve()
337+
return
338+
}
339+
340+
// `child.killed` only records that a signal was sent, so escalation has to
341+
// look at whether the process has actually gone away.
342+
constforce=setTimeout(()=>{
343+
if(child.exitCode===null&&child.signalCode===null){
335344
child.kill('SIGKILL')
336345
}
337346
},5000)
338-
child.on('exit',()=>resolve())
347+
force.unref?.()
348+
349+
child.on('exit',()=>{
350+
clearTimeout(force)
351+
resolve()
352+
})
353+
child.kill('SIGTERM')
339354
})
355+
356+
awaitwaitForPortRelease(port,host)
340357
},
341358
}
342359
}
343360

361+
/** Wait for a dev server's listener to be released, so the next runtime can bind it. */
362+
asyncfunctionwaitForPortRelease(port: number,host: string,retries=50,delay=100): Promise<void>{
363+
for(leti=0;i<retries;i++){
364+
if(awaitcheckPort(port,host)){
365+
return
366+
}
367+
awaitnewPromise(resolve=>setTimeout(resolve,delay))
368+
}
369+
}
370+
344371
interfaceWebSocketTestOptions{
345372
url: string
346373
timeout?: number

0 commit comments

Comments
 (0)