import { Stitcher } from '../src/stitcher.js'; import { describe, expect, it, vi, beforeEach } from 'vitest'; import { EventEmitter } from 'events'; import { spawn } from 'child_process'; const mockChildProcess = new (class MockChildProcess extends EventEmitter { kill = vi.fn(() => { return true; }); })(); vi.mock('child_process', () => { return { spawn: vi.fn(() => mockChildProcess) } }); describe('stitcher', () => { beforeEach(() => { vi.clearAllMocks(); }); it('passes the correct arguments to ffmpeg', async () => { const p = Stitcher(['1.flac', 'dir/2.flac']); mockChildProcess.emit('exit', 0, null); await p; expect(spawn).toBeCalledWith('ffmpeg', [ "-i", '1.flac', '-i', 'dir/2.flac', '-filter_complex', '[0:a][1:a][2:a]concat=n=2:v=0:a=1[out]', '-map', '[out]', '-ar', '44100', '-ac', '2', '-c:a', 'pcm_s16le', 'output.wav' ]); }); it('throws an error when ffmpeg fails', async () => { const p = Stitcher(['sound.mp3']); mockChildProcess.emit('exit', 1, null); await expect(p).rejects.toThrow('exited with 1'); expect(spawn).toBeCalledWith('ffmpeg', [ "-i", 'sound.mp3', '-filter_complex', '[0:a][1:a][2:a]concat=n=1:v=0:a=1[out]', '-map', '[out]', '-ar', '44100', '-ac', '2', '-c:a', 'pcm_s16le', 'output.wav' ]); }); it('throws an error when ffmpeg takes longer than expected', { timeout: 6000 }, async () => { await expect(Stitcher(['in.wav'])).rejects.toThrow('timed out'); expect(spawn).toBeCalledWith('ffmpeg', [ "-i", 'in.wav', '-filter_complex', '[0:a][1:a][2:a]concat=n=1:v=0:a=1[out]', '-map', '[out]', '-ar', '44100', '-ac', '2', '-c:a', 'pcm_s16le', 'output.wav' ]); }); });