Première brique du pipeline : lister les vidéos/streams d'une chaîne YouTube (yt-dlp --flat-playlist), filtrables par mots-clés sur le titre. - ytDlpRunner.ts : exécution de yt-dlp via child_process.spawn (jamais de shell, arguments en tableau - exclut l'injection de commande) - ChannelDiscoveryService.ts : validation stricte du handle/URL de chaîne + séparateur `--` avant l'URL (défense en profondeur contre l'injection d'options yt-dlp), parsing tolérant des lignes JSON, filtrage mots-clés - routes/channel.ts : GET /api/channel (validation de schéma Fastify, 400 si entrée invalide, 502 si yt-dlp échoue) - 14 tests (unitaires services + intégration route via app.inject) - un test de route a révélé une regex de validation trop permissive qu'un test de service avait manquée, corrigée avant ce commit La file d'attente et le téléchargement suivront dans une PR séparée. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
25 lines
823 B
TypeScript
25 lines
823 B
TypeScript
import { afterEach, describe, expect, it } from 'vitest';
|
|
import { YtDlpError, runYtDlp } from '../src/services/ytDlpRunner.js';
|
|
|
|
describe('runYtDlp', () => {
|
|
afterEach(() => {
|
|
// biome-ignore lint/performance/noDelete: une assignation à `undefined` stockerait la chaîne "undefined" dans process.env.
|
|
delete process.env.YTDLP_PATH;
|
|
});
|
|
|
|
it('retourne stdout quand le processus réussit', async () => {
|
|
process.env.YTDLP_PATH = process.execPath;
|
|
|
|
const stdout = await runYtDlp(['-e', "console.log('bonjour')"]);
|
|
|
|
expect(stdout.trim()).toBe('bonjour');
|
|
});
|
|
|
|
it('lève YtDlpError quand le processus se termine en échec', async () => {
|
|
process.env.YTDLP_PATH = process.execPath;
|
|
|
|
await expect(runYtDlp(['-e', "console.error('boom'); process.exit(3)"])).rejects.toBeInstanceOf(
|
|
YtDlpError,
|
|
);
|
|
});
|
|
});
|