import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as smartpdf from '../ts/index.js'; import * as fs from 'fs'; import * as path from 'path'; let testSmartPdf: smartpdf.SmartPdf; /** * Ensures that a directory exists. * @param dirPath - The directory path to ensure. */ function ensureDir(dirPath: string): void { if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } } // Clean test results directory at start const testResultsDir = path.join('.nogit', 'testresults'); if (fs.existsSync(testResultsDir)) { fs.rmSync(testResultsDir, { recursive: true, force: true }); } ensureDir(testResultsDir); tap.test('should create a valid instance of SmartPdf', async () => { testSmartPdf = new smartpdf.SmartPdf(); expect(testSmartPdf).toBeInstanceOf(smartpdf.SmartPdf); }); tap.test('should start the SmartPdf instance', async () => { await testSmartPdf.start(); }); tap.test('should create PDFs from HTML string', async () => { const pdf1 = await testSmartPdf.getA4PdfResultForHtmlString('hi'); const pdf2 = await testSmartPdf.getA4PdfResultForHtmlString('hello'); expect(pdf1.buffer).toBeInstanceOf(Buffer); expect(pdf2.buffer).toBeInstanceOf(Buffer); }); tap.test('should create PDFs from websites', async () => { const pdfA4 = await testSmartPdf.getPdfResultForWebsite('https://www.wikipedia.org'); const pdfSingle = await testSmartPdf.getFullWebsiteAsSinglePdf('https://www.wikipedia.org'); expect(pdfA4.buffer).toBeInstanceOf(Buffer); expect(pdfSingle.buffer).toBeInstanceOf(Buffer); }); tap.test('should create valid PDF results and write them to disk', async () => { const writePdfToDisk = async (urlArg: string, fileName: string) => { const pdfResult = await testSmartPdf.getFullWebsiteAsSinglePdf(urlArg); expect(pdfResult.buffer).toBeInstanceOf(Buffer); ensureDir('.nogit'); fs.writeFileSync(path.join('.nogit', fileName), pdfResult.buffer as Buffer); }; await writePdfToDisk('https://lossless.com/', '1.pdf'); await writePdfToDisk('https://layer.io', '2.pdf'); }); tap.test('should merge PDFs into a combined PDF', async () => { const pdf1 = await testSmartPdf.readFileToPdfObject('.nogit/1.pdf'); const pdf2 = await testSmartPdf.readFileToPdfObject('.nogit/2.pdf'); const mergedBuffer = await testSmartPdf.mergePdfs([pdf1.buffer, pdf2.buffer]); ensureDir('.nogit'); fs.writeFileSync(path.join('.nogit', 'combined.pdf'), mergedBuffer); }); tap.test('should create PNG images from combined PDF using Puppeteer conversion', async () => { const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/combined.pdf'); const images = await testSmartPdf.convertPDFToPngBytes(pdfObject.buffer); expect(images.length).toBeGreaterThan(0); console.log('Puppeteer-based conversion image sizes:', images.map(img => img.length)); }); tap.test('should store PNG results from both conversion functions in .nogit/testresults', async () => { const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/combined.pdf'); // Convert using Puppeteer-based function and store images const imagesPuppeteer = await testSmartPdf.convertPDFToPngBytes(pdfObject.buffer); imagesPuppeteer.forEach((img, index) => { const filePath = path.join(testResultsDir, `png_combined_page${index + 1}.png`); fs.writeFileSync(filePath, Buffer.from(img)); }); }); tap.test('should create WebP preview images from PDF', async () => { const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/3.pdf'); const webpPreviews = await testSmartPdf.convertPDFToWebpBytes(pdfObject.buffer); expect(webpPreviews.length).toBeGreaterThan(0); console.log('WebP preview sizes:', webpPreviews.map(img => img.length)); // Also create PNG previews for comparison const pngPreviews = await testSmartPdf.convertPDFToPngBytes(pdfObject.buffer); console.log('PNG preview sizes:', pngPreviews.map(img => img.length)); // Save the first page as both WebP and PNG preview fs.writeFileSync(path.join(testResultsDir, 'webp_default_page1.webp'), Buffer.from(webpPreviews[0])); fs.writeFileSync(path.join(testResultsDir, 'png_default_page1.png'), Buffer.from(pngPreviews[0])); }); tap.test('should create WebP previews with custom scale and quality', async () => { const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/3.pdf'); // Create smaller previews with lower quality for thumbnails const thumbnails = await testSmartPdf.convertPDFToWebpBytes(pdfObject.buffer, { scale: 0.5, // Create readable thumbnails at ~36 DPI quality: 70 }); expect(thumbnails.length).toBeGreaterThan(0); console.log('Thumbnail sizes:', thumbnails.map(img => img.length)); // Save thumbnails thumbnails.forEach((thumb, index) => { fs.writeFileSync(path.join(testResultsDir, `webp_thumbnail_page${index + 1}.webp`), Buffer.from(thumb)); }); }); tap.test('should create WebP previews with max dimensions', async () => { const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/3.pdf'); // Create previews with maximum dimensions (will use high scale but constrain to max size) const constrainedPreviews = await testSmartPdf.convertPDFToWebpBytes(pdfObject.buffer, { scale: smartpdf.SmartPdf.SCALE_HIGH, // Start with high quality quality: 90, maxWidth: 800, maxHeight: 1000 }); expect(constrainedPreviews.length).toBeGreaterThan(0); console.log('Constrained preview sizes:', constrainedPreviews.map(img => img.length)); // Save constrained preview fs.writeFileSync(path.join(testResultsDir, 'webp_constrained_page1.webp'), Buffer.from(constrainedPreviews[0])); }); tap.test('should verify WebP files are smaller than PNG', async () => { const pdfObject = await testSmartPdf.readFileToPdfObject('.nogit/3.pdf'); // Generate both PNG and WebP versions at the same scale for fair comparison const comparisonScale = smartpdf.SmartPdf.SCALE_HIGH; // Both use 3.0 scale const pngImages = await testSmartPdf.convertPDFToPngBytes(pdfObject.buffer, { scale: comparisonScale }); const webpImages = await testSmartPdf.convertPDFToWebpBytes(pdfObject.buffer, { scale: comparisonScale, quality: 85 }); expect(pngImages.length).toEqual(webpImages.length); // Compare sizes let totalPngSize = 0; let totalWebpSize = 0; pngImages.forEach((png, index) => { const pngSize = png.length; const webpSize = webpImages[index].length; totalPngSize += pngSize; totalWebpSize += webpSize; const reduction = ((pngSize - webpSize) / pngSize * 100).toFixed(1); console.log(`Page ${index + 1}: PNG=${pngSize} bytes, WebP=${webpSize} bytes, Reduction=${reduction}%`); // Save comparison files fs.writeFileSync(path.join(testResultsDir, `comparison_png_page${index + 1}.png`), Buffer.from(png)); fs.writeFileSync(path.join(testResultsDir, `comparison_webp_page${index + 1}.webp`), Buffer.from(webpImages[index])); }); const totalReduction = ((totalPngSize - totalWebpSize) / totalPngSize * 100).toFixed(1); console.log(`Total size reduction: ${totalReduction}% (PNG: ${totalPngSize} bytes, WebP: ${totalWebpSize} bytes)`); // WebP should be smaller expect(totalWebpSize).toBeLessThan(totalPngSize); }); tap.test('should close the SmartPdf instance properly', async () => { await testSmartPdf.stop(); }); tap.start();