Duplicate Code Opportunity
Summary
- Pattern:
makeReq(), makeRes(), makeProxyReq(), makeProxyRes(), and getStructuredLogs() factory functions for building mock HTTP objects are defined independently in each test file.
- Locations: 5 test files in
containers/api-proxy/
- Impact: ~55 duplicate lines across 5 files; any change to mock shape (e.g. adding a new field to
res) requires editing every file independently.
Evidence
containers/api-proxy/server.anthropic-beta.test.js lines 36–85 and containers/api-proxy/server.model-not-supported.test.js lines 38–90 are nearly identical:
// Both files define the same 5 helpers, differing only in req.url:
function makeReq(headers = {}) {
const req = new EventEmitter();
req.url = '/v1/messages'; // anthropic-beta
// req.url = '/v1/chat/completions'; // model-not-supported
req.method = 'POST';
req.headers = { 'content-type': 'application/json', ...headers };
return req;
}
function makeRes() {
const res = {
headersSent: false,
setHeader: jest.fn(),
writeHead: jest.fn(() => { res.headersSent = true; }),
end: jest.fn(),
destroy: jest.fn(),
};
return res;
}
function makeProxyReq() {
const proxyReq = new EventEmitter();
proxyReq.end = jest.fn();
proxyReq.write = jest.fn();
proxyReq.destroy = jest.fn();
return proxyReq;
}
function makeProxyRes(statusCode, headers = { 'content-type': 'application/json' }) {
const proxyRes = new EventEmitter();
proxyRes.statusCode = statusCode;
proxyRes.headers = headers;
proxyRes.pipe = jest.fn();
return proxyRes;
}
function getStructuredLogs(writeSpy, eventName) {
return writeSpy.mock.calls
.map(([line]) => { try { return JSON.parse(line); } catch { return null; } })
.filter(entry => entry && entry.event === eventName);
}
Simpler variants of makeReq + makeRes also appear in:
containers/api-proxy/server.token-guards.test.js (lines 36–52, and again at 115–132)
containers/api-proxy/server.proxy-headers.test.js (lines 30–51)
containers/api-proxy/server.error-handling.test.js (lines 31–51)
Suggested Refactoring
Extract to containers/api-proxy/test-helpers/server-mock-factories.js (the test-helpers/ directory already exists with mock-oidc-server.js and token-tracker-setup.js):
// containers/api-proxy/test-helpers/server-mock-factories.js
'use strict';
const { EventEmitter } = require('events');
function makeReq(url, headers = {}) {
const req = new EventEmitter();
req.url = url;
req.method = 'POST';
req.headers = { 'content-type': 'application/json', ...headers };
return req;
}
function makeRes() {
const res = {
headersSent: false,
setHeader: jest.fn(),
writeHead: jest.fn(() => { res.headersSent = true; }),
end: jest.fn(),
destroy: jest.fn(),
};
return res;
}
function makeProxyReq() {
const proxyReq = new EventEmitter();
proxyReq.end = jest.fn();
proxyReq.write = jest.fn();
proxyReq.destroy = jest.fn();
return proxyReq;
}
function makeProxyRes(statusCode, headers = { 'content-type': 'application/json' }) {
const proxyRes = new EventEmitter();
proxyRes.statusCode = statusCode;
proxyRes.headers = headers;
proxyRes.pipe = jest.fn();
return proxyRes;
}
function getStructuredLogs(writeSpy, eventName) {
return writeSpy.mock.calls
.map(([line]) => { try { return JSON.parse(line); } catch { return null; } })
.filter(entry => entry && entry.event === eventName);
}
module.exports = { makeReq, makeRes, makeProxyReq, makeProxyRes, getStructuredLogs };
Affected Files
containers/api-proxy/server.anthropic-beta.test.js — lines 36–85
containers/api-proxy/server.model-not-supported.test.js — lines 38–90
containers/api-proxy/server.token-guards.test.js — lines 36–52, 115–132
containers/api-proxy/server.proxy-headers.test.js — lines 30–51
containers/api-proxy/server.error-handling.test.js — lines 31–51
Effort Estimate
Low
Detected by Duplicate Code Detector workflow. Run date: 2026-05-27
Generated by Duplicate Code Detector · sonnet46 3.1M · ◷
Duplicate Code Opportunity
Summary
makeReq(),makeRes(),makeProxyReq(),makeProxyRes(), andgetStructuredLogs()factory functions for building mock HTTP objects are defined independently in each test file.containers/api-proxy/res) requires editing every file independently.Evidence
containers/api-proxy/server.anthropic-beta.test.jslines 36–85 andcontainers/api-proxy/server.model-not-supported.test.jslines 38–90 are nearly identical:Simpler variants of
makeReq+makeResalso appear in:containers/api-proxy/server.token-guards.test.js(lines 36–52, and again at 115–132)containers/api-proxy/server.proxy-headers.test.js(lines 30–51)containers/api-proxy/server.error-handling.test.js(lines 31–51)Suggested Refactoring
Extract to
containers/api-proxy/test-helpers/server-mock-factories.js(thetest-helpers/directory already exists withmock-oidc-server.jsandtoken-tracker-setup.js):Affected Files
containers/api-proxy/server.anthropic-beta.test.js— lines 36–85containers/api-proxy/server.model-not-supported.test.js— lines 38–90containers/api-proxy/server.token-guards.test.js— lines 36–52, 115–132containers/api-proxy/server.proxy-headers.test.js— lines 30–51containers/api-proxy/server.error-handling.test.js— lines 31–51Effort Estimate
Low
Detected by Duplicate Code Detector workflow. Run date: 2026-05-27