fix: use preview:dev for correct dist dir and kill process groups in test:e2e

- build:dev outputs to dist-dev/ but preview serves from dist/,
  so use preview:dev which serves from dist-dev/
- pnpm spawns child processes, so SIGINT only hits the wrapper;
  use setpgid + kill(-pgid) to terminate the entire process group
This commit is contained in:
kolaente 2026-02-21 21:35:24 +01:00
parent 51a9f9c9f8
commit d00851292d
1 changed files with 37 additions and 16 deletions

View File

@ -37,6 +37,7 @@ import (
"runtime"
"strconv"
"strings"
"syscall"
"time"
"github.com/iancoleman/strcase"
@ -337,6 +338,23 @@ func getRandomPort() (int, error) {
return l.Addr().(*net.TCPAddr).Port, nil
}
// setProcessGroup configures a command to run in its own process group,
// so that all child processes can be killed together.
func setProcessGroup(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
}
// killProcessGroup sends a signal to the entire process group of the given command.
func killProcessGroup(cmd *exec.Cmd) {
if cmd.Process != nil {
pgid, err := syscall.Getpgid(cmd.Process.Pid)
if err == nil {
syscall.Kill(-pgid, syscall.SIGTERM)
}
cmd.Wait()
}
}
// waitForHTTP polls a URL until it returns a 200 status or the timeout expires.
func waitForHTTP(url string, timeout time.Duration) error {
deadline := time.Now().Add(timeout)
@ -487,15 +505,13 @@ func (Test) E2E(args string) error {
)
apiCmd.Stdout = os.Stdout
apiCmd.Stderr = os.Stderr
setProcessGroup(apiCmd)
if err := apiCmd.Start(); err != nil {
return fmt.Errorf("failed to start API: %w", err)
}
defer func() {
fmt.Println("\n--- Stopping API server ---")
if apiCmd.Process != nil {
apiCmd.Process.Signal(os.Interrupt)
apiCmd.Wait()
}
killProcessGroup(apiCmd)
}()
// Wait for API to be ready
@ -506,25 +522,30 @@ func (Test) E2E(args string) error {
}
printSuccess("API is ready!")
// Start the frontend dev server
fmt.Println("\n--- Starting frontend dev server ---")
frontendCmd := exec.Command("pnpm", "dev", "--port", strconv.Itoa(frontendPort))
// Build the frontend
fmt.Println("\n--- Building frontend ---")
buildFrontendCmd := exec.Command("pnpm", "build:dev")
buildFrontendCmd.Dir = "frontend"
buildFrontendCmd.Stdout = os.Stdout
buildFrontendCmd.Stderr = os.Stderr
if err := buildFrontendCmd.Run(); err != nil {
return fmt.Errorf("failed to build frontend: %w", err)
}
printSuccess("Frontend built!")
// Serve the built frontend with vite preview (static, no file watchers)
fmt.Println("\n--- Starting frontend preview server ---")
frontendCmd := exec.Command("pnpm", "preview:dev", "--port", strconv.Itoa(frontendPort))
frontendCmd.Dir = "frontend"
frontendCmd.Env = append(os.Environ(),
fmt.Sprintf("VIKUNJA_FRONTEND_PORT=%d", frontendPort),
fmt.Sprintf("DEV_PROXY=http://127.0.0.1:%d", apiPort),
)
frontendCmd.Stdout = os.Stdout
frontendCmd.Stderr = os.Stderr
setProcessGroup(frontendCmd)
if err := frontendCmd.Start(); err != nil {
return fmt.Errorf("failed to start frontend: %w", err)
}
defer func() {
fmt.Println("\n--- Stopping frontend dev server ---")
if frontendCmd.Process != nil {
frontendCmd.Process.Signal(os.Interrupt)
frontendCmd.Wait()
}
fmt.Println("\n--- Stopping frontend preview server ---")
killProcessGroup(frontendCmd)
}()
// Wait for frontend to be ready