import {test} from 'node:test'; import assert from 'node:assert/strict'; import {quantityParts,validateBidRows,bidRowTotal,parseBidPrice} from '../src/services/bidValidation.js'; import {yaziylaTL,teklifCetveliHtml} from '../src/services/bidDocs.js'; test('Turkish quantities, decimal quantities and units are preserved',()=>{ assert.deepEqual(quantityParts('2.138.330 puan'),{miktar:2138330,birim:'puan'}); assert.deepEqual(quantityParts('1.234,50 litre'),{miktar:1234.5,birim:'litre'}); assert.deepEqual(quantityParts('1.5 litre'),{miktar:1.5,birim:'litre'}); assert.equal(quantityParts('kalem 15').miktar,null); assert.equal(validateBidRows([{name:'Kit',quantity:'20',birimFiyat:10}]).length,1); }); test('empty and partially priced bids cannot generate a valid sheet',()=>{ assert.ok(validateBidRows([]).length); assert.throws(()=>teklifCetveliHtml({},[],0)); assert.ok(validateBidRows([{name:'Kit',quantity:'20 adet',birimFiyat:''}]).length); assert.equal(bidRowTotal({quantity:'3 adet',birimFiyat:'0.335'}),1.01); assert.equal(yaziylaTL(1.999),'iki Türk Lirası'); }); test('100 rows retain Turkish names and escaped content in printable sheet',()=>{ const rows=Array.from({length:100},(_,i)=>({name:`Ölçüm ${i}`,quantity:'2 adet',birimFiyat:10})); const out=teklifCetveliHtml({firmaUnvan:'İğdır',ikn:'2026/1'},rows,2000); assert.equal((out.match(/Ölçüm <kit>/g)||[]).length,100); assert.ok(out.includes('İğdır'));assert.ok(out.includes('2.000,00')); }); test('Turkish decimal price is identical in row total and printable sheet',()=>{ const row={name:'Kit',quantity:'2 adet',birimFiyat:'125,50'}; assert.equal(parseBidPrice(row.birimFiyat),125.5); assert.equal(parseBidPrice('1.250,50'),1250.5); assert.equal(bidRowTotal(row),251); const html=teklifCetveliHtml({},[row],251); assert.ok(html.includes('125,50'));assert.ok(html.includes('251,00')); assert.ok(!html.includes('25.100')); for(const value of ['', '125,,50','1e3','125 TL','1.2.3','-20','125,']) assert.equal(parseBidPrice(value),null); assert.equal(bidRowTotal({quantity:'1000000000 adet',birimFiyat:'999999999999999'}),null); }); test('aggregate overflow is rejected across printable and workbook output',async()=>{ const {bidTotal,bidAmount}=await import('../src/services/bidValidation.js'); const {createBidWorkbook}=await import('../src/services/bidWorkbook.js'); const {teklifMektubuHtml}=await import('../src/services/bidDocs.js'); const rows=Array.from({length:3},()=>({name:'Cihaz',quantity:'1 adet',birimFiyat:40000000000000})); assert.deepEqual(validateBidRows(rows),[]); assert.equal(bidTotal(rows),null); assert.throws(()=>teklifCetveliHtml({},rows,120000000000000),/sınır/); await assert.rejects(createBidWorkbook({},rows),/sınır/); for(const amount of ['999999999999999', '0.001', '', '-1', Infinity]) { assert.equal(bidAmount(amount),null); assert.throws(()=>teklifMektubuHtml({},amount),/geçersiz/); } assert.equal(bidAmount('125,505'),125.51); }); test('print total must equal the common rounded row sum',async()=>{ const {bidTotal}=await import('../src/services/bidValidation.js'); const rows=Array.from({length:100},()=>({name:'Kit',quantity:'3 adet',birimFiyat:'0.335'})); assert.equal(bidTotal(rows),101); const {createBidWorkbook}=await import('../src/services/bidWorkbook.js'); const {default:ExcelJS}=await import('exceljs'); const workbook=new ExcelJS.Workbook(); await workbook.xlsx.load(await createBidWorkbook({},rows)); assert.equal(workbook.worksheets[0].getCell('F107').result,101); for(let i=7;i<=106;i++) assert.equal(workbook.worksheets[0].getCell(`F${i}`).result,1.01); assert.throws(()=>teklifCetveliHtml({},rows,100.5),/uyuşmuyor/); assert.ok(teklifCetveliHtml({},rows,101).includes('101,00')); assert.equal(bidTotal([{name:'Kit',quantity:'2 adet',birimFiyat:''}]),null); });