325c827322
All 100 files in extensions/general/mcp-server/__tests__ fake supabase. query-journal.test.ts says out loud that its query chain is "exercised by the live MCP smoke test", and no such test exists in CI. So the PostgREST grammar of 157 tools, every .select() column string, every resource embed, every or=(...) form, is gated by nothing and fails first in production. pg-real cannot cover this: it holds a pg Pool and writes SQL, and none of that grammar is resolved by Postgres. It is resolved by PostgREST at request time. Adds a tool-pg vitest project, a docker-compose stack, a reset script that replays every migration the way the pg-real CI job does, and a CI job. The first sweep covers 74 read tools and finds no malformed query, across 87 real requests. That number is honest rather than impressive: with an empty argument set many tools bail before querying. Per-tool fixtures are what deepen it, and this harness is what makes writing them worth the effort. Includes a self-test that injects a bad column and asserts the harness detects it. That is not ceremony. It caught this file passing green while exercising nothing, twice: once locally where supabase-js prefixes /rest/v1 onto a bare PostgREST that does not serve it, and once on CI where Node 20 has no native WebSocket, so every client construction threw and was swallowed by the per-tool catch as a domain refusal. The client is now built once outside that catch, the proof-of-life assertion counts real requests instead of being trivially satisfiable, and realtime gets an inert transport. Also excludes .next from all three vitest projects. These projects override vitest's default excludes, so a local `npm run build` leaves a traced copy of the repo that gets collected as a second set of test files. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
94 lines
3.3 KiB
TypeScript
94 lines
3.3 KiB
TypeScript
import { defineConfig } from 'vitest/config'
|
|
import path from 'path'
|
|
|
|
const alias = {
|
|
'@': path.resolve(__dirname, '.'),
|
|
// `server-only` is a build-time guard whose real entry point always throws;
|
|
// Next.js swaps it out during bundling, Vitest cannot. Without this stub any
|
|
// test that transitively imports a server-only module fails at import time.
|
|
'server-only': path.resolve(__dirname, 'tests/stubs/server-only.ts'),
|
|
}
|
|
|
|
const unitProject = {
|
|
resolve: { alias },
|
|
test: {
|
|
name: 'unit',
|
|
globals: true,
|
|
environment: 'node' as const,
|
|
include: ['**/*.test.ts'],
|
|
// `.claude/worktrees/*` are ephemeral agent checkouts whose `@/*` imports
|
|
// resolve back to this root: never part of the suite.
|
|
// Two additions to the exclude list, both learned the hard way:
|
|
// * `*.tool.test.ts` also matches `**/*.test.ts`, so without it the unit
|
|
// project runs the PostgREST suite with no stack up.
|
|
// * `.next/standalone` is a traced COPY of the repo left by a local
|
|
// build, so `npm run build && npm test` collects those files a second
|
|
// time. Only two match here today, but the duplication is silent and
|
|
// grows with the build's tracing.
|
|
exclude: [
|
|
'**/node_modules/**',
|
|
'**/*.pg.test.ts',
|
|
'**/*.tool.test.ts',
|
|
'**/.claude/**',
|
|
'**/.next/**',
|
|
],
|
|
},
|
|
}
|
|
|
|
const pgRealProject = {
|
|
resolve: { alias },
|
|
test: {
|
|
name: 'pg-real',
|
|
globals: true,
|
|
environment: 'node' as const,
|
|
include: ['**/*.pg.test.ts'],
|
|
// `.next/standalone` holds a traced copy of these files after a local
|
|
// build; 128 of them match this project's glob.
|
|
exclude: ['**/node_modules/**', '**/.claude/**', '**/.next/**'],
|
|
setupFiles: ['tests/pg/setup.ts'],
|
|
// One-connection-at-a-time to avoid cross-file DB contention.
|
|
fileParallelism: false,
|
|
testTimeout: 15000,
|
|
},
|
|
}
|
|
|
|
// MCP tools queried through a REAL supabase-js client against a REAL
|
|
// PostgREST. Separate from pg-real because that project holds a `pg` Pool and
|
|
// writes SQL, which cannot see the half of a tool that PostgREST resolves: the
|
|
// `.select()` column strings, the resource embeds, the or=(...) grammar.
|
|
const toolPgProject = {
|
|
resolve: { alias },
|
|
test: {
|
|
name: 'tool-pg',
|
|
globals: true,
|
|
environment: 'node' as const,
|
|
include: ['**/*.tool.test.ts'],
|
|
// See the unit project's note: `.next/standalone` is a build artifact that
|
|
// would otherwise be collected as a second copy of this suite.
|
|
exclude: ['**/node_modules/**', '**/.claude/**', '**/.next/**'],
|
|
setupFiles: ['tests/tool-pg/setup.ts'],
|
|
// The suite shares one database; parallel files would race on seeded rows.
|
|
fileParallelism: false,
|
|
testTimeout: 30000,
|
|
},
|
|
}
|
|
|
|
// Only register the pg-real project when DATABASE_URL is set. Local devs
|
|
// running a bare `vitest run` would otherwise hit the schema sanity check
|
|
// against a non-existent DB. `npm run test:pg` is the opt-in entry point, and
|
|
// `npm run test:tools` is the equivalent for tool-pg.
|
|
const projects = [
|
|
unitProject,
|
|
...(process.env.DATABASE_URL ? [pgRealProject] : []),
|
|
...(process.env.TOOL_PG_REST_URL ? [toolPgProject] : []),
|
|
]
|
|
|
|
export default defineConfig({
|
|
resolve: { alias },
|
|
test: {
|
|
globals: true,
|
|
environment: 'node',
|
|
projects,
|
|
},
|
|
})
|