78 lines
5.1 KiB
TypeScript
78 lines
5.1 KiB
TypeScript
import { createElement } from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import { expect, it } from 'vitest';
|
|
import type { GpoBackupStatusRecord } from '../../src/api/assessor-api-contract';
|
|
import { GpoStatusRow } from '../../src/features/project-import/GpoStatusRow';
|
|
import { summarizeClientProcessingReadiness } from '../../src/features/project-import/datahub-processing-readiness';
|
|
|
|
const record: GpoBackupStatusRecord = {
|
|
version: 1, artifactId: 'synthetic-artifact', fileName: 'Synthetic.zip', sizeBytes: 12, submittedAt: '', updatedAt: '',
|
|
state: 'succeeded', attempts: 1, maxAttempts: 3, gpoCount: 1, backupInstanceCount: 1,
|
|
evaluationUpdates: [{ evaluationRunId: 'old', aggregationRunId: 'aggregation', baselineAnalysisIds: ['baseline'],
|
|
artifactIds: ['synthetic-artifact'], previousVersion: '1.3.3', currentVersion: '1.4.0',
|
|
reasons: ['engine-version'] }]
|
|
};
|
|
it('makes the client actionable and renders an explicit evaluation action, not an upload request', () => {
|
|
expect(summarizeClientProcessingReadiness([], [], [record])).toMatchObject({ state: 'update' });
|
|
const html = renderToStaticMarkup(createElement(GpoStatusRow, { projectId: 'synthetic-project', record, imported: 'Synthetic date', busy: false,
|
|
onEvaluate() {}, onReprocess() {}, onRetry() {}, onDelete() {} }));
|
|
expect(html).toContain('Re-evaluation required');
|
|
expect(html).toContain('>Re-evaluate</button>');
|
|
expect(html).not.toContain('>Ready<');
|
|
expect(html).toContain('no file upload is required');
|
|
expect(summarizeClientProcessingReadiness([], [], [{ ...record, evaluationUpdates: [] }])).toMatchObject({ state: 'ready' });
|
|
expect(summarizeClientProcessingReadiness([], [], [{ ...record, state: 'dead-letter' }])).toMatchObject({ state: 'error' });
|
|
});
|
|
|
|
it('shows partial GPO processing as a technical analysis limit without requesting manual review', () => {
|
|
const html = renderToStaticMarkup(createElement(GpoStatusRow, { projectId: 'synthetic-project',
|
|
record: { ...record, state: 'partial', evaluationUpdates: [] },
|
|
imported: 'Synthetic date', busy: false, onEvaluate() {}, onReprocess() {}, onRetry() {}, onDelete() {}
|
|
}));
|
|
expect(html).toContain('Limited analysis');
|
|
expect(html).not.toContain('review required');
|
|
expect(html).not.toContain('>Imported<');
|
|
});
|
|
|
|
it('offers the same re-evaluation when only the baseline analysis generation changed', () => {
|
|
const current: GpoBackupStatusRecord = { ...record, evaluationUpdates: [{
|
|
...record.evaluationUpdates![0], previousVersion: '1.4.0', currentVersion: '1.4.0',
|
|
baselineAnalysisIds: ['baseline-current'], reasons: ['baseline-analysis']
|
|
}] };
|
|
expect(summarizeClientProcessingReadiness([], [], [current])).toMatchObject({ state: 'update' });
|
|
const html = renderToStaticMarkup(createElement(GpoStatusRow, { projectId: 'synthetic-project', record: current, imported: 'Synthetic date',
|
|
busy: false, onEvaluate() {}, onReprocess() {}, onRetry() {}, onDelete() {} }));
|
|
expect(html).toContain('Re-evaluation required');
|
|
expect(html).toContain('Updated Microsoft baseline analysis');
|
|
expect(html).not.toContain('Engine 1.4.0');
|
|
expect(html).toContain('>Re-evaluate</button>');
|
|
});
|
|
|
|
it('asks for reprocessing, not re-evaluation, when the retained analysis uses an older analyzer', () => {
|
|
const outdated: GpoBackupStatusRecord = { ...record, evaluationUpdates: [], analysisUpdate: {
|
|
identityAnalysisRunId: 'analysis-1', expectedLatestProcessingRunId: 'processing-1',
|
|
previousAnalyzerVersion: 'gpo-backup-policy-analysis:2.2.3',
|
|
currentAnalyzerVersion: 'gpo-backup-policy-analysis:2.2.4'
|
|
} };
|
|
expect(summarizeClientProcessingReadiness([], [], [outdated])).toMatchObject({ state: 'update' });
|
|
const html = renderToStaticMarkup(createElement(GpoStatusRow, { projectId: 'synthetic-project', record: outdated, imported: 'Synthetic date',
|
|
busy: false, onEvaluate() {}, onReprocess() {}, onRetry() {}, onDelete() {} }));
|
|
expect(html).toContain('Reprocessing required');
|
|
expect(html).toContain('Analyzer gpo-backup-policy-analysis:2.2.3 → gpo-backup-policy-analysis:2.2.4');
|
|
// Reprocessing rebuilds retained parsing output, so it replaces the re-evaluation action.
|
|
expect(html).toContain('>Reprocess</button>');
|
|
expect(html).not.toContain('>Re-evaluate</button>');
|
|
expect(html).toContain('no file upload is required');
|
|
});
|
|
|
|
it('shows the number of GPOs without a link once link facts are retained', () => {
|
|
const withLinks: GpoBackupStatusRecord = { ...record, evaluationUpdates: [], gpoCount: 184, backupInstanceCount: 184, notLinkedGpoCount: 29 };
|
|
const html = renderToStaticMarkup(createElement(GpoStatusRow, { projectId: 'synthetic-project', record: withLinks, imported: 'Synthetic date',
|
|
busy: false, onEvaluate() {}, onReprocess() {}, onRetry() {}, onDelete() {} }));
|
|
expect(html).toContain('184 GPOs');
|
|
expect(html).toContain(' · 29 not linked');
|
|
const unknown = renderToStaticMarkup(createElement(GpoStatusRow, { projectId: 'synthetic-project', record: { ...withLinks, notLinkedGpoCount: undefined },
|
|
imported: 'Synthetic date', busy: false, onEvaluate() {}, onReprocess() {}, onRetry() {}, onDelete() {} }));
|
|
expect(unknown).not.toContain('not linked');
|
|
});
|