mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
Second pass over the suite, driven by the inventory in the gaps document. Nine agents wrote suites in parallel against private databases, then a tenth read all of it adversarially and five of its findings were fixed. unit + component 2076 -> 2079 (+888 over the round) api 647 -> 1015 e2e 18 -> 29 What was closed: - lib/route-access.ts, the page-level authorization layer, went from zero tests to 48. Every API route was guarded and none of the pages were. - The five media proxy routes now have a real 2xx beside every 403. The blocker was the positive control, solved by stubbing r2Client.send() and leaving lib/r2-media-proxy.ts itself real. - Every remaining server-side lib module: invitations, email verification, the upload tokens, the logger, request origin, the whole R2 and Bunny lifecycle, notifications and admin stats. - Six video-page hooks, and the chunking arithmetic extracted out of lib/client/r2-video-upload.ts as a pure module. - Five end-to-end flows: workspace members, bulk operations, the admin area, player interaction and failure recovery. Three things about the harness itself turned out to be wrong: - Two @/lib/r2 stubs in tests/setup/api.ts had the wrong return shape, so every route reaching finalizeR2VideoUpload silently took the "not a valid video" branch and no test noticed. - The auth matrix asserted only "not 2xx", which two entries satisfied without their guard existing. It now requires 401 or 403, which makes both load-bearing, and all 60 routes pass the stricter form. - Both admin API routes had no positive control anywhere: replacing their guard with an unconditional refusal left the entire suite green. Found by the adversarial review, now covered. Process: - bun run test:mutation runs StrykerJS over the authorization and validation modules. Diagnostic, not a gate, weekly in CI rather than on a push. - playwright.config.ts gains an opt-in webkit project for the player spec. - AGENTS.md now requires a batch of new tests to be reviewed by somebody who did not write them. Only two production files change, both deliberate: lib/auth.ts loses a verbatim copy of its own permission formulas, and lib/client/r2-video-upload.ts calls the extracted arithmetic. No behaviour change in either.
33 lines
1.6 KiB
TypeScript
33 lines
1.6 KiB
TypeScript
import { defineConfig } from 'vitest/config';
|
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
|
|
// The Vitest config StrykerJS runs against, kept apart from vitest.config.ts on
|
|
// purpose.
|
|
//
|
|
// Only the `unit` project belongs here. Stryker restarts the suite once per
|
|
// surviving mutant across several concurrent workers, and the `api` project
|
|
// cannot take that: it shares one Postgres, empties every table between tests,
|
|
// and therefore runs with `fileParallelism: false`. Pointing Stryker at it would
|
|
// either serialise the whole run into something nobody waits for, or let two
|
|
// workers truncate each other's rows and report the resulting failures as killed
|
|
// mutants, which is a false pass.
|
|
//
|
|
// So mutation coverage is scoped to modules the unit project genuinely covers.
|
|
// `stryker.config.json` lists them explicitly rather than globbing `lib/`, for
|
|
// the same reason: a file whose only coverage is an API integration test would
|
|
// report every one of its mutants as survived, and a report that is mostly noise
|
|
// gets ignored.
|
|
export default defineConfig({
|
|
plugins: [tsconfigPaths()],
|
|
test: {
|
|
environment: 'node',
|
|
include: ['tests/unit/**/*.test.ts'],
|
|
// Same reason as the root config: next-auth's lib/env.js imports the
|
|
// extensionless specifier 'next/server', which Node's ESM resolver cannot
|
|
// resolve, so it has to go through Vite's resolver instead of being
|
|
// externalised. Stryker runs under node, never under bun, so this is not
|
|
// optional here the way it appears to be locally.
|
|
server: { deps: { inline: [/next-auth/] } },
|
|
},
|
|
});
|