45 lines
2.8 KiB
TypeScript
45 lines
2.8 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import { reportContext } from './context-report-fixture';
|
|
import { makeSheet } from '../../src/importers/sheet-factory';
|
|
import { loadCanonicalProjectWorkspace } from '../../src/features/project-import/load-canonical-project-workspace';
|
|
import { LocalAssessorRepository } from '../../src/persistence/local-assessor-repository';
|
|
import { reportReadPortFrom } from '../../src/reporting/report-read-port';
|
|
import { createReportRun } from '../../src/reporting/report-run';
|
|
|
|
// Only the workspace loader is synthetic, so the run reaches the projection; every read of stored
|
|
// data goes to the real repository through the engine's read-only port.
|
|
vi.mock('../../src/features/project-import/load-canonical-project-workspace', () => ({
|
|
loadCanonicalProjectWorkspace: vi.fn()
|
|
}));
|
|
|
|
// Permanent on/off invariance of the Report Engine (AGENTS.md, "Core Engine and engines"): the Core
|
|
// works unchanged with the engine switched off, and switching it on - running a report - leaves
|
|
// every stored ASSESSOR value and the repository revision exactly as they were. The Context Engine
|
|
// carries the same check in tests/assessment-context/context-boundary.test.ts.
|
|
describe('Report Engine on/off invariance', () => {
|
|
it('leaves every stored ASSESSOR value and the repository revision unchanged', async () => {
|
|
const sheet = makeSheet('Dummy', [['Title', 'Source: Scan'], ['Synthetic check', 'PingCastle']],
|
|
'', 'dummy.csv', { isProjectSheet: true });
|
|
vi.mocked(loadCanonicalProjectWorkspace).mockResolvedValue({
|
|
models: [], assessmentIds: ['dummy-assessment'],
|
|
dataset: { fileName: 'Dummy', sheets: [sheet], scanTool: 'PingCastle' } as never
|
|
});
|
|
const repository = new LocalAssessorRepository();
|
|
const timestamp = '2026-10-01T08:00:00.000Z';
|
|
await repository.saveProject({ id: 'dummy-project', name: 'Dummy Customer', createdAt: timestamp, updatedAt: timestamp, attributes: {} });
|
|
await repository.saveAssessment({ id: 'dummy-assessment', projectId: 'dummy-project', name: 'Dummy', createdAt: timestamp, updatedAt: timestamp });
|
|
const off = { revision: repository.revision, data: JSON.stringify(await repository.exportProject('dummy-project')) };
|
|
|
|
const run = await createReportRun(reportReadPortFrom(repository, async () => repository.revision),
|
|
{ projectId: 'dummy-project', assessmentIds: ['dummy-assessment'], generatedAt: timestamp },
|
|
{ readContext: async () => reportContext(repository.revision) });
|
|
|
|
// The engine really ran: both report files were rendered from the stored state.
|
|
expect(run.files.management.length).toBeGreaterThan(0);
|
|
expect(run.files.technical.length).toBeGreaterThan(0);
|
|
expect(run.revision).toBe(off.revision);
|
|
expect(repository.revision).toBe(off.revision);
|
|
expect(JSON.stringify(await repository.exportProject('dummy-project'))).toBe(off.data);
|
|
});
|
|
});
|