import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import test from 'node:test'; import { getMetadataArgsStorage, type QueryRunner } from 'typeorm'; import { InspectionVisit } from '../../src/database/entities/inspection-visit.entity'; import { F4RemoveInspectionLegacyFields1790000500000 } from '../../src/database/migrations/1790000500000-f4-remove-inspection-legacy-fields'; const root = process.cwd(); const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8'); test('F4: InspectionVisit no vuelve a mapear title ni plannedEndAt', () => { const metadata = getMetadataArgsStorage(); const columns = metadata.columns .filter((column) => column.target === InspectionVisit) .map((column) => column.propertyName); const indexes = metadata.indices .filter((index) => index.target === InspectionVisit) .map((index) => index.name); assert.equal(columns.includes('title'), false); assert.equal(columns.includes('plannedEndAt'), false); assert.equal(columns.includes('plannedStartAt'), true); assert.equal(indexes.includes('idx_inspection_visits_planned_dates'), false); assert.equal(indexes.includes('idx_inspection_visits_planned_start_at'), true); }); test('F4: los consumidores backend activos no consultan el title físico de la Inspección', () => { const acts = read('src/inspection-acts/inspection-acts.service.ts'); const findings = read('src/inspection-findings/inspection-findings.service.ts'); assert.doesNotMatch(acts, /visit\.title/); assert.doesNotMatch(acts, /['"]title['"]\s*,\s*visit\.title/); assert.doesNotMatch(findings, /visit\.title/); assert.doesNotMatch(findings, /verification_target\.title/); assert.doesNotMatch(findings, /visitTitle/); }); test('F4: el contrato WEB de Inspecciones no reintroduce title, visitTitle ni plannedEndAt', () => { const webApi = read('../web-v2/src/lib/api.ts'); const start = webApi.indexOf('export type InspectionVisitStatus'); const end = webApi.indexOf('let csrfToken: string | null'); assert.notEqual(start, -1); assert.notEqual(end, -1); const inspectionContract = webApi.slice(start, end); const visitListStart = inspectionContract.indexOf('export interface InspectionVisitListItem'); const visitListEnd = inspectionContract.indexOf('export type InspectionVerificationOutcome'); assert.notEqual(visitListStart, -1); assert.notEqual(visitListEnd, -1); const visitListContract = inspectionContract.slice(visitListStart, visitListEnd); assert.doesNotMatch(visitListContract, /\btitle\s*:/); assert.doesNotMatch(visitListContract, /\bplannedEndAt\b/); assert.doesNotMatch(inspectionContract, /\bvisitTitle\b/); assert.doesNotMatch(inspectionContract, /\bplannedEndAt\b/); }); test('F4: la migración retira las columnas legacy y conserva índice de inicio', async () => { const statements: string[] = []; const queryRunner = { query: async (sql: string) => { statements.push(sql.replace(/\s+/g, ' ').trim()); return []; }, } as unknown as QueryRunner; await new F4RemoveInspectionLegacyFields1790000500000().up(queryRunner); const sql = statements.join('\n'); assert.match(sql, /DROP COLUMN IF EXISTS planned_end_at/i); assert.match(sql, /DROP COLUMN IF EXISTS title/i); assert.match(sql, /DROP CONSTRAINT IF EXISTS chk_inspection_visits_planned_dates/i); assert.match(sql, /CREATE INDEX IF NOT EXISTS idx_inspection_visits_planned_start_at/i); assert.doesNotMatch(sql, /CREATE INDEX IF NOT EXISTS idx_inspection_visits_planned_dates/i); }); test('F4: el rollback reconstruye la forma histórica de D1', async () => { const statements: string[] = []; const queryRunner = { query: async (sql: string) => { statements.push(sql.replace(/\s+/g, ' ').trim()); return []; }, } as unknown as QueryRunner; await new F4RemoveInspectionLegacyFields1790000500000().down(queryRunner); const sql = statements.join('\n'); assert.match(sql, /ADD COLUMN IF NOT EXISTS title varchar\(200\)/i); assert.match(sql, /UPDATE inspection_visits SET title = code WHERE title IS NULL/i); assert.match(sql, /ALTER COLUMN title SET NOT NULL/i); assert.match(sql, /ADD COLUMN IF NOT EXISTS planned_end_at timestamptz/i); assert.match(sql, /ADD CONSTRAINT chk_inspection_visits_planned_dates CHECK/i); assert.match(sql, /CREATE INDEX IF NOT EXISTS idx_inspection_visits_planned_dates/i); });