youtubeDownloader/server/test/ytDlpRunner.test.ts
Nicolas 0e78b44a55
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
feat(server): service de découverte de chaîne (GET /api/channel)
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>
2026-09-16 08:05:29 +02:00

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,
);
});
});