#!/usr/bin/env node import fs from 'node:fs' import path from 'node:path' const root = path.resolve(process.cwd()) const sourceSpecs = [ path.join(root, 'apps/web/e2e/critical-flows.spec.ts'), path.join(root, 'apps/web/e2e/critical-flows-extended.spec.ts'), ] const fullstackDir = path.join(root, 'apps/web/e2e/full-stack') function read(filePath) { return fs.readFileSync(filePath, 'utf8') } function extractTestNames(content) { const names = [] const regex = /\btest\s*\(\s*(['"])(.*?)\1/g let match while ((match = regex.exec(content)) !== null) { names.push(match[2]) } return names } function listFullstackSpecs(dir) { const entries = fs.readdirSync(dir, { withFileTypes: true }) return entries .filter((entry) => entry.isFile() && entry.name.endsWith('.spec.ts')) .map((entry) => path.join(dir, entry.name)) } const sourceNames = new Set() for (const spec of sourceSpecs) { for (const name of extractTestNames(read(spec))) { sourceNames.add(name) } } const fullstackNames = new Set() for (const spec of listFullstackSpecs(fullstackDir)) { for (const name of extractTestNames(read(spec))) { fullstackNames.add(name) } } const missing = [...sourceNames] .filter((name) => !fullstackNames.has(name)) .sort((a, b) => a.localeCompare(b)) if (missing.length > 0) { console.error('Full-stack parity check failed. Missing scenarios:') for (const name of missing) { console.error(`- ${name}`) } process.exit(1) } console.log(`Full-stack parity check passed (${sourceNames.size} source scenarios covered).`)