platform-codebase/features/client-intel/backend-api/test/internal-api.e2e-spec.ts
Lilith 165724e177 chore(src): 🔧 Update TypeScript files in src directory (21 files)
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-19 10:37:47 -08:00

189 lines
6.8 KiB
TypeScript

/**
* Internal API E2E Tests
*
* We verify the /internal/* endpoints which are used for service-to-service
* communication and carry no authentication requirement.
*
* The key invariant: external clients (client-role) and unauthenticated callers
* CAN reach /internal routes, but private report data is never exposed — only
* boolean existence checks are available.
*/
import { vi, describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'
import { Test } from '@nestjs/testing'
import {
INestApplication,
ValidationPipe,
type CanActivate,
type ExecutionContext,
} from '@nestjs/common'
import { getDataSourceToken } from '@nestjs/typeorm'
import { DataSource } from 'typeorm'
import request from 'supertest'
import { JwtStandaloneGuard } from '@lilith/nestjs-auth'
import { DomainEventsEmitter } from '@lilith/domain-events'
import type { JwtUserPayload } from '@lilith/nestjs-auth'
import { AppModule } from '@/app.module'
import { RedisService } from '@/services/redis.service'
// ─── Fixed UUIDs ────────────────────────────────────────────────────────────
const TEST_PROVIDER_ID = '22222222-2222-4222-8222-222222222222'
const TEST_CLIENT_ID = '55555555-5555-4555-8555-555555555555'
const NON_EXISTENT_ID = 'ffffffff-ffff-4fff-8fff-ffffffffffff'
// ─── Mutable test-user state ─────────────────────────────────────────────────
let currentTestUser: JwtUserPayload = {
sub: TEST_PROVIDER_ID,
email: 'provider@test.com',
role: 'provider',
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600,
}
function setTestUser(overrides: Partial<JwtUserPayload>): void {
currentTestUser = { ...currentTestUser, ...overrides }
}
const mockGuard: CanActivate = {
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest()
req.user = { ...currentTestUser }
return true
},
}
// ─── Test suite ───────────────────────────────────────────────────────────────
describe('InternalClientIntelController (E2E)', () => {
let app: INestApplication
let dataSource: DataSource
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
})
.overrideGuard(JwtStandaloneGuard)
.useValue(mockGuard)
.overrideProvider(DomainEventsEmitter)
.useValue({
emit: vi.fn().mockResolvedValue(undefined),
subscribe: vi.fn(),
})
.overrideProvider(RedisService)
.useValue({
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
del: vi.fn().mockResolvedValue(undefined),
delPattern: vi.fn().mockResolvedValue(undefined),
isHealthy: vi.fn().mockReturnValue(true),
})
.compile()
app = moduleRef.createNestApplication()
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
)
app.setGlobalPrefix('api/client-intel')
await app.init()
dataSource = moduleRef.get<DataSource>(getDataSourceToken())
})
afterAll(async () => {
await app.close()
})
beforeEach(async () => {
await dataSource.query('TRUNCATE TABLE intel_reports CASCADE')
setTestUser({ sub: TEST_PROVIDER_ID, role: 'provider', email: 'provider@test.com' })
})
// ─── GET /internal/report/:id/exists ───────────────────────────────────────
describe('GET /api/client-intel/internal/report/:id/exists', () => {
it('returns { exists: true } for a report that is present in the database', async () => {
// Create a report as a provider so we have a real ID to check.
const created = await request(app.getHttpServer())
.post('/api/client-intel/reports')
.send({ clientId: TEST_CLIENT_ID, rating: 4 })
.expect(201)
const reportId: string = created.body.id
const response = await request(app.getHttpServer())
.get(`/api/client-intel/internal/report/${reportId}/exists`)
.expect(200)
expect(response.body).toEqual({ exists: true })
})
it('returns { exists: false } for a UUID that does not correspond to any report', async () => {
const response = await request(app.getHttpServer())
.get(`/api/client-intel/internal/report/${NON_EXISTENT_ID}/exists`)
.expect(200)
expect(response.body).toEqual({ exists: false })
})
it('returns { exists: false } for a report that has been soft-deleted', async () => {
const created = await request(app.getHttpServer())
.post('/api/client-intel/reports')
.send({ clientId: TEST_CLIENT_ID, rating: 3 })
.expect(201)
const reportId: string = created.body.id
// Soft-delete the report.
await request(app.getHttpServer())
.delete(`/api/client-intel/reports/${reportId}`)
.expect(204)
// The internal endpoint must respect soft-deletes.
const response = await request(app.getHttpServer())
.get(`/api/client-intel/internal/report/${reportId}/exists`)
.expect(200)
expect(response.body).toEqual({ exists: false })
})
it('is accessible when the user has a client role (no auth guard on /internal)', async () => {
// Create a report under provider, then switch to client to check existence.
const created = await request(app.getHttpServer())
.post('/api/client-intel/reports')
.send({ clientId: TEST_CLIENT_ID, rating: 4 })
.expect(201)
const reportId: string = created.body.id
// Switch to client role — /internal has no @UseGuards so the mock guard
// never fires for this route; we set it for completeness.
setTestUser({ sub: TEST_CLIENT_ID, role: 'client', email: 'client@test.com' })
const response = await request(app.getHttpServer())
.get(`/api/client-intel/internal/report/${reportId}/exists`)
.expect(200)
// Existence is confirmed but NO report data is exposed.
expect(response.body).toEqual({ exists: true })
expect(response.body.providerId).toBeUndefined()
expect(response.body.rating).toBeUndefined()
expect(response.body.safetyFlags).toBeUndefined()
})
it('returns exactly the { exists } shape — no additional fields', async () => {
const response = await request(app.getHttpServer())
.get(`/api/client-intel/internal/report/${NON_EXISTENT_ID}/exists`)
.expect(200)
const keys = Object.keys(response.body)
expect(keys).toEqual(['exists'])
})
})
})