fix: harden engine, enrich failure diagnostics, close adoption gaps
- P0: CLI verify now honors test budget with seeded multi-sample - P0: Observe sampling enforced via Math.random() gate in hook-validator - P1: Remove misleading undici-mock-agent isolation option - P1: Qualify reuses shared discoverRouteDetails() with warnings - P1: Chaos/scenario config exposed via preset schema - P1: README/docs limitations updated to current state - P2: Nested response annotations prefer 2xx deterministically - P2: --changed documented as heuristic in verify.md - Add observe sink tests (sampling 0/1, sink failure non-interference) - Add verify runs regression tests (scale, determinism, variants) - Add configured-scenario qualify test (independent of OAuth fixture) - Add coverageBreakdown to qualify artifacts (per-gate route coverage) - Add production-style observe example with real sink in docs/observe.md - Add nightly/staging vs PR gating guidance to docs/qualify.md - Enrich VerifyFailure with formula-aware diagnostics: status:201 => 'HTTP 200', body field checks => actual values - Remove stale observe CLI activation message - Document outbound mocks as process-global in getting-started.md - Refresh APOPHIS_ADOPTION_AUDIT.md with current state 903 tests pass, build clean, typecheck clean.
This commit is contained in:
@@ -43,7 +43,7 @@ describe('packaging', () => {
|
||||
it('--version exits 0 and prints version', () => {
|
||||
const { stdout, status } = run(['--version']);
|
||||
assert.strictEqual(status, 0, `Expected exit 0, got ${status}`);
|
||||
assert.match(stdout, /2\.0\.0/, `Version should include 2.0.0, got: ${stdout}`);
|
||||
assert.match(stdout, /2\.7\.0/, `Version should include 2.7.0, got: ${stdout}`);
|
||||
});
|
||||
|
||||
it('init --help exits 0 and prints init help', () => {
|
||||
@@ -103,7 +103,7 @@ describe('packaging', () => {
|
||||
name: 'test-consumer',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'apophis-fastify': `file:${ROOT}`,
|
||||
'@apophis/fastify': `file:${ROOT}`,
|
||||
},
|
||||
};
|
||||
writeFileSync(join(tmpDir, 'package.json'), JSON.stringify(pkg, null, 2));
|
||||
@@ -134,6 +134,118 @@ describe('packaging', () => {
|
||||
assert(files.includes('dist/cli/index.js'), 'Tarball must include dist/cli/index.js');
|
||||
});
|
||||
|
||||
it('npm pack does not contain dist/test files', () => {
|
||||
const result = spawnSync('npm', ['pack', '--dry-run', '--json'], {
|
||||
cwd: ROOT, encoding: 'utf8', timeout: 30000,
|
||||
});
|
||||
assert.strictEqual(result.status, 0, `npm pack failed: ${result.stderr}`);
|
||||
const packOutput = JSON.parse(result.stdout);
|
||||
const files = packOutput[0]?.files?.map((f: { path: string }) => f.path) || [];
|
||||
const testFiles = files.filter((f: string) => f.includes('dist/test/'));
|
||||
assert.strictEqual(testFiles.length, 0, `Package must not contain dist/test/ files. Found: ${testFiles.join(', ')}`);
|
||||
});
|
||||
|
||||
it('real consumer can import the package after install', () => {
|
||||
const tmpDir = join(tmpdir(), `apophis-consumer-${Date.now()}`);
|
||||
mkdirSync(tmpDir, { recursive: true });
|
||||
try {
|
||||
const pkg = {
|
||||
name: 'test-consumer-import',
|
||||
version: '1.0.0',
|
||||
type: 'module',
|
||||
dependencies: {
|
||||
'@apophis/fastify': `file:${ROOT}`,
|
||||
},
|
||||
};
|
||||
writeFileSync(join(tmpDir, 'package.json'), JSON.stringify(pkg));
|
||||
|
||||
const installResult = spawnSync('npm', ['install', '--silent', '--install-strategy=nested'], {
|
||||
cwd: tmpDir, encoding: 'utf8', timeout: 120000,
|
||||
});
|
||||
assert.strictEqual(installResult.status, 0, `npm install failed: ${installResult.stderr}`);
|
||||
|
||||
const importRootResult = spawnSync('node', ['-e', "import('@apophis/fastify').then(m => console.log('OK:', Object.keys(m))).catch(e => { console.error('FAIL:', e.message); process.exit(1) })"], {
|
||||
cwd: tmpDir, encoding: 'utf8', timeout: 30000,
|
||||
});
|
||||
assert.strictEqual(importRootResult.status, 0, `Import root failed: ${importRootResult.stderr}`);
|
||||
assert.ok(importRootResult.stdout.includes('OK:'), `Import should print OK, got: ${importRootResult.stdout}`);
|
||||
|
||||
const importExtResult = spawnSync('node', ['-e', "import('@apophis/fastify/extensions').then(m => console.log('EXT OK:', Object.keys(m))).catch(e => { console.error('EXT FAIL:', e.message); process.exit(1) })"], {
|
||||
cwd: tmpDir, encoding: 'utf8', timeout: 30000,
|
||||
});
|
||||
assert.strictEqual(importExtResult.status, 0, `Import extensions failed: ${importExtResult.stderr}`);
|
||||
assert.ok(importExtResult.stdout.includes('EXT OK:'), `Extensions import should print OK, got: ${importExtResult.stdout}`);
|
||||
|
||||
const binResult = spawnSync('node', [join(tmpDir, 'node_modules/.bin/apophis'), '--version'], {
|
||||
cwd: tmpDir, encoding: 'utf8', timeout: 30000,
|
||||
});
|
||||
assert.strictEqual(binResult.status, 0, `CLI bin failed: ${binResult.stderr}`);
|
||||
assert.ok(binResult.stdout.includes('2.'), `CLI should print version starting with 2., got: ${binResult.stdout}`);
|
||||
} finally {
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('TypeScript consumer can import and typecheck', () => {
|
||||
const tmpDir = join(tmpdir(), `apophis-ts-consumer-${Date.now()}`);
|
||||
mkdirSync(tmpDir, { recursive: true });
|
||||
try {
|
||||
writeFileSync(join(tmpDir, 'package.json'), JSON.stringify({
|
||||
name: 'ts-test',
|
||||
version: '1.0.0',
|
||||
type: 'module',
|
||||
dependencies: {
|
||||
'@apophis/fastify': `file:${ROOT}`,
|
||||
'fastify': '^5.0.0',
|
||||
'@fastify/swagger': '^9.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
const installResult = spawnSync('npm', ['install', '--silent', '--install-strategy=nested'], {
|
||||
cwd: tmpDir, encoding: 'utf8', timeout: 120000,
|
||||
});
|
||||
assert.strictEqual(installResult.status, 0, `npm install failed: ${installResult.stderr}`);
|
||||
|
||||
writeFileSync(join(tmpDir, 'consumer.ts'), `
|
||||
import Fastify from 'fastify'
|
||||
import apophis, { createAuthExtension } from '@apophis/fastify'
|
||||
import { jwtExtension } from '@apophis/fastify/extensions'
|
||||
import { sseExtension } from '@apophis/fastify/extensions/sse'
|
||||
import { websocketExtension } from '@apophis/fastify/extensions/websocket'
|
||||
import { createSerializerExtension, createSerializerRegistry } from '@apophis/fastify/extensions/serializers'
|
||||
import { createHeaderExtension } from '@apophis/fastify/extension/factories'
|
||||
|
||||
const app = Fastify()
|
||||
app.register(apophis, {
|
||||
extensions: [jwtExtension, sseExtension, websocketExtension],
|
||||
})
|
||||
`);
|
||||
|
||||
writeFileSync(join(tmpDir, 'tsconfig.json'), JSON.stringify({
|
||||
compilerOptions: {
|
||||
target: 'es2020',
|
||||
module: 'nodenext',
|
||||
moduleResolution: 'nodenext',
|
||||
strict: true,
|
||||
skipLibCheck: true,
|
||||
},
|
||||
include: ['consumer.ts'],
|
||||
}));
|
||||
|
||||
const tsc = join(ROOT, 'node_modules/.bin/tsc');
|
||||
const tscResult = spawnSync(tsc, ['--noEmit', '--project', tmpDir], {
|
||||
cwd: tmpDir, encoding: 'utf8', timeout: 60000,
|
||||
});
|
||||
|
||||
if (tscResult.status !== 0) {
|
||||
console.error('TSC errors:', tscResult.stdout + tscResult.stderr);
|
||||
}
|
||||
assert.strictEqual(tscResult.status, 0, `TypeScript typecheck must pass cleanly. Got:\n${tscResult.stdout}${tscResult.stderr}`);
|
||||
} finally {
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('npx apophis --help works in a temp project after npm install', () => {
|
||||
const tmpDir = join(tmpdir(), `apophis-npx-test-${Date.now()}`);
|
||||
mkdirSync(tmpDir, { recursive: true });
|
||||
@@ -142,7 +254,7 @@ describe('packaging', () => {
|
||||
name: 'npx-test',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'apophis-fastify': `file:${ROOT}`,
|
||||
'@apophis/fastify': `file:${ROOT}`,
|
||||
},
|
||||
};
|
||||
writeFileSync(join(tmpDir, 'package.json'), JSON.stringify(pkg, null, 2));
|
||||
@@ -173,7 +285,7 @@ describe('packaging', () => {
|
||||
name: 'npx-test',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'apophis-fastify': `file:${ROOT}`,
|
||||
'@apophis/fastify': `file:${ROOT}`,
|
||||
},
|
||||
};
|
||||
writeFileSync(join(tmpDir, 'package.json'), JSON.stringify(pkg, null, 2));
|
||||
@@ -199,7 +311,7 @@ describe('packaging', () => {
|
||||
|
||||
it('declares supported Node policy and default confidence test path', () => {
|
||||
const rootPkg = JSON.parse(readFileSync(PACKAGE_JSON, 'utf8'));
|
||||
assert.strictEqual(rootPkg.engines.node, '^20.0.0 || ^22.0.0');
|
||||
assert.strictEqual(rootPkg.engines.node, '>=20.18.1 <21 || >=22 <23');
|
||||
assert.strictEqual(rootPkg.scripts.test, 'npm run build && npm run test:src && npm run test:cli');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user