Skip to content

Commit 7841f91

Browse files
feat: feat: Prism-based OpenAPI mock server for contract verification in CI
1 parent 7ca2d9b commit 7841f91

1 file changed

Lines changed: 64 additions & 0 deletions

File tree

tests/pact/replay-prism.mjs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Replays the recorded Pact request corpus against a running Prism mock
2+
// server and fails if any request cannot be resolved by the OpenAPI spec.
3+
import fs from 'node:fs';
4+
import path from 'node:path';
5+
6+
const PRISM = process.env.PRISM_URL || 'http://127.0.0.1:4010';
7+
8+
function walk(dir) {
9+
const out = [];
10+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
11+
const p = path.join(dir, entry.name);
12+
if (entry.isDirectory()) out.push(...walk(p));
13+
else if (entry.name.endsWith('.json')) out.push(p);
14+
}
15+
return out;
16+
}
17+
18+
function extractRequests(pact) {
19+
const reqs = [];
20+
const interactions = pact.interactions || pact.pacts || pact.contracts || [];
21+
for (const it of interactions) {
22+
const req = it.request || it;
23+
if (req && req.method && req.path) {
24+
reqs.push({ method: String(req.method).toUpperCase(), path: req.path, description: it.description || '' });
25+
}
26+
}
27+
return reqs;
28+
}
29+
30+
let total = 0;
31+
let unresolved = 0;
32+
const files = walk(process.argv[2] || 'tests/pact');
33+
if (files.length === 0) {
34+
console.error('::error::No Pact JSON files found under tests/pact');
35+
process.exit(1);
36+
}
37+
38+
for (const file of files) {
39+
const pact = JSON.parse(fs.readFileSync(file, 'utf8'));
40+
for (const req of extractRequests(pact)) {
41+
total += 1;
42+
const url = `${PRISM}${req.path}`;
43+
try {
44+
const res = await fetch(url, {
45+
method: req.method,
46+
headers: { 'Content-Type': 'application/json', Prefer: 'code=200, example=first' },
47+
});
48+
const text = await res.text();
49+
const notResolved = text.includes('NO_ROUTE_MATCHED') || text.includes('No route matched');
50+
if (res.status === 404 && notResolved) {
51+
console.error(`FAIL ${req.method} ${req.path} - not resolvable by OpenAPI spec (${req.description})`);
52+
unresolved += 1;
53+
} else {
54+
console.log(`OK ${res.status} ${req.method} ${req.path} (${req.description})`);
55+
}
56+
} catch (e) {
57+
console.error(`FAIL ${req.method} ${req.path} - ${e.message}`);
58+
unresolved += 1;
59+
}
60+
}
61+
}
62+
63+
console.log(`Replayed ${total} requests, ${unresolved} unresolved.`);
64+
if (unresolved > 0) process.exit(1);

0 commit comments

Comments
 (0)