Files
ersatztv/web/src/api/troubleshoot.test.ts
T
timothyandClaude Fable 5 40299f5ee6 feat(api): SPA wrappers for troubleshoot playback stream-selectors/subtitles/status
Adds thin client wrappers (+ URL-building tests) for GET
/api/troubleshoot/playback/{stream-selectors,subtitles/{id},status}, used by
the playback troubleshooting screen (#145).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 00:03:26 +02:00

122 lines
4.2 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import {
getTroubleshootingInfo,
getTroubleshootingPlaybackStatus,
getTroubleshootingStreamSelectors,
getTroubleshootingSubtitles,
validateSequentialSchedule
} from './troubleshoot';
function jsonResponse(body: unknown, status = 200): Response {
return new Response(JSON.stringify(body), { headers: { 'Content-Type': 'application/json' }, status });
}
const sampleInfo = {
generalJson: '{"Version":"1.2.3"}',
nvidiaCapabilities: 'nvidia output',
qsvCapabilities: null,
vaapiCapabilities: null,
videoToolboxCapabilities: null
};
describe('getTroubleshootingInfo', () => {
beforeEach(() => {
window.localStorage.clear();
vi.restoreAllMocks();
});
it('GETs /api/troubleshoot/info and returns the info payload', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockResolvedValue(
new Response(JSON.stringify(sampleInfo), {
headers: { 'Content-Type': 'application/json' },
status: 200
})
);
await expect(getTroubleshootingInfo()).resolves.toMatchObject({ nvidiaCapabilities: 'nvidia output' });
const [url, init] = fetchSpy.mock.calls[0];
expect(url).toBe('/api/troubleshoot/info');
expect((init?.method ?? 'GET').toUpperCase()).toBe('GET');
});
it('rejects with the ApiError status on failure', async () => {
vi.spyOn(window, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ status: 500, title: 'Server Error' }), {
headers: { 'Content-Type': 'application/json' },
status: 500
})
);
await expect(getTroubleshootingInfo()).rejects.toMatchObject({ status: 500 });
});
});
describe('validateSequentialSchedule', () => {
const sampleResult = { isValid: true, messages: [], json: '{}' };
beforeEach(() => {
window.localStorage.clear();
vi.restoreAllMocks();
});
it('POSTs /api/troubleshoot/validate-schedule with the yaml and isImport body', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockResolvedValue(
new Response(JSON.stringify(sampleResult), {
headers: { 'Content-Type': 'application/json' },
status: 200
})
);
await expect(validateSequentialSchedule('content: []', true)).resolves.toMatchObject({ isValid: true });
const [url, init] = fetchSpy.mock.calls[0];
expect(url).toBe('/api/troubleshoot/validate-schedule');
expect((init?.method ?? 'GET').toUpperCase()).toBe('POST');
expect(JSON.parse(String(init?.body))).toEqual({ yaml: 'content: []', isImport: true });
});
it('rejects with the ApiError status on failure', async () => {
vi.spyOn(window, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ status: 400, title: 'Validation failed' }), {
headers: { 'Content-Type': 'application/json' },
status: 400
})
);
await expect(validateSequentialSchedule('', false)).rejects.toMatchObject({ status: 400 });
});
});
describe('troubleshooting playback wrappers', () => {
beforeEach(() => {
window.localStorage.clear();
vi.restoreAllMocks();
});
it('GETs the stream selectors list', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockResolvedValue(jsonResponse(['a', 'b']));
await expect(getTroubleshootingStreamSelectors()).resolves.toEqual(['a', 'b']);
expect(fetchSpy.mock.calls[0][0]).toBe('/api/troubleshoot/playback/stream-selectors');
});
it('GETs the subtitle list for a media item id', async () => {
const fetchSpy = vi
.spyOn(window, 'fetch')
.mockResolvedValue(jsonResponse([{ id: 3, language: 'eng', title: 'English', codec: 'subrip' }]));
await expect(getTroubleshootingSubtitles(42)).resolves.toMatchObject([{ id: 3 }]);
expect(fetchSpy.mock.calls[0][0]).toBe('/api/troubleshoot/playback/subtitles/42');
});
it('GETs the playback status', async () => {
const fetchSpy = vi
.spyOn(window, 'fetch')
.mockResolvedValue(jsonResponse({ state: 'completed', exitCode: 0, speed: 1.2, logs: 'ok' }));
await expect(getTroubleshootingPlaybackStatus()).resolves.toMatchObject({ state: 'completed', speed: 1.2 });
expect(fetchSpy.mock.calls[0][0]).toBe('/api/troubleshoot/playback/status');
});
});