run-e2e.mjs 2.03 KB
import { spawn } from 'node:child_process'

const VITE_READY_PATTERN = /127\.0\.0\.1:4174/
const START_TIMEOUT = 20_000

function waitForServer(serverProcess) {
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      reject(new Error('等待 Vite 测试服务启动超时'))
    }, START_TIMEOUT)

    const handleOutput = (chunk) => {
      const text = chunk.toString()
      process.stdout.write(text)

      if (VITE_READY_PATTERN.test(text)) {
        clearTimeout(timeout)
        serverProcess.stdout.off('data', handleOutput)
        serverProcess.stderr.off('data', handleOutput)
        resolve()
      }
    }

    serverProcess.stdout.on('data', handleOutput)
    serverProcess.stderr.on('data', handleOutput)
    serverProcess.once('exit', (code) => {
      clearTimeout(timeout)
      reject(new Error(`Vite 测试服务启动失败,退出码:${code ?? 'unknown'}`))
    })
  })
}

function killProcessTree(serverProcess) {
  return new Promise((resolve) => {
    if (serverProcess.killed) {
      resolve()
      return
    }

    serverProcess.once('exit', () => resolve())
    serverProcess.kill('SIGTERM')

    setTimeout(() => {
      if (!serverProcess.killed) {
        serverProcess.kill('SIGKILL')
      }
    }, 3_000)
  })
}

async function main() {
  const playwrightArgs = process.argv.slice(2)
  const serverProcess = spawn(
    'npx',
    ['vite', '--host', '127.0.0.1', '--port', '4174', '--strictPort'],
    {
      stdio: ['ignore', 'pipe', 'pipe'],
      env: process.env,
    },
  )

  try {
    await waitForServer(serverProcess)

    const testProcess = spawn('npx', ['playwright', 'test', ...playwrightArgs], {
      stdio: 'inherit',
      env: process.env,
    })

    const exitCode = await new Promise((resolve, reject) => {
      testProcess.once('exit', (code) => resolve(code ?? 1))
      testProcess.once('error', reject)
    })

    process.exitCode = exitCode
  } finally {
    await killProcessTree(serverProcess)
  }
}

main().catch((error) => {
  console.error(error)
  process.exitCode = 1
})