const CodeGenerationService = require('../services/CodeGenerationService'); describe('CodeGenerationService', () => { let codeGenService; beforeEach(() => { codeGenService = new CodeGenerationService(); }); describe('Constructor and Configuration', () => { test('should initialize with default options', () => { expect(codeGenService.supportedBarcodeFormats).toContain('CODE128'); expect(codeGenService.supportedBarcodeFormats).toContain('CODE39'); expect(codeGenService.supportedBarcodeFormats).toContain('EAN13'); expect(codeGenService.defaultBarcodeOptions.format).toBe('CODE128'); expect(codeGenService.defaultQROptions.errorCorrectionLevel).toBe('M'); }); test('should return supported formats', () => { const formats = codeGenService.getSupportedFormats(); expect(formats).toEqual(['CODE128', 'CODE39', 'EAN13', 'EAN8', 'UPC']); }); }); describe('Barcode Generation', () => { test('should generate barcode with default CODE128 format', async () => { const result = await codeGenService.generateBarcode('TEST123'); expect(result.success).toBe(true); expect(result.data).toMatch(/^data:image\/png;base64,/); expect(result.format).toBe('CODE128'); expect(result.productCode).toBe('TEST123'); expect(result.metadata).toHaveProperty('width'); expect(result.metadata).toHaveProperty('height'); expect(result.metadata.format).toBe('PNG'); }); test('should generate barcode with specified format', async () => { const result = await codeGenService.generateBarcode('TEST123', 'CODE39'); expect(result.success).toBe(true); expect(result.format).toBe('CODE39'); expect(result.productCode).toBe('TEST123'); }); test('should handle invalid product code', async () => { const result = await codeGenService.generateBarcode(''); expect(result.success).toBe(false); expect(result.error).toContain('Product code must be a non-empty string'); }); test('should handle null product code', async () => { const result = await codeGenService.generateBarcode(null); expect(result.success).toBe(false); expect(result.error).toContain('Product code must be a non-empty string'); }); test('should handle unsupported barcode format', async () => { const result = await codeGenService.generateBarcode('TEST123', 'INVALID_FORMAT'); expect(result.success).toBe(false); expect(result.error).toContain('Unsupported barcode format'); }); test('should validate EAN13 format requirements', async () => { const validEAN13 = '123456789012'; const invalidEAN13 = 'ABC123'; const validResult = await codeGenService.generateBarcode(validEAN13, 'EAN13'); expect(validResult.success).toBe(true); const invalidResult = await codeGenService.generateBarcode(invalidEAN13, 'EAN13'); expect(invalidResult.success).toBe(false); expect(invalidResult.error).toContain('EAN13 format requires 12-13 digits'); }); test('should validate EAN8 format requirements', async () => { const validEAN8 = '1234567'; const invalidEAN8 = 'ABC123'; const validResult = await codeGenService.generateBarcode(validEAN8, 'EAN8'); expect(validResult.success).toBe(true); const invalidResult = await codeGenService.generateBarcode(invalidEAN8, 'EAN8'); expect(invalidResult.success).toBe(false); expect(invalidResult.error).toContain('EAN8 format requires 7-8 digits'); }); test('should validate UPC format requirements', async () => { const validUPC = '12345678901'; const invalidUPC = 'ABC123'; const validResult = await codeGenService.generateBarcode(validUPC, 'UPC'); expect(validResult.success).toBe(true); const invalidResult = await codeGenService.generateBarcode(invalidUPC, 'UPC'); expect(invalidResult.success).toBe(false); expect(invalidResult.error).toContain('UPC format requires 11-12 digits'); }); test('should validate CODE39 format requirements', async () => { const validCODE39 = 'TEST-123'; const invalidCODE39 = 'test@123'; const validResult = await codeGenService.generateBarcode(validCODE39, 'CODE39'); expect(validResult.success).toBe(true); const invalidResult = await codeGenService.generateBarcode(invalidCODE39, 'CODE39'); expect(invalidResult.success).toBe(false); expect(invalidResult.error).toContain('CODE39 format supports only uppercase letters'); }); test('should accept custom barcode options', async () => { const customOptions = { width: 3, height: 150, background: '#f0f0f0' }; const result = await codeGenService.generateBarcode('TEST123', 'CODE128', customOptions); expect(result.success).toBe(true); }); }); describe('QR Code Generation', () => { const sampleProductData = { product_code: 'PROD001', description: 'Test Product', category: 'Electronics', unit_of_measure: 'pcs' }; test('should generate QR code with product data', async () => { const result = await codeGenService.generateQRCode(sampleProductData); expect(result.success).toBe(true); expect(result.data).toMatch(/^data:image\/png;base64,/); expect(result.productCode).toBe('PROD001'); expect(result.embeddedData).toHaveProperty('code', 'PROD001'); expect(result.embeddedData).toHaveProperty('desc', 'Test Product'); expect(result.embeddedData).toHaveProperty('cat', 'Electronics'); expect(result.embeddedData).toHaveProperty('uom', 'pcs'); expect(result.embeddedData).toHaveProperty('ts'); expect(result.metadata.format).toBe('PNG'); }); test('should handle minimal product data', async () => { const minimalData = { product_code: 'MIN001' }; const result = await codeGenService.generateQRCode(minimalData); expect(result.success).toBe(true); expect(result.embeddedData.code).toBe('MIN001'); expect(result.embeddedData.desc).toBe(''); expect(result.embeddedData.cat).toBe(''); expect(result.embeddedData.uom).toBe(''); }); test('should handle invalid product data', async () => { const result = await codeGenService.generateQRCode(null); expect(result.success).toBe(false); expect(result.error).toContain('Product data must be an object'); }); test('should require product_code in data', async () => { const invalidData = { description: 'Test without code' }; const result = await codeGenService.generateQRCode(invalidData); expect(result.success).toBe(false); expect(result.error).toContain('Product data must include product_code'); }); test('should accept custom QR options', async () => { const customOptions = { width: 300, errorCorrectionLevel: 'H', color: { dark: '#FF0000', light: '#FFFFFF' } }; const result = await codeGenService.generateQRCode(sampleProductData, customOptions); expect(result.success).toBe(true); expect(result.metadata.errorCorrectionLevel).toBe('H'); expect(result.metadata.width).toBe(300); }); }); describe('Combined Code Generation', () => { const sampleProductData = { product_code: 'COMBO001', description: 'Combo Test Product', category: 'Test', unit_of_measure: 'pcs' }; test('should generate both barcode and QR code', async () => { const result = await codeGenService.generateBothCodes(sampleProductData); expect(result.productCode).toBe('COMBO001'); expect(result.barcode.success).toBe(true); expect(result.qrCode.success).toBe(true); expect(result.barcode.format).toBe('CODE128'); expect(result.qrCode.productCode).toBe('COMBO001'); expect(result.timestamp).toBeDefined(); }); test('should generate both codes with custom options', async () => { const options = { barcodeFormat: 'CODE39', barcode: { width: 3 }, qr: { width: 250 } }; const result = await codeGenService.generateBothCodes(sampleProductData, options); expect(result.barcode.format).toBe('CODE39'); expect(result.qrCode.metadata.width).toBe(250); }); test('should handle errors in individual code generation', async () => { const invalidData = { product_code: 'test@invalid' }; const options = { barcodeFormat: 'CODE39' }; const result = await codeGenService.generateBothCodes(invalidData, options); expect(result.barcode.success).toBe(false); expect(result.qrCode.success).toBe(true); }); }); describe('QR Code Data Parsing', () => { test('should parse valid QR code data', () => { const qrData = JSON.stringify({ code: 'PARSE001', desc: 'Parsed Product', cat: 'Category', uom: 'pcs', ts: '2023-01-01T00:00:00.000Z' }); const result = codeGenService.parseQRCodeData(qrData); expect(result.success).toBe(true); expect(result.productCode).toBe('PARSE001'); expect(result.description).toBe('Parsed Product'); expect(result.category).toBe('Category'); expect(result.unitOfMeasure).toBe('pcs'); expect(result.timestamp).toBe('2023-01-01T00:00:00.000Z'); }); test('should handle invalid QR code data', () => { const invalidData = 'invalid json data'; const result = codeGenService.parseQRCodeData(invalidData); expect(result.success).toBe(false); expect(result.error).toBe('Invalid QR code data format'); expect(result.rawData).toBe(invalidData); }); test('should handle empty QR code data', () => { const result = codeGenService.parseQRCodeData(''); expect(result.success).toBe(false); expect(result.error).toBe('Invalid QR code data format'); }); }); describe('Format Validation', () => { test('should validate format case insensitivity', async () => { const result1 = await codeGenService.generateBarcode('TEST123', 'code128'); const result2 = await codeGenService.generateBarcode('TEST123', 'CODE128'); expect(result1.success).toBe(true); expect(result2.success).toBe(true); expect(result1.format).toBe('CODE128'); expect(result2.format).toBe('CODE128'); }); test('should handle edge cases in product codes', async () => { const edgeCases = [ { code: '1', format: 'CODE128', shouldPass: true }, { code: 'A'.repeat(50), format: 'CODE128', shouldPass: true }, { code: '123456789012', format: 'EAN13', shouldPass: true }, { code: '1234567890123', format: 'EAN13', shouldPass: true } ]; for (const testCase of edgeCases) { const result = await codeGenService.generateBarcode(testCase.code, testCase.format); if (result.success !== testCase.shouldPass) { console.log(`Failed test case: ${testCase.code} (${testCase.format}) - Expected: ${testCase.shouldPass}, Got: ${result.success}, Error: ${result.error}`); } expect(result.success).toBe(testCase.shouldPass); } }); }); });