Files
ersatztv/web/src/api/autoTune.test.ts
T
timothyandClaude Opus 4.8 33ba3a0492
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 9s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 9s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m52s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 12s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 8s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 8m37s
feat(69): Auto-Tune SPA wizard — Configure → Preview → Create (PR2)
New `/app/auto-tune` screen driving the PR1 endpoints: pick metadata axes
(TV Shows / TV Genres / Movie Genres) + defaults, preview proposed channels
grouped by axis with per-row/per-group selection and already-exists dedup,
then bulk-create with a Created/Skipped/Failed summary. Additive/non-destructive.

The per-channel DetailPanel from the design iteration is deferred to #383
(new endpoints backlogged) — this ships the 3-step wizard only.

- web/src/api/autoTune.ts (+test), web/src/screens/AutoTuneScreen.tsx (+test)
- route/nav (routes.tsx, ScreenContent.tsx), api barrel, App nav-smoke test
- docs: domain-model (route), blazor-route-parity (net-new SPA screen)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 00:04:42 +02:00

90 lines
2.9 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { createAutoTunedChannels, previewAutoTune } from './autoTune';
const sampleProposals = [
{ axis: 'TvShow', value: 'The Office', name: 'The Office', number: '500', itemCount: 201, alreadyExists: false },
{ axis: 'TvGenre', value: 'Comedy', name: 'Comedy', number: '501', itemCount: 640, alreadyExists: true }
];
const sampleResult = {
results: [{ name: 'The Office', status: 'Created', channelId: 80, reason: null }],
createdCount: 1,
skippedCount: 0,
failedCount: 0
};
describe('previewAutoTune', () => {
beforeEach(() => {
window.localStorage.clear();
vi.restoreAllMocks();
});
it('POSTs /api/v1/channels/auto-tune/preview with the axes/minItems/startingNumber body', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockResolvedValue(
new Response(JSON.stringify(sampleProposals), {
headers: { 'Content-Type': 'application/json' },
status: 200
})
);
await expect(
previewAutoTune({ axes: ['TvShow', 'TvGenre'], minItems: 5, startingNumber: 500 })
).resolves.toHaveLength(2);
const [url, init] = fetchSpy.mock.calls[0];
expect(url).toBe('/api/v1/channels/auto-tune/preview');
expect((init?.method ?? 'GET').toUpperCase()).toBe('POST');
expect(JSON.parse(String(init?.body))).toEqual({
axes: ['TvShow', 'TvGenre'],
minItems: 5,
startingNumber: 500
});
});
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(
previewAutoTune({ axes: ['TvShow'], minItems: 1, startingNumber: 1 })
).rejects.toMatchObject({ status: 500 });
});
});
describe('createAutoTunedChannels', () => {
beforeEach(() => {
window.localStorage.clear();
vi.restoreAllMocks();
});
it('POSTs /api/v1/channels/auto-tune with templateId, group and echoed channels', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockResolvedValue(
new Response(JSON.stringify(sampleResult), {
headers: { 'Content-Type': 'application/json' },
status: 200
})
);
await expect(
createAutoTunedChannels({
templateId: 3,
group: 'Auto-Tuned',
channels: [{ axis: 'TvShow', value: 'The Office', name: 'The Office', number: '500' }]
})
).resolves.toMatchObject({ createdCount: 1 });
const [url, init] = fetchSpy.mock.calls[0];
expect(url).toBe('/api/v1/channels/auto-tune');
expect((init?.method ?? 'GET').toUpperCase()).toBe('POST');
expect(JSON.parse(String(init?.body))).toEqual({
templateId: 3,
group: 'Auto-Tuned',
channels: [{ axis: 'TvShow', value: 'The Office', name: 'The Office', number: '500' }]
});
});
});