fix(tests): resolve 4 failing test suites and patch lodash vulnerability

Test fixes (type mismatches introduced by V&V resolution changes):
- HealthDetailedController.test.ts: replace pool/makePool with dbProbe/makeDbProbe
  to match refactored HealthDetailedDeps interface (Pool → DbProbe abstraction)
- EventPublisher.test.ts: pass all 4 required constructor args to WebhookDeliveryWorker
  mock (pool, vaultClient, redisClient, redisUrl) — was passing only 1
- MarketplaceService.test.ts: IAgent.did/didCreatedAt are string|undefined (not null);
  fix makeAgent defaults and makeAgent({did:null}) call; fix type assertion to unknown first
- OIDCTrustPolicyService.test.ts: ICreateTrustPolicyRequest.branch is string|undefined
  (not nullable); replace all branch:null with branch:undefined

Security fix:
- npm audit fix: lodash ≤4.17.23 (HIGH) → patched; 0 vulnerabilities remaining

Result: 50/50 test suites pass, 722/722 tests pass, 0 vulnerabilities

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SentryAgent.ai Developer
2026-04-08 08:40:23 +00:00
parent f9a6a8aafb
commit 5e580b51dd
5 changed files with 44 additions and 43 deletions

View File

@@ -11,8 +11,7 @@
import express, { Application } from 'express';
import request from 'supertest';
import { Pool, PoolClient } from 'pg';
import { HealthDetailedController, HealthDetailedDeps } from '../../../src/controllers/HealthDetailedController';
import { HealthDetailedController, HealthDetailedDeps, DbProbe } from '../../../src/controllers/HealthDetailedController';
// ── fetch mock ────────────────────────────────────────────────────────────────
@@ -22,23 +21,19 @@ global.fetch = mockFetch;
// ── Helpers ────────────────────────────────────────────────────────────────────
function makePoolClient(latencyMs = 0, error?: Error): jest.Mocked<Pick<PoolClient, 'query' | 'release'>> {
/**
* Creates a mock DbProbe. When `error` is provided, checkLiveness() rejects
* with that error (simulates unreachable DB). Otherwise it resolves after
* `latencyMs` ms (0 by default — Date.now mocking handles degraded scenarios).
*/
function makeDbProbe(error?: Error, latencyMs = 0): DbProbe {
return {
query: error
checkLiveness: error
? jest.fn().mockRejectedValue(error)
: jest.fn().mockImplementation(() =>
new Promise((resolve) => setTimeout(() => resolve({ rows: [], rowCount: 0 }), latencyMs)),
: jest.fn().mockImplementation(
() => new Promise<void>((resolve) => setTimeout(() => resolve(), latencyMs)),
),
release: jest.fn(),
} as unknown as jest.Mocked<Pick<PoolClient, 'query' | 'release'>>;
}
function makePool(connectError?: Error, queryLatencyMs = 0, queryError?: Error): jest.Mocked<Pool> {
return {
connect: connectError
? jest.fn().mockRejectedValue(connectError)
: jest.fn().mockResolvedValue(makePoolClient(queryLatencyMs, queryError)),
} as unknown as jest.Mocked<Pool>;
};
}
function makeRedisClient(pingError?: Error, latencyMs = 0): { ping(): Promise<string> } {
@@ -67,7 +62,7 @@ beforeEach(() => {
describe('GET /health/detailed — all services healthy', () => {
it('returns 200 with overall status "healthy" when postgres and redis respond quickly', async () => {
const app = buildApp({
pool: makePool(undefined, 10),
dbProbe: makeDbProbe(undefined, 10),
redisClient: makeRedisClient(undefined, 5),
});
@@ -81,7 +76,7 @@ describe('GET /health/detailed — all services healthy', () => {
it('includes version and uptime in the response body', async () => {
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
});
@@ -93,7 +88,7 @@ describe('GET /health/detailed — all services healthy', () => {
it('includes latencyMs for each service', async () => {
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
});
@@ -146,7 +141,7 @@ describe('GET /health/detailed — degraded scenario', () => {
try {
const app = buildApp({
pool: makePool(undefined, 0),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(undefined, 0),
});
@@ -177,7 +172,7 @@ describe('GET /health/detailed — degraded scenario', () => {
try {
const app = buildApp({
pool: makePool(undefined, 0),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(undefined, 0),
});
@@ -195,7 +190,7 @@ describe('GET /health/detailed — degraded scenario', () => {
describe('GET /health/detailed — unreachable scenarios', () => {
it('returns 503 when postgres connect() throws', async () => {
const app = buildApp({
pool: makePool(new Error('ECONNREFUSED')),
dbProbe: makeDbProbe(new Error('ECONNREFUSED')),
redisClient: makeRedisClient(),
});
@@ -208,7 +203,7 @@ describe('GET /health/detailed — unreachable scenarios', () => {
it('returns 503 when redis ping() throws', async () => {
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(new Error('Redis ECONNREFUSED')),
});
@@ -221,7 +216,7 @@ describe('GET /health/detailed — unreachable scenarios', () => {
it('returns 503 when both postgres and redis are unreachable', async () => {
const app = buildApp({
pool: makePool(new Error('PG down')),
dbProbe: makeDbProbe(new Error('PG down')),
redisClient: makeRedisClient(new Error('Redis down')),
});
@@ -237,7 +232,7 @@ describe('GET /health/detailed — unreachable scenarios', () => {
describe('GET /health/detailed — optional services omitted when not configured', () => {
it('does not include vault in services when vaultAddr is not provided', async () => {
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
});
@@ -248,7 +243,7 @@ describe('GET /health/detailed — optional services omitted when not configured
it('does not include opa in services when opaUrl is not provided', async () => {
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
});
@@ -263,7 +258,7 @@ describe('GET /health/detailed — Vault and OPA probes', () => {
mockFetch.mockResolvedValue(new Response(null, { status: 200 }));
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
vaultAddr: 'http://vault:8200',
});
@@ -278,7 +273,7 @@ describe('GET /health/detailed — Vault and OPA probes', () => {
mockFetch.mockRejectedValue(new Error('Network failure'));
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
vaultAddr: 'http://vault:8200',
});
@@ -292,7 +287,7 @@ describe('GET /health/detailed — Vault and OPA probes', () => {
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
opaUrl: 'http://opa:8181',
});
@@ -307,7 +302,7 @@ describe('GET /health/detailed — Vault and OPA probes', () => {
mockFetch.mockResolvedValue(new Response(null, { status: 503 }));
const app = buildApp({
pool: makePool(),
dbProbe: makeDbProbe(),
redisClient: makeRedisClient(),
opaUrl: 'http://opa:8181',
});