Files
triggerdotdev--trigger.dev/apps/webapp/test
Daniel Sutton a1ca64613b fix(webapp): reuse the primary db pool for legacy run-ops when DSNs match (#4253)
## Summary

When the run-ops split is enabled, the legacy run-ops database client
was always constructed as its own connection pool, even when it points
at the same database as the primary (control-plane) client. On setups
where those two DSNs resolve to the same physical database, this opened
a second, redundant pool and doubled the number of connections used
against that database. This change makes the legacy client reuse the
primary client's pool whenever their DSNs point at the same database,
and only open a separate pool when they genuinely differ.

## Fix

A small `sameDatabaseTarget` comparison (host, port, database name,
user) decides whether the legacy DSN points at the same database as the
primary. When it does, the legacy handle reuses the primary client by
reference, so no second pool is opened. When the DSNs diverge, the
legacy client is built independently as before, so the split still works
once the databases are actually separate.

Two smaller changes ride along:

- An optional per-pool limit for the run-ops read replica, which
connects unpooled and so draws raw backend connections; unset, it falls
back to the existing default and behaviour is unchanged.
- A startup warning about a missing legacy replica URL is now suppressed
when the legacy client shares the primary pool, where it would be
misleading.

## Verification

Booted the webapp end-to-end in three modes and confirmed the pools
opened as expected via the client's own startup logs and live backend
connection counts: split off (single pool), split on with a shared
database (legacy reuses the primary pool, no doubling), and split on
with separate databases (legacy opens its own pool).
2026-07-14 11:20:21 +01:00
..

Webapp tests

Three suites live in this directory.

Unit tests — *.test.ts

Run with pnpm test from apps/webapp. Default vitest pickup. No container setup. Run on every PR via unit-tests-webapp.yml.

Smoke e2e — *.e2e.test.ts

End-to-end auth baseline that proves the route auth plumbing is wired up. Each file spins up its own webapp + Postgres + Redis container in beforeAll (~30s startup). Vitest config: vitest.e2e.config.ts. Run on every PR via e2e-webapp.yml.

cd apps/webapp
pnpm exec vitest --config vitest.e2e.config.ts

Comprehensive auth e2e — *.e2e.full.test.ts

The full RBAC auth matrix — every route family with explicit pass/fail scenarios. See TRI-8731 for the parent ticket and TRI-8732 onwards for each family's coverage spec.

Architecture: one container reused across the whole suite via vitest.e2e.full.config.ts's globalSetup. Test files share the server through getTestServer() from helpers/sharedTestServer.ts. Each test seeds its own resources so order doesn't matter.

Layout:

File Top-level describe Family subtasks
auth-api.e2e.full.test.ts API TRI-8733 trigger, TRI-8734 run resource, TRI-8735 run mutations, TRI-8736 run lists, TRI-8737 batches, TRI-8738 prompts, TRI-8739 deployments + query, TRI-8740 waitpoints + input streams, TRI-8741 PAT
auth-dashboard.e2e.full.test.ts Dashboard TRI-8742 admin pages
auth-cross-cutting.e2e.full.test.ts Cross-cutting TRI-8743 deleted projects / revoked keys / expired JWTs / env mismatch / force-fallback toggle

Adding a new family: pick the relevant file, add a nested describe block. Inside, seed your own fixtures via the helpers and hit the shared server.

describe("Trigger task", () => {
  const server = getTestServer();

  it("missing Authorization → 401", async () => {
    const res = await server.webapp.fetch("/api/v1/tasks/x/trigger", { method: "POST", body: "{}" });
    expect(res.status).toBe(401);
  });
});

CI: e2e-webapp-auth-full.yml. Triggers on workflow_dispatch, nightly schedule, and PRs touching auth-relevant paths (route builders, rbac.server.ts, apiAuth.server.ts, apiroutes, the suite itself).

Run locally:

cd apps/webapp
pnpm exec vitest --config vitest.e2e.full.config.ts