clean
This commit is contained in:
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* Excel Integration Tests
|
||||
* Verifies that Excel data is correctly parsed and integrated into products
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { getExcelTechnicalDataForProduct, getExcelRowsForProduct } from '../lib/excel-products';
|
||||
import { enrichProductWithExcelData, getAllProducts } from '../lib/data';
|
||||
|
||||
describe('Excel Integration', () => {
|
||||
it('should parse Excel files and return technical data', () => {
|
||||
const testProduct = {
|
||||
name: 'NA2XS(FL)2Y',
|
||||
slug: 'na2xsfl2y-3',
|
||||
sku: 'NA2XS(FL)2Y-high-voltage-cables',
|
||||
translationKey: 'na2xsfl2y-3'
|
||||
};
|
||||
|
||||
const excelData = getExcelTechnicalDataForProduct(testProduct);
|
||||
|
||||
expect(excelData).toBeTruthy();
|
||||
// Avoid non-null assertions here because ESLint may parse this file without TS syntax support.
|
||||
if (!excelData) throw new Error('Expected excelData to be defined');
|
||||
expect(excelData.configurations).toBeInstanceOf(Array);
|
||||
expect(excelData.configurations.length).toBeGreaterThan(0);
|
||||
expect(excelData.attributes).toBeInstanceOf(Array);
|
||||
});
|
||||
|
||||
it('should return correct structure for Excel data', () => {
|
||||
const testProduct = {
|
||||
name: 'NA2XS(FL)2Y',
|
||||
slug: 'na2xsfl2y-3',
|
||||
sku: 'NA2XS(FL)2Y-high-voltage-cables',
|
||||
translationKey: 'na2xsfl2y-3'
|
||||
};
|
||||
|
||||
const excelData = getExcelTechnicalDataForProduct(testProduct);
|
||||
|
||||
expect(excelData).toHaveProperty('configurations');
|
||||
expect(excelData).toHaveProperty('attributes');
|
||||
|
||||
// Check that configurations are properly formatted
|
||||
if (excelData && excelData.configurations.length > 0) {
|
||||
const firstConfig = excelData.configurations[0];
|
||||
// Should contain cross-section and optionally voltage
|
||||
expect(typeof firstConfig).toBe('string');
|
||||
expect(firstConfig.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('should enrich products with Excel data', () => {
|
||||
const products = getAllProducts();
|
||||
const testProduct = products.find(p => p.slug === 'na2xsfl2y-3');
|
||||
|
||||
if (!testProduct) {
|
||||
// Skip test if product not found
|
||||
return;
|
||||
}
|
||||
|
||||
const enriched = enrichProductWithExcelData(testProduct);
|
||||
|
||||
expect(enriched.excelConfigurations).toBeDefined();
|
||||
expect(enriched.excelAttributes).toBeDefined();
|
||||
|
||||
if (enriched.excelConfigurations) {
|
||||
expect(enriched.excelConfigurations.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle products without Excel data gracefully', () => {
|
||||
const testProduct = {
|
||||
id: 99999,
|
||||
translationKey: 'nonexistent-product',
|
||||
locale: 'en',
|
||||
slug: 'nonexistent-product',
|
||||
path: '/product/nonexistent-product',
|
||||
name: 'Nonexistent Product',
|
||||
shortDescriptionHtml: '<p>Test</p>',
|
||||
descriptionHtml: '<p>Test</p>',
|
||||
images: [],
|
||||
featuredImage: null,
|
||||
sku: 'TEST-001',
|
||||
regularPrice: '',
|
||||
salePrice: '',
|
||||
currency: 'EUR',
|
||||
stockStatus: 'instock',
|
||||
categories: [],
|
||||
attributes: [],
|
||||
variations: [],
|
||||
updatedAt: new Date().toISOString(),
|
||||
translation: null
|
||||
};
|
||||
|
||||
const enriched = enrichProductWithExcelData(testProduct);
|
||||
|
||||
// Should not have Excel data for non-existent product
|
||||
expect(enriched.excelConfigurations).toBeUndefined();
|
||||
expect(enriched.excelAttributes).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should get raw Excel rows for inspection', () => {
|
||||
const testProduct = {
|
||||
name: 'NA2XS(FL)2Y',
|
||||
slug: 'na2xsfl2y-3',
|
||||
sku: 'NA2XS(FL)2Y-high-voltage-cables',
|
||||
translationKey: 'na2xsfl2y-3'
|
||||
};
|
||||
|
||||
const rows = getExcelRowsForProduct(testProduct);
|
||||
|
||||
expect(rows).toBeInstanceOf(Array);
|
||||
expect(rows.length).toBeGreaterThan(0);
|
||||
|
||||
if (rows.length > 0) {
|
||||
// Should have valid row structure
|
||||
const firstRow = rows[0];
|
||||
expect(typeof firstRow).toBe('object');
|
||||
expect(Object.keys(firstRow).length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,177 +0,0 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user