import {describe, expect, it, beforeAll, afterAll} from 'bun:test'; import {PCastApi} from '../../src/PCastApi'; import {Channels} from '../../src/apis/Channels'; import {Streams} from '../../src/apis/Stream'; import {Reporting} from '../../src/apis/Reporting/Reporting'; import type {ApplicationCredentials} from '../../src/apis/PCastRequests'; import {mockChannel} from '../mocks/Channel'; import {mockMember} from '../mocks/Member'; describe('PCastApi', () => { let originalFetch: typeof globalThis.fetch; const mockCredentials: ApplicationCredentials = { id: 'test-app-id', secret: 'test-app-secret' }; // Set up mock fetch before all tests to handle Channels.initialize() beforeAll(() => { originalFetch = globalThis.fetch; globalThis.fetch = () => Promise.resolve({ ok: true, status: 200, headers: new Headers({'content-type': 'application/json'}), json: async () => ({status: 'ok', channels: [], members: []}) } as Response); }); afterAll(() => { globalThis.fetch = originalFetch; }); describe('when creating an instance', () => { it('should create a PCastApi with the factory method', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api).toBeInstanceOf(PCastApi); }); it('should automatically append /pcast to URI if not present', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api).toBeInstanceOf(PCastApi); }); it('should not duplicate /pcast suffix if already present', () => { const api = PCastApi.create('https://pcast.example.com/pcast', mockCredentials); expect(api).toBeInstanceOf(PCastApi); }); it('should handle URI with trailing slash', () => { const api = PCastApi.create('https://pcast.example.com/', mockCredentials); expect(api).toBeInstanceOf(PCastApi); }); }); describe('when accessing sub-APIs', () => { it('should expose channels API', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api.channels).toBeInstanceOf(Channels); }); it('should expose streams API', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api.streams).toBeInstanceOf(Streams); }); it('should expose reporting API', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api.reporting).toBeInstanceOf(Reporting); }); it('should return the same channels instance on multiple accesses', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api.channels).toBe(api.channels); }); it('should return the same streams instance on multiple accesses', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api.streams).toBe(api.streams); }); it('should return the same reporting instance on multiple accesses', () => { const api = PCastApi.create('https://pcast.example.com', mockCredentials); expect(api.reporting).toBe(api.reporting); }); }); describe('legacy API methods', () => { describe('when calling createChannel', () => { it('should delegate to channels.create', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'application/json'}), json: async () => ({status: 'ok', channel: {...mockChannel, name: 'Test Channel'}}) } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.createChannel('Test Channel', 'Description', ['opt1']); expect(result.name).toBe('Test Channel'); }); }); describe('when calling getChannelInfoByAlias', () => { it('should delegate to channels.get with alias parameter', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'application/json'}), json: async () => ({status: 'ok', channels: [{...mockChannel, alias: 'my-alias'}]}) } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.getChannelInfoByAlias('my-alias'); expect(result?.alias).toBe('my-alias'); }); }); describe('when calling getChannelInfoByChannelId', () => { it('should delegate to channels.get with channelId parameter', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'application/json'}), json: async () => ({status: 'ok', channels: [{...mockChannel, channelId: 'specific-id'}]}) } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.getChannelInfoByChannelId('specific-id'); expect(result?.channelId).toBe('specific-id'); }); }); describe('when calling getChannelPublisherCount', () => { it('should delegate to channels.getPublisherCount', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'text/plain'}), text: async () => '5' } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.getChannelPublisherCount('channel-123'); expect(result).toBe(5); }); }); describe('when calling getChannelMembers', () => { it('should delegate to channels.getMembers', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'application/json'}), json: async () => ({status: 'ok', members: [{...mockMember, sessionId: 'sess-123'}]}) } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.getChannelMembers('channel-123'); expect(result).toHaveLength(1); expect(result[0].sessionId).toBe('sess-123'); }); }); describe('when calling deleteChannel', () => { it('should delegate to channels.delete with channelId', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'application/json'}), json: async () => ({status: 'ok'}) } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.deleteChannel('channel-to-delete'); expect(result.status).toBe('ok'); }); }); describe('when calling generateViewingReport', () => { it('should delegate to reporting.generateReport with correct parameters', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'text/plain'}), text: async () => 'report-id-abc' } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const startDate = new Date('2024-01-01T00:00:00Z'); const endDate = new Date('2024-01-02T00:00:00Z'); const result = await api.generateViewingReport('RealTime', startDate, endDate, {tags: ['tag1']}); expect(result).toBe('report-id-abc'); }); it('should handle HLS viewing report kind', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'text/plain'}), text: async () => 'report-id' } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.generateViewingReport('HLS', new Date('2024-01-01'), new Date('2024-01-02')); expect(result).toBe('report-id'); }); it('should handle DASH viewing report kind', async () => { globalThis.fetch = () => Promise.resolve({ ok: true, headers: new Headers({'content-type': 'text/plain'}), text: async () => 'report-id' } as Response); const api = PCastApi.create('https://pcast.example.com', mockCredentials); const result = await api.generateViewingReport('DASH', new Date('2024-01-01'), new Date('2024-01-02')); expect(result).toBe('report-id'); }); }); }); });