Assessor_2.0/tests/features/datahub-tenant-detail-refer...

126 lines
10 KiB
TypeScript

import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
const dataHub = readFileSync(new URL('../../src/features/project-import/DataHub.tsx', import.meta.url), 'utf8');
const gpoImport = readFileSync(new URL('../../src/features/project-import/GpoFolderImport.tsx', import.meta.url), 'utf8');
const styles = readFileSync(new URL('../../src/styles/datahub.css', import.meta.url), 'utf8');
describe('Mandant detail reference', () => {
it('keeps entry actions on the right and separates additions from deleting the timeslot', () => {
expect(styles).toMatch(/@container timeslot-sources[^}]+grid-template-columns:\s*var\(--space-5\) minmax\(0, 1fr\) calc\(var\(--space-8\) \* 2\.5\)/s);
expect(styles).toMatch(/\.tenant-report-row > :last-child\s*\{[^}]*grid-column: 3;[^}]*grid-row: 1 \/ span 3;/s);
const actions = dataHub.slice(dataHub.indexOf('<div className="tenant-timeslot-actions">'));
expect(actions).toContain('<h4>Add Entry</h4>');
expect(actions).not.toContain('Existing entries are kept.');
expect(actions).toMatch(/tenant-timeslot-delete-action[^]*?<span>Entire timeslot<\/span>[^]*?>Delete timeslot<\/button>/);
expect(actions.match(/<FileImport[^>]+\/>/)?.[0]).not.toContain('replacesScanRunId');
});
it('scrolls the complete timeslot list without an inner scrollbar per timeslot', () => {
expect(styles).toMatch(/\.tenant-timeslot-list\s*\{[^}]*grid-auto-rows: max-content;/s);
expect(styles).toMatch(/\.tenant-timeslot-list\s*\{[^}]*overflow-y: auto;/s);
const reportListRule = styles.match(/\.tenant-report-list\s*\{([^}]*)\}/s)?.[1] ?? '';
expect(reportListRule).not.toMatch(/max-height|overflow-y|scrollbar-/);
expect(dataHub).not.toContain('{selected && <div className="tenant-timeslot-actions">');
expect(dataHub).toContain('<div className="tenant-timeslot-actions">');
});
it('uses the selected Work/Reports master-detail structure', () => {
expect(dataHub).toContain('className="tenant-detail-layout"');
expect(dataHub).toContain('<aside className="tenant-detail-navigation">');
expect(dataHub).toContain('<main className="tenant-detail-information">');
expect(dataHub).toContain('className="tenant-information-sheet"');
expect(dataHub).toContain('<strong>Client Information</strong>');
expect(dataHub).toContain('className="tenant-timeslot-list"');
expect(dataHub).toContain('className="tenant-report-list"');
expect(dataHub).toContain('className="tenant-report-row"');
expect(styles).toMatch(/\.tenant-detail-page > \.tenant-detail-layout\s*\{[^}]*grid-template-columns:\s*clamp\(420px, 27vw, 520px\) minmax\(0, 1fr\);/s);
expect(styles).toMatch(/\.tenant-information-sheet\s*\{[^}]*width:\s*min\(794px, 100%\);[^}]*background:\s*transparent;/s);
expect(styles).toMatch(/\.tenant-timeslot-list\s*\{[^}]*overflow-y:\s*auto;/s);
expect(styles).toMatch(/\.tenant-timeslot-list\s*\{[^}]*display:\s*grid;[^}]*gap:\s*var\(--space-3\);[^}]*overflow-y:\s*auto;/s);
expect(styles).toMatch(/\.tenant-timeslot-list\s*\{[^}]*padding:\s*var\(--space-2\) var\(--space-2\) var\(--space-5\);[^}]*overflow-y:\s*auto;/s);
const reportListRule = styles.match(/\.tenant-report-list\s*\{([^}]*)\}/s)?.[1] ?? '';
expect(reportListRule).not.toMatch(/max-height|overflow-y|scrollbar-/);
expect(styles).toMatch(/\.tenant-scan-history\s*\{[^}]*border:\s*var\(--bw-hairline\) solid var\(--border-default\);[^}]*background:\s*var\(--surface-panel-raised\);/s);
expect(styles).toMatch(/\.tenant-detail-information\s*\{[^}]*overflow-y:\s*auto;/s);
expect(styles).toMatch(/\.tenant-timeslot\.is-selected\s*\{[^}]*var\(--marker-width\)[^}]*var\(--state-active\)/s);
});
it('preserves all existing client and timeslot actions without placeholder data', () => {
expect(dataHub).toContain('className="btn primary tenant-navigation-open"');
expect(dataHub).toContain('aria-label="Back to client overview"');
expect(dataHub).toContain('className="btn danger tenant-delete-client"');
expect(dataHub).toContain('>Delete client</button>');
expect(dataHub).not.toContain('M4 7h16M9 7V4h6v3');
expect(styles).toMatch(/\.tenant-delete-client\s*\{[^}]*min-width:/s);
expect(dataHub).not.toContain('tenant-information-footer');
expect(dataHub).not.toContain('tenant-master-data-edit');
expect(dataHub).toMatch(/tenant-information-actions[^\n]*tenant-delete-client[^\n]*>Delete client<\/button>[^\n]*tenant-edit-client[^\n]*>Edit<\/button>/);
expect(dataHub).toContain('form.project && !masterDataEditing && <button className="btn danger tenant-delete-client"');
expect(dataHub).toContain('className="btn primary tenant-save-client"');
expect(styles).toMatch(/\.tenant-edit-client,\s*\.tenant-save-client\s*\{[^}]*min-width:\s*calc\(var\(--space-8\) \* 3\);/s);
expect(styles).toMatch(/\.tenant-delete-client\s*\{[^}]*min-width:\s*calc\(var\(--space-8\) \* 3\);/s);
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-header\s*\{[^}]*display:\s*grid;[^}]*grid-template-columns:\s*minmax\(0, 1fr\) auto;/s);
expect(styles).toMatch(/\.tenant-detail-page \.tenant-navigation-open\s*\{[^}]*grid-column:\s*2;[^}]*justify-self:\s*end;/s);
expect(dataHub).toContain('>Delete timeslot</button>');
expect(dataHub).toContain('label="Import Scan"');
expect(dataHub).toContain('label="Import GPO Folder"');
expect(dataHub).toContain('archiveLabel="Import GPO ZIP"');
expect(dataHub).toContain('targetAssessmentId={group.assessmentIds[0]}');
expect(dataHub).toContain('targetAssessmentId={report.assessmentIds[0]}');
expect(dataHub).toContain('assessmentId={group.assessmentIds[0]}');
expect(dataHub).toContain('showStatus={false}');
expect(gpoImport).toContain('<button className="btn primary"');
expect(gpoImport).toContain('accept=".zip,application/zip"');
expect(dataHub).toContain('<span>Status</span><span>Actions</span>');
expect(dataHub).toContain("processing.state === 'update' ? 'reimport-recommended' : processing.state === 'review' ? 'review-required' : processing.state === 'error' ? 'processing-error' : readiness");
expect(dataHub).toContain('disabled={!viewable}');
expect(dataHub).toContain('>Delete</button>');
expect(dataHub).toContain('aria-label="Create timeslot"');
expect(dataHub).toContain('title="Create Timeslot"');
expect(dataHub).toContain("form.mode === 'create' || masterDataEditing");
expect(dataHub).not.toContain('Scan report 01');
expect(dataHub).not.toContain('23.07.2026');
expect(dataHub).not.toContain('24.07.2026');
expect(dataHub).toContain("type TenantDetailSection = 'client-information' | 'gpo-analysis'");
expect(dataHub).toContain('<PolicyAnalysisPanel projectId={form.project.id}/>');
expect(gpoImport).toContain('showStatus = true');
});
it('keeps read-first client editing and selectable scan reports', () => {
expect(dataHub).toContain('className="btn primary tenant-edit-client"');
expect(dataHub).toContain("form.mode === 'edit' && !masterDataEditing");
expect(dataHub).toContain('setMasterDataEditing(true)');
expect(dataHub).toContain('setMasterDataEditing(false)');
expect(dataHub).toContain("tenant-editor-form${masterDataEditing ? ' is-editing' : ''}");
expect(dataHub).toContain('className="tenant-field-value"');
expect(dataHub).toContain('className="tenant-field-value tenant-field-prose"');
expect(dataHub).toContain('<span className="tenant-field-label">Name');
expect(dataHub).not.toContain('tenant-identity-name-input');
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-form \.tenant-field-value\s*\{[^}]*justify-self:\s*start;[^}]*font-size:\s*var\(--type-body-size\);[^}]*text-align:\s*left;/s);
expect(dataHub).toContain('const [excludedScanRunIds, setExcludedScanRunIds]');
expect(dataHub).toMatch(/const openEdit = \(project: AssessmentProject\) => \{[\s\S]*?setSelectedTimeslotIds\(latestTimeslot \? \[latestTimeslot\.id\] : \[\]\);[\s\S]*?setExpandedTimeslotIds\(affectedTimeslotIds\);/);
expect(dataHub).toContain('const toggleScanReport =');
expect(dataHub).toContain('<span className="tenant-timeslot-title">');
expect(dataHub).toMatch(/type="checkbox"[^>]*onClick=\{event => event\.stopPropagation\(\)\}[^>]*onChange=\{event => toggleTimeslot/);
expect(dataHub).not.toContain('<label className="tenant-timeslot-title"');
expect(dataHub).not.toMatch(/const toggleTimeslot[\s\S]*?setExpandedTimeslotIds[\s\S]*?const toggleScanReport/);
expect(styles).toMatch(/\.tenant-timeslot-title\s*\{[^}]*flex:\s*0 0 calc\(var\(--space-8\) \* 4\.25\);/s);
expect(styles).toMatch(/\.tenant-timeslot > \.tenant-section-bar > \.tenant-history-meta\s*\{[^}]*flex:\s*1 1 auto;[^}]*cursor:\s*pointer;/s);
expect(dataHub).toContain('aria-label={`Select ${report.tool.name} scan report`}');
expect(dataHub).toContain('selectedTimeslots[0].scanRunIds.filter');
expect(dataHub).toContain('runIds: group.scanRunIds.filter');
expect(dataHub).toContain('isDatahubScanViewable(scanReadiness[runId])');
expect(dataHub).toContain('onClick={openSelectedTimeslots}>Open</button>');
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-form\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\);/s);
expect(styles).toMatch(/accent-color:\s*var\(--state-active\);/s);
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-form label\s*\{[^}]*display:\s*block;[^}]*border-bottom:/s);
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-form \.tenant-field-label\s*\{[^}]*background:\s*transparent;[^}]*font-size:\s*var\(--type-label-size\);[^}]*text-transform:\s*none;/s);
expect(styles).toMatch(/\.tenant-report-copy b\s*\{[^}]*font-size:\s*var\(--fs-lg\);/s);
expect(styles).toMatch(/\.tenant-report-copy small\s*\{[^}]*font-size:\s*var\(--type-meta-size\);/s);
expect(styles).toMatch(/\.tenant-report-row\s*\{[^}]*grid-template-columns:[^;}]*calc\(var\(--space-8\) \* 4\.25\)/s);
expect(dataHub).toContain('rows={10} placeholder="Notes about the client or project"');
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-form textarea\.input\s*\{[^}]*width:\s*100%;/s);
expect(styles).toMatch(/\.tenant-detail-page \.tenant-editor-form\.is-editing textarea\.input\s*\{[^}]*min-height:\s*calc\(var\(--space-8\) \* 8\);/s);
});
});