Fix D5 downloader test mocks: execFile args pass (cmd, args[], cb) not flat list
This commit is contained in:
@@ -2,13 +2,17 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|||||||
import { rm } from 'fs/promises';
|
import { rm } from 'fs/promises';
|
||||||
import type { TranscriptResponse } from 'youtube-transcript';
|
import type { TranscriptResponse } from 'youtube-transcript';
|
||||||
|
|
||||||
const { mockExecFile, mockFetchTranscript } = vi.hoisted(() => ({
|
const { mockExecFile, mockFetchTranscript, TEST_DATA_DIR } = vi.hoisted(() => {
|
||||||
mockExecFile: vi.fn(),
|
const dir = `/tmp/tonemark-downloader-test-${Date.now()}`;
|
||||||
mockFetchTranscript: vi.fn()
|
// Set DATA_DIR before any import evaluation so that the module-level
|
||||||
}));
|
// DATA_DIR constant in data-dir.ts picks up the test temp dir.
|
||||||
|
process.env.DATA_DIR = dir;
|
||||||
const TEST_DATA_DIR = `/tmp/tonemark-downloader-test-${Date.now()}`;
|
return {
|
||||||
vi.stubEnv('DATA_DIR', TEST_DATA_DIR);
|
mockExecFile: vi.fn(),
|
||||||
|
mockFetchTranscript: vi.fn(),
|
||||||
|
TEST_DATA_DIR: dir
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
vi.mock('child_process', () => ({
|
vi.mock('child_process', () => ({
|
||||||
execFile: mockExecFile
|
execFile: mockExecFile
|
||||||
@@ -137,13 +141,13 @@ describe('downloadYouTube', () => {
|
|||||||
describe('empty captions fallback (D5)', () => {
|
describe('empty captions fallback (D5)', () => {
|
||||||
it('falls back to audio when fetchTranscript returns empty segments array', async () => {
|
it('falls back to audio when fetchTranscript returns empty segments array', async () => {
|
||||||
mockFetchTranscript.mockResolvedValue([] satisfies TranscriptResponse[]);
|
mockFetchTranscript.mockResolvedValue([] satisfies TranscriptResponse[]);
|
||||||
mockExecFile.mockImplementation((...args: unknown[]) => {
|
mockExecFile.mockImplementation(function ytdlpMock(...args: unknown[]) {
|
||||||
const allArgs = args.slice(0, -1) as string[];
|
const cmd = args[0] as string;
|
||||||
|
const cmdArgs = args[1] as string[];
|
||||||
const cb = args.at(-1) as (...callbackArgs: unknown[]) => void;
|
const cb = args.at(-1) as (...callbackArgs: unknown[]) => void;
|
||||||
// downloadAudio: yt-dlp -f bestaudio [...]
|
if (cmd === 'yt-dlp' && cmdArgs.includes('-f')) {
|
||||||
if (allArgs.includes('-f')) {
|
const oIdx = cmdArgs.indexOf('-o');
|
||||||
const oIdx = allArgs.indexOf('-o');
|
const outPattern = oIdx !== -1 ? cmdArgs[oIdx + 1] : '';
|
||||||
const outPattern = oIdx !== -1 ? allArgs[oIdx + 1] : '';
|
|
||||||
const outDir = outPattern ? outPattern.substring(0, outPattern.lastIndexOf('/')) : '';
|
const outDir = outPattern ? outPattern.substring(0, outPattern.lastIndexOf('/')) : '';
|
||||||
if (outDir) {
|
if (outDir) {
|
||||||
const { mkdirSync, writeFileSync } = require('fs');
|
const { mkdirSync, writeFileSync } = require('fs');
|
||||||
@@ -154,12 +158,8 @@ describe('empty captions fallback (D5)', () => {
|
|||||||
}
|
}
|
||||||
cb(null, JSON.stringify({ title: 'Empty Captions Video' }), '');
|
cb(null, JSON.stringify({ title: 'Empty Captions Video' }), '');
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await downloadYouTube('https://youtube.com/watch?v=empty', 'test-empty-1');
|
const result = await downloadYouTube('https://youtube.com/watch?v=empty', 'test-empty-1');
|
||||||
|
expect(mockFetchTranscript).toHaveBeenCalledWith('https://youtube.com/watch?v=empty', { lang: 'en' });
|
||||||
expect(mockFetchTranscript).toHaveBeenCalledWith('https://youtube.com/watch?v=empty', {
|
|
||||||
lang: 'en'
|
|
||||||
});
|
|
||||||
expect(result.type).toBe('audio');
|
expect(result.type).toBe('audio');
|
||||||
expect(result.title).toBe('Empty Captions Video');
|
expect(result.title).toBe('Empty Captions Video');
|
||||||
});
|
});
|
||||||
@@ -169,12 +169,13 @@ describe('empty captions fallback (D5)', () => {
|
|||||||
{ text: ' ', offset: 1000, duration: 2000, lang: 'en' },
|
{ text: ' ', offset: 1000, duration: 2000, lang: 'en' },
|
||||||
{ text: ' ', offset: 3000, duration: 1000, lang: 'en' }
|
{ text: ' ', offset: 3000, duration: 1000, lang: 'en' }
|
||||||
] satisfies TranscriptResponse[]);
|
] satisfies TranscriptResponse[]);
|
||||||
mockExecFile.mockImplementation((...args: unknown[]) => {
|
mockExecFile.mockImplementation(function ytdlpMock(...args: unknown[]) {
|
||||||
const allArgs = args.slice(0, -1) as string[];
|
const cmd = args[0] as string;
|
||||||
|
const cmdArgs = args[1] as string[];
|
||||||
const cb = args.at(-1) as (...callbackArgs: unknown[]) => void;
|
const cb = args.at(-1) as (...callbackArgs: unknown[]) => void;
|
||||||
if (allArgs.includes('-f')) {
|
if (cmd === 'yt-dlp' && cmdArgs.includes('-f')) {
|
||||||
const oIdx = allArgs.indexOf('-o');
|
const oIdx = cmdArgs.indexOf('-o');
|
||||||
const outPattern = oIdx !== -1 ? allArgs[oIdx + 1] : '';
|
const outPattern = oIdx !== -1 ? cmdArgs[oIdx + 1] : '';
|
||||||
const outDir = outPattern ? outPattern.substring(0, outPattern.lastIndexOf('/')) : '';
|
const outDir = outPattern ? outPattern.substring(0, outPattern.lastIndexOf('/')) : '';
|
||||||
if (outDir) {
|
if (outDir) {
|
||||||
const { mkdirSync, writeFileSync } = require('fs');
|
const { mkdirSync, writeFileSync } = require('fs');
|
||||||
@@ -185,9 +186,7 @@ describe('empty captions fallback (D5)', () => {
|
|||||||
}
|
}
|
||||||
cb(null, JSON.stringify({ title: 'Whitespace Only' }), '');
|
cb(null, JSON.stringify({ title: 'Whitespace Only' }), '');
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await downloadYouTube('https://youtube.com/watch?v=ws-only', 'test-empty-2');
|
const result = await downloadYouTube('https://youtube.com/watch?v=ws-only', 'test-empty-2');
|
||||||
|
|
||||||
expect(result.type).toBe('audio');
|
expect(result.type).toBe('audio');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user