Files
klz-cables.com/tests/pdf-datasheet.test.ts
2026-01-14 17:16:09 +01:00

178 lines
6.0 KiB
TypeScript

/**
* PDF Datasheet Generator Test Suite
* Validates that datasheets are generated correctly with all expected values
*/
import { describe, it, expect } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
import { execSync } from 'child_process';
// Test configuration
const TEST_CONFIG = {
productsFile: path.join(process.cwd(), 'data/processed/products.json'),
excelFiles: [
path.join(process.cwd(), 'data/source/high-voltage.xlsx'),
path.join(process.cwd(), 'data/source/medium-voltage-KM.xlsx'),
path.join(process.cwd(), 'data/source/low-voltage-KM.xlsx'),
path.join(process.cwd(), 'data/source/solar-cables.xlsx'),
],
outputDir: path.join(process.cwd(), 'public/datasheets'),
};
// Expected table headers (13 columns as specified)
const EXPECTED_HEADERS = ['DI', 'RI', 'Wi', 'Ibl', 'Ibe', 'Ik', 'Wm', 'Rbv', 'Ø', 'Fzv', 'Al', 'Cu', 'G'];
// Helper functions (copied from generate-pdf-datasheets.ts for testing)
function normalizeExcelKey(value) {
return String(value || '')
.toUpperCase()
.replace(/-\d+$/g, '')
.replace(/[^A-Z0-9]+/g, '');
}
function normalizeValue(value) {
if (!value) return '';
return String(value)
.replace(/<[^>]*>/g, '')
.replace(/\s+/g, ' ')
.trim();
}
function loadExcelRows(filePath) {
const out = execSync(`npx -y xlsx-cli -j "${filePath}"`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
const trimmed = out.trim();
const jsonStart = trimmed.indexOf('[');
if (jsonStart < 0) return [];
const jsonText = trimmed.slice(jsonStart);
try {
return JSON.parse(jsonText);
} catch {
return [];
}
}
function getExcelIndex() {
const idx = new Map();
for (const file of TEST_CONFIG.excelFiles) {
if (!fs.existsSync(file)) continue;
const rows = loadExcelRows(file);
const unitsRow = rows.find(r => r && r['Part Number'] === 'Units') || null;
const units = {};
if (unitsRow) {
for (const [k, v] of Object.entries(unitsRow)) {
if (k === 'Part Number') continue;
const unit = normalizeValue(String(v ?? ''));
if (unit) units[k] = unit;
}
}
for (const r of rows) {
const pn = r?.['Part Number'];
if (!pn || pn === 'Units') continue;
const key = normalizeExcelKey(String(pn));
if (!key) continue;
const cur = idx.get(key);
if (!cur) {
idx.set(key, { rows: [r], units });
} else {
cur.rows.push(r);
if (Object.keys(cur.units).length < Object.keys(units).length) cur.units = units;
}
}
}
return idx;
}
function findExcelForProduct(product) {
const idx = getExcelIndex();
const candidates = [
product.name,
product.slug ? product.slug.replace(/-\d+$/g, '') : '',
product.sku,
product.translationKey,
].filter(Boolean);
for (const c of candidates) {
const key = normalizeExcelKey(c);
const match = idx.get(key);
if (match && match.rows.length) return match;
}
return null;
}
describe('PDF Datasheet Generator (smoke)', () => {
it('excel source files exist', () => {
const missing = TEST_CONFIG.excelFiles.filter(f => !fs.existsSync(f));
expect(missing, `Missing Excel files: ${missing.join(', ')}`).toHaveLength(0);
});
it('products.json exists', () => {
expect(fs.existsSync(TEST_CONFIG.productsFile)).toBe(true);
});
it('pdf output directory exists', () => {
expect(fs.existsSync(TEST_CONFIG.outputDir)).toBe(true);
});
it(
'excel data is loadable',
() => {
const idx = getExcelIndex();
expect(idx.size).toBeGreaterThan(0);
},
30_000,
);
it(
'product NA2XS(FL)2Y has excel data',
() => {
const products = JSON.parse(fs.readFileSync(TEST_CONFIG.productsFile, 'utf8'));
const product = products.find(p => p.id === 46773);
expect(product).toBeTruthy();
const match = findExcelForProduct(product);
expect(match).toBeTruthy();
expect(match?.rows?.length || 0).toBeGreaterThan(0);
},
30_000,
);
it(
'excel contains required column families',
() => {
const products = JSON.parse(fs.readFileSync(TEST_CONFIG.productsFile, 'utf8'));
const product = products.find(p => p.id === 46773);
const match = findExcelForProduct(product);
expect(match).toBeTruthy();
if (!match) return;
const sampleRow = match.rows[0];
const excelKeys = Object.keys(sampleRow).map(k => k.toLowerCase());
const hasDI = excelKeys.some(k => k.includes('diameter over insulation') || k.includes('insulation diameter'));
const hasRI = excelKeys.some(k => k.includes('dc resistance') || k.includes('resistance conductor') || k.includes('leiterwiderstand'));
const hasWi = excelKeys.some(k => k.includes('nominal insulation thickness') || k.includes('insulation thickness'));
const hasIbl = excelKeys.some(k => k.includes('current ratings in air') || k.includes('strombelastbarkeit luft'));
const hasIbe = excelKeys.some(k => k.includes('current ratings in ground') || k.includes('strombelastbarkeit erdreich'));
const hasIk = excelKeys.some(k => k.includes('shortcircuit current') || k.includes('kurzschlussstrom'));
const hasWm = excelKeys.some(k => k.includes('sheath thickness') || k.includes('manteldicke'));
const hasRbv = excelKeys.some(k => k.includes('bending radius') || k.includes('biegeradius'));
const hasOD = excelKeys.some(k => k.includes('outer diameter') || k.includes('außen') || k.includes('durchmesser'));
const hasG = excelKeys.some(k => k.includes('weight') || k.includes('gewicht'));
const foundCount = [hasDI, hasRI, hasWi, hasIbl, hasIbe, hasIk, hasWm, hasRbv, hasOD, hasG].filter(Boolean).length;
expect(foundCount).toBeGreaterThanOrEqual(5);
},
30_000,
);
it('pdf naming convention is correct', () => {
const pdfFiles = fs.readdirSync(TEST_CONFIG.outputDir).filter(f => f.endsWith('.pdf'));
const namingPattern = /^[a-z0-9-]+-(en|de)\.pdf$/;
expect(pdfFiles.length).toBeGreaterThan(0);
expect(pdfFiles.every(f => namingPattern.test(f))).toBe(true);
});
});