90 lines
3.8 KiB
Markdown
90 lines
3.8 KiB
Markdown
|
|
---
|
||
|
|
kind: task
|
||
|
|
slug: bootstrap-vitest-for-apps-web
|
||
|
|
title: Bootstrap Vitest for the Next.js app (apps/web) with alias + env wiring
|
||
|
|
plan_slug: multitenant-saas-hardening
|
||
|
|
epic_slug: test-foundation
|
||
|
|
status: draft
|
||
|
|
priority: P2
|
||
|
|
tenant_id: global
|
||
|
|
owner: unassigned
|
||
|
|
cursor_todo_id: null
|
||
|
|
updated_at: "2026-06-02"
|
||
|
|
---
|
||
|
|
|
||
|
|
# Task summary
|
||
|
|
|
||
|
|
Vitest is configured for `packages/shared`, `packages/database`, and `packages/ai` (see `Task-bootstrap-vitest-and-ci`). It is NOT configured for `apps/web`. This means callback logic, tRPC procedures, and React hooks in the web app have no unit-test home — only the manual smoke-test path covers them.
|
||
|
|
|
||
|
|
This task adds the harness so future work can put real assertions next to the code they verify.
|
||
|
|
|
||
|
|
## Description
|
||
|
|
|
||
|
|
### Vitest config
|
||
|
|
|
||
|
|
Add `apps/web/vitest.config.ts`. The Next.js app uses a `@/*` path alias and a mix of server-only modules (DB clients, NextAuth callbacks) and client modules (React components). The config has to:
|
||
|
|
|
||
|
|
- Resolve `@/*` to `apps/web/*` (matches `tsconfig.json`).
|
||
|
|
- Run server-side modules under `environment: "node"`.
|
||
|
|
- Run React-component modules under `environment: "jsdom"` with `@testing-library/react` available. (Optional in v1 — start with node tests only; React testing is its own incremental step.)
|
||
|
|
- Mock `next/headers`, `next/navigation`, and `next-auth` for any test that imports a Next-specific module without booting the full framework.
|
||
|
|
|
||
|
|
Reference: [Next.js + Vitest docs](https://nextjs.org/docs/app/building-your-application/testing/vitest).
|
||
|
|
|
||
|
|
### Add `test` + `test:watch` scripts to `apps/web/package.json` and verify `pnpm test` (turbo) picks them up
|
||
|
|
|
||
|
|
### Initial tests (high-ROI)
|
||
|
|
|
||
|
|
The point of bootstrapping the harness is to immediately backfill the assertions that were deferred from `Task-multi-email-identity`. Specifically:
|
||
|
|
|
||
|
|
1. **`resolveOAuthEmailVerified`** (currently a non-exported helper in `apps/web/lib/auth.ts`). Either extract to its own module or export it. Test:
|
||
|
|
- Google + Authentik branches return `profile.email_verified` directly.
|
||
|
|
- GitHub branch makes the right `fetch` call and reads `verified` from the matching entry. Mock `globalThis.fetch`.
|
||
|
|
- Unknown provider returns `false`.
|
||
|
|
|
||
|
|
2. **`resolveOAuthUser`** — harder, hits the DB. Either:
|
||
|
|
- Set up a test-DB harness (transaction-per-test pattern with `pg-test-transactions` or hand-rolled BEGIN/ROLLBACK).
|
||
|
|
- OR mock `getSql` and assert the SQL templates.
|
||
|
|
|
||
|
|
I'd vote for the test-DB harness eventually — mocking SQL strings is brittle — but it's a meaningful chunk of infrastructure. Filed as a follow-up to this task if it bloats.
|
||
|
|
|
||
|
|
3. **`userOwnsEmail` + `findUserIdByVerifiedEmail`** in `apps/web/server/lib/identity.ts`. Same DB-harness question.
|
||
|
|
|
||
|
|
### Anti-goals (defer)
|
||
|
|
|
||
|
|
- E2E tests via Playwright. That's a separate plan.
|
||
|
|
- Full coverage of every tRPC procedure. Add tests where regressions would hurt; don't manufacture coverage.
|
||
|
|
|
||
|
|
## Subtasks
|
||
|
|
|
||
|
|
- [ ] Add `apps/web/vitest.config.ts` with alias + env wiring.
|
||
|
|
- [ ] Add `test` / `test:watch` scripts to `apps/web/package.json`.
|
||
|
|
- [ ] Decide on test-DB strategy (real Postgres via a `_test` suffix DB + per-test BEGIN/ROLLBACK is recommended). Document it in `AGENTS.md`.
|
||
|
|
- [ ] Backfill the `resolveOAuthEmailVerified` test.
|
||
|
|
- [ ] Backfill the `userOwnsEmail` test against the chosen DB harness.
|
||
|
|
|
||
|
|
## Owner or assignee
|
||
|
|
|
||
|
|
Unassigned
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
draft
|
||
|
|
|
||
|
|
## Estimation
|
||
|
|
|
||
|
|
M
|
||
|
|
|
||
|
|
## Acceptance criteria
|
||
|
|
|
||
|
|
- [ ] `pnpm --filter @tasks/web test` runs and passes from a clean clone.
|
||
|
|
- [ ] `pnpm test` (turbo, root) includes the apps/web suite.
|
||
|
|
- [ ] At least one real test per planned target (`resolveOAuthEmailVerified`, `userOwnsEmail`).
|
||
|
|
- [ ] CI gates the merged result.
|
||
|
|
|
||
|
|
## Links
|
||
|
|
|
||
|
|
- Epic: `./Epic-test-foundation.md`
|
||
|
|
- Plan: `../Plan-multitenant-saas-hardening.md`
|
||
|
|
- Unblocks proper test coverage for: `Task-multi-email-identity.md`, all subsequent `Plan-multitenant-saas-hardening` work that lives in `apps/web`.
|