import { describe, it, expect, beforeEach, vi } from 'vitest'; import { parseXMLTV, parseXMLTVDate, fetchAndParseXMLTV } from '../parsers/xmltv'; // Mock DOMParser for Node environment if (typeof DOMParser === 'undefined') { global.DOMParser = class { parseFromString(xml: string, type: string): Document { const { JSDOM } = require('jsdom'); const dom = new JSDOM(xml, { contentType: 'text/xml' }); return dom.window.document; } } as any; } describe('XMLTV Parser', () => { describe('parseXMLTVDate', () => { it('should parse XMLTV date with timezone', () => { const dateStr = '20240101120000 +0000'; const result = parseXMLTVDate(dateStr); expect(result).toBe('2024-01-01T12:00:00.000Z'); }); it('should parse XMLTV date without timezone', () => { const dateStr = '20240101120000'; const result = parseXMLTVDate(dateStr); expect(result).toBe('2024-01-01T12:00:00.000Z'); }); it('should parse XMLTV date with custom timezone', () => { const dateStr = '20240101120000'; const result = parseXMLTVDate(dateStr, '+0500'); // The result will be converted to UTC, so 12:00 +05:00 = 07:00 UTC expect(result).toBe('2024-01-01T07:00:00.000Z'); }); it('should throw error for invalid date format', () => { expect(() => parseXMLTVDate('invalid')).toThrow(); }); }); describe('parseXMLTV', () => { it('should parse basic XMLTV format', () => { const xml = ` HBO Test Show Test Description Movies `; const result = parseXMLTV(xml); expect(result.channels).toHaveLength(1); expect(result.channels[0].id).toBe('hbo'); expect(result.channels[0].displayName).toBe('HBO'); expect(result.channels[0].icon).toBe('http://example.com/hbo.png'); expect(result.programs).toHaveLength(1); expect(result.programs[0].channelId).toBe('hbo'); expect(result.programs[0].title).toBe('Test Show'); expect(result.programs[0].description).toBe('Test Description'); expect(result.programs[0].category).toBe('Movies'); }); it('should parse multiple channels and programmes', () => { const xml = ` HBO ESPN Show 1 Show 2 `; const result = parseXMLTV(xml); expect(result.channels).toHaveLength(2); expect(result.programs).toHaveLength(2); }); it('should handle missing optional fields', () => { const xml = ` HBO Test Show `; const result = parseXMLTV(xml); expect(result.programs[0].description).toBeUndefined(); expect(result.programs[0].category).toBeUndefined(); expect(result.programs[0].image).toBeUndefined(); }); it('should handle channel without display-name', () => { const xml = ` `; const result = parseXMLTV(xml); expect(result.channels).toHaveLength(1); expect(result.channels[0].displayName).toBe('hbo'); }); it('should skip programmes without required attributes', () => { const xml = ` HBO Valid Show Invalid Show `; const result = parseXMLTV(xml); expect(result.programs).toHaveLength(1); expect(result.programs[0].title).toBe('Valid Show'); }); it('should skip programmes with invalid dates', () => { const xml = ` HBO Invalid Date Show Valid Show `; const result = parseXMLTV(xml); expect(result.programs).toHaveLength(1); expect(result.programs[0].title).toBe('Valid Show'); }); it('should parse episode information', () => { const xml = ` HBO Test Show S01E01 `; const result = parseXMLTV(xml); expect(result.programs[0].episode).toBeDefined(); expect(result.programs[0].episode?.season).toBe(1); expect(result.programs[0].episode?.episode).toBe(1); }); it('should parse programme icon', () => { const xml = ` HBO Test Show `; const result = parseXMLTV(xml); expect(result.programs[0].image).toBe('http://example.com/show.png'); }); }); describe('fetchAndParseXMLTV', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should fetch and parse XMLTV from URL', async () => { const mockXml = ` HBO Test Show `; global.fetch = vi.fn().mockResolvedValue({ ok: true, text: async () => mockXml, }); const result = await fetchAndParseXMLTV('https://example.com/epg.xml'); expect(result.channels).toHaveLength(1); expect(result.programs).toHaveLength(1); expect(global.fetch).toHaveBeenCalledWith('https://example.com/epg.xml', { headers: { 'Accept': 'application/xml, text/xml', }, }); }); it('should use proxy URL if provided', async () => { const mockXml = ` HBO `; global.fetch = vi.fn().mockResolvedValue({ ok: true, text: async () => mockXml, }); await fetchAndParseXMLTV( 'https://example.com/epg.xml', undefined, 'https://proxy.com' ); expect(global.fetch).toHaveBeenCalledWith( 'https://proxy.com?url=' + encodeURIComponent('https://example.com/epg.xml'), expect.any(Object) ); }); it('should throw error on fetch failure', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: false, statusText: 'Not Found', }); await expect( fetchAndParseXMLTV('https://example.com/epg.xml') ).rejects.toThrow('Failed to fetch XMLTV: Not Found'); }); }); });