import { generateConsolidatedSummary, generateConsolidatedDescription, extractFirstCve, extractCommonVendor, } from './jiraConsolidation'; describe('generateConsolidatedSummary', () => { it('formats summary with count, common vendor, and first title', () => { const items = [ { vendor: 'Microsoft', finding_title: 'RCE in Exchange' }, { vendor: 'Microsoft', finding_title: 'XSS in Outlook' }, ]; expect(generateConsolidatedSummary(items)).toBe( '[2 findings] Microsoft - RCE in Exchange' ); }); it('uses "Multiple Vendors" when vendors differ', () => { const items = [ { vendor: 'Microsoft', finding_title: 'RCE in Exchange' }, { vendor: 'Adobe', finding_title: 'Buffer overflow' }, ]; expect(generateConsolidatedSummary(items)).toBe( '[2 findings] Multiple Vendors - RCE in Exchange' ); }); it('uses "Multiple Vendors" when vendor is null/empty', () => { const items = [ { vendor: null, finding_title: 'Finding A' }, { vendor: '', finding_title: 'Finding B' }, ]; expect(generateConsolidatedSummary(items)).toBe( '[2 findings] Multiple Vendors - Finding A' ); }); it('uses "Untitled" when first item has no finding_title', () => { const items = [{ vendor: 'Cisco' }, { vendor: 'Cisco', finding_title: 'Bug' }]; expect(generateConsolidatedSummary(items)).toBe( '[2 findings] Cisco - Untitled' ); }); it('truncates to 255 characters', () => { const longTitle = 'A'.repeat(300); const items = [{ vendor: 'V', finding_title: longTitle }]; const result = generateConsolidatedSummary(items); expect(result.length).toBeLessThanOrEqual(255); expect(result).toMatch(/^\[1 findings\] V - /); }); }); describe('generateConsolidatedDescription', () => { it('includes header with item count', () => { const items = [ { vendor: 'Microsoft', finding_title: 'Bug', cves_json: '["CVE-2024-001"]', hostname: 'host1', ip_address: '10.0.0.1' }, ]; const result = generateConsolidatedDescription(items); expect(result).toContain('Consolidated Jira ticket covering 1 Ivanti queue findings.'); }); it('groups items by vendor', () => { const items = [ { vendor: 'Microsoft', finding_title: 'Bug A', hostname: 'h1', ip_address: '10.0.0.1' }, { vendor: 'Adobe', finding_title: 'Bug B', hostname: 'h2', ip_address: '10.0.0.2' }, { vendor: 'Microsoft', finding_title: 'Bug C', hostname: 'h3', ip_address: '10.0.0.3' }, ]; const result = generateConsolidatedDescription(items); expect(result).toContain('== Microsoft =='); expect(result).toContain('== Adobe =='); expect(result).toContain('Bug A'); expect(result).toContain('Bug B'); expect(result).toContain('Bug C'); }); it('uses "Unknown Vendor" for null/empty vendor', () => { const items = [ { vendor: null, finding_title: 'Bug', hostname: 'h1', ip_address: '10.0.0.1' }, ]; const result = generateConsolidatedDescription(items); expect(result).toContain('== Unknown Vendor =='); }); it('includes CVEs, hostname, and IP for each item', () => { const items = [ { vendor: 'Cisco', finding_title: 'Vuln', cves_json: '["CVE-2024-100","CVE-2024-101"]', hostname: 'server1', ip_address: '192.168.1.1' }, ]; const result = generateConsolidatedDescription(items); expect(result).toContain('CVEs: CVE-2024-100, CVE-2024-101'); expect(result).toContain('Host: server1 (192.168.1.1)'); }); it('shows "None" for items without CVEs', () => { const items = [ { vendor: 'Cisco', finding_title: 'Vuln', hostname: 'h1', ip_address: '10.0.0.1' }, ]; const result = generateConsolidatedDescription(items); expect(result).toContain('CVEs: None'); }); it('shows "N/A" for missing hostname and ip_address', () => { const items = [{ vendor: 'Cisco', finding_title: 'Vuln' }]; const result = generateConsolidatedDescription(items); expect(result).toContain('Host: N/A (N/A)'); }); }); describe('extractFirstCve', () => { it('returns first CVE from first item with non-empty cves_json', () => { const items = [ { cves_json: null }, { cves_json: '["CVE-2024-200","CVE-2024-201"]' }, { cves_json: '["CVE-2024-300"]' }, ]; expect(extractFirstCve(items)).toBe('CVE-2024-200'); }); it('returns empty string when no items have CVEs', () => { const items = [ { cves_json: null }, { cves_json: '[]' }, ]; expect(extractFirstCve(items)).toBe(''); }); it('returns empty string for empty array', () => { expect(extractFirstCve([])).toBe(''); }); it('skips items with invalid JSON in cves_json', () => { const items = [ { cves_json: 'not-json' }, { cves_json: '["CVE-2024-500"]' }, ]; expect(extractFirstCve(items)).toBe('CVE-2024-500'); }); }); describe('extractCommonVendor', () => { it('returns vendor when all items share the same vendor', () => { const items = [ { vendor: 'Microsoft' }, { vendor: 'Microsoft' }, { vendor: 'Microsoft' }, ]; expect(extractCommonVendor(items)).toBe('Microsoft'); }); it('returns empty string when vendors differ', () => { const items = [ { vendor: 'Microsoft' }, { vendor: 'Adobe' }, ]; expect(extractCommonVendor(items)).toBe(''); }); it('returns empty string when all vendors are null/empty', () => { const items = [ { vendor: null }, { vendor: '' }, ]; expect(extractCommonVendor(items)).toBe(''); }); it('returns vendor when some items have null vendor but all non-null are same', () => { const items = [ { vendor: 'Cisco' }, { vendor: null }, { vendor: 'Cisco' }, ]; expect(extractCommonVendor(items)).toBe('Cisco'); }); });