( fixtureName: string, fn: (port: number) => Promise<void> )
| 429 | ); |
| 430 | |
| 431 | function withLocalDev( |
| 432 | fixtureName: string, |
| 433 | fn: (port: number) => Promise<void> |
| 434 | ) { |
| 435 | return async () => { |
| 436 | const cwd = join(__dirname, 'fixtures', fixtureName); |
| 437 | const port = await getPort(); |
| 438 | let stdout = ''; |
| 439 | let stderr = ''; |
| 440 | |
| 441 | await _execa('npm', ['install'], { |
| 442 | cwd, |
| 443 | shell: true, |
| 444 | stdio: 'inherit', |
| 445 | }); |
| 446 | |
| 447 | const dev = _execa( |
| 448 | binaryPath, |
| 449 | ['dev', '--local', '--yes', '--listen', String(port)], |
| 450 | { |
| 451 | cwd, |
| 452 | env: { ...process.env, __VERCEL_SKIP_DEV_CMD: '1' }, |
| 453 | reject: false, |
| 454 | shell: true, |
| 455 | stdio: 'pipe', |
| 456 | } |
| 457 | ); |
| 458 | |
| 459 | dev.stdout?.setEncoding('utf8'); |
| 460 | dev.stderr?.setEncoding('utf8'); |
| 461 | dev.stdout?.on('data', chunk => { |
| 462 | stdout += chunk; |
| 463 | }); |
| 464 | dev.stderr?.on('data', chunk => { |
| 465 | stderr += chunk; |
| 466 | }); |
| 467 | |
| 468 | try { |
| 469 | await waitForReady(() => `${stdout}\n${stderr}`); |
| 470 | await fn(port); |
| 471 | } finally { |
| 472 | if (dev.pid) { |
| 473 | await nukeProcessTree(dev.pid); |
| 474 | } else { |
| 475 | dev.kill('SIGTERM', { forceKillAfterTimeout: 5000 }); |
| 476 | } |
| 477 | await dev.catch(() => null); |
| 478 | } |
| 479 | |
| 480 | if (dev.exitCode && dev.exitCode !== 0 && dev.exitCode !== 143) { |
| 481 | throw new Error( |
| 482 | `vc dev exited with ${dev.exitCode}:\n${stdout}\n${stderr}` |
| 483 | ); |
| 484 | } |
| 485 | }; |
| 486 | } |
| 487 | |
| 488 | async function waitForReady(readOutput: () => string) { |
no test coverage detected