feat: improve error handling and add initialization checks
- Add custom error types and error codes - Add configuration validation - Add dependency checks - Add safe cleanup handling - Improve code organization
This commit is contained in:
parent
480e2c62ad
commit
ae532256e3
13
jest.config.mjs
Normal file
13
jest.config.mjs
Normal file
@ -0,0 +1,13 @@
|
||||
export default {
|
||||
preset: 'ts-jest/presets/default-esm',
|
||||
testEnvironment: 'node',
|
||||
extensionsToTreatAsEsm: ['.ts', '.mts'],
|
||||
moduleNameMapper: {
|
||||
'^(\\.{1,2}/.*)\\.m?js$': '$1',
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.m?[tj]s$': ['ts-jest', {
|
||||
useESM: true,
|
||||
}],
|
||||
},
|
||||
};
|
||||
3867
package-lock.json
generated
3867
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kevinwatt/yt-dlp-mcp",
|
||||
"version": "0.6.9",
|
||||
"version": "0.6.10",
|
||||
"description": "yt-dlp MCP Server - Download video content via Model Context Protocol",
|
||||
"keywords": [
|
||||
"mcp",
|
||||
@ -26,7 +26,8 @@
|
||||
],
|
||||
"main": "./lib/index.mjs",
|
||||
"scripts": {
|
||||
"prepare": "tsc && shx chmod +x ./lib/index.mjs"
|
||||
"prepare": "tsc && shx chmod +x ./lib/index.mjs",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --detectOpenHandles --forceExit"
|
||||
},
|
||||
"author": "Dewei Yen <k@funmula.com>",
|
||||
"license": "MIT",
|
||||
@ -42,7 +43,11 @@
|
||||
"spawn-rx": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"shx": "^0.3.4",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
|
||||
79
src/__tests__/index.test.ts
Normal file
79
src/__tests__/index.test.ts
Normal file
@ -0,0 +1,79 @@
|
||||
// @ts-nocheck
|
||||
// @jest-environment node
|
||||
import { jest } from '@jest/globals';
|
||||
import { describe, test, expect, beforeAll, afterAll, beforeEach } from '@jest/globals';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
|
||||
// 簡化 mock
|
||||
jest.mock('spawn-rx', () => ({
|
||||
spawnPromise: jest.fn().mockImplementation(async (cmd, args) => {
|
||||
if (args.includes('--get-filename')) {
|
||||
return 'mock_video.mp4';
|
||||
}
|
||||
return 'Download completed';
|
||||
})
|
||||
}));
|
||||
jest.mock('rimraf', () => ({
|
||||
rimraf: { sync: jest.fn() }
|
||||
}));
|
||||
|
||||
import { downloadVideo } from '../index.mts';
|
||||
|
||||
describe('downloadVideo', () => {
|
||||
const mockTimestamp = '2024-03-20_12-30-00';
|
||||
let originalDateToISOString: () => string;
|
||||
|
||||
// 全局清理
|
||||
afterAll(done => {
|
||||
// 清理所有計時器
|
||||
jest.useRealTimers();
|
||||
// 確保所有異步操作完成
|
||||
process.nextTick(done);
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
originalDateToISOString = Date.prototype.toISOString;
|
||||
Date.prototype.toISOString = jest.fn(() => '2024-03-20T12:30:00.000Z');
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
Date.prototype.toISOString = originalDateToISOString;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('downloads video successfully with correct format', async () => {
|
||||
const result = await downloadVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
|
||||
|
||||
// 驗證基本功能
|
||||
expect(result).toMatch(/Video successfully downloaded as/);
|
||||
expect(result).toContain(mockTimestamp);
|
||||
expect(result).toContain(os.homedir());
|
||||
expect(result).toContain('Downloads');
|
||||
});
|
||||
|
||||
test('handles special characters in video URL', async () => {
|
||||
// 使用有效的視頻 ID,但包含需要編碼的字符
|
||||
const result = await downloadVideo('https://www.youtube.com/watch?v=dQw4w9WgXcQ&title=特殊字符');
|
||||
|
||||
expect(result).toMatch(/Video successfully downloaded as/);
|
||||
expect(result).toContain(mockTimestamp);
|
||||
});
|
||||
|
||||
test('uses correct resolution format', async () => {
|
||||
const resolutions = ['480p', '720p', '1080p', 'best'];
|
||||
|
||||
// 使用 Promise.all 並行執行測試
|
||||
const results = await Promise.all(resolutions.map(resolution => downloadVideo(
|
||||
'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
resolution
|
||||
)));
|
||||
|
||||
results.forEach(result => {
|
||||
expect(result).toMatch(/Video successfully downloaded as/);
|
||||
});
|
||||
});
|
||||
});
|
||||
481
src/index.mts
481
src/index.mts
File diff suppressed because it is too large
Load Diff
8
tsconfig.jest.json
Normal file
8
tsconfig.jest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib",
|
||||
"module": "ES2020",
|
||||
"target": "ES2020"
|
||||
}
|
||||
}
|
||||
@ -10,10 +10,10 @@
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedParameters": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"pretty": true,
|
||||
"target": "es2015",
|
||||
"target": "ES2020",
|
||||
"outDir": "lib",
|
||||
"lib": ["dom", "es2015"],
|
||||
"esModuleInterop": true,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user