用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/dev-hann/song --skill youtube-mocking命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | youtube-mocking |
| description | Mock YouTube.js API calls for isolated testing |
| license | MIT |
| compatibility | opencode |
| metadata | {"category":"testing","complexity":"intermediate"} |
Use this when you need to:
I'll ask clarifying questions if:
import { describe, it, expect, vi, beforeEach } from 'vitest';
vi.mock('youtubei.js', () => ({
Innertube: {
create: vi.fn(),
},
}));
describe('YouTube.js Mocking', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should mock Innertube.create', async () => {
const mockInnertube = { session: {} };
const { Innertube } = await import('youtubei.js');
vi.mocked(Innertube.create).mockResolvedValue(mockInnertube as any);
const result = await Innertube.create();
expect(result).toBe(mockInnertube);
expect(Innertube.create).toHaveBeenCalledWith({
generate_session_locally: true,
enable_session_cache: false,
lang: 'ko',
location: 'KR',
});
});
});
vi.mock('@/lib/youtube', () => ({
getInnertube: vi.fn(),
}));
describe('getInnertube', () => {
it('should return mocked Innertube instance', async () => {
const mockInnertube = {
search: vi.fn(),
getBasicInfo: vi.fn(),
getChannel: vi.fn(),
getPlaylist: vi.fn(),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const result = await getInnertube();
expect(result).toBe(mockInnertube);
});
});
it('should mock search results', async () => {
const mockInnertube = {
search: vi.fn().mockResolvedValue({
results: [
{
id: 'video123',
type: 'video',
title: 'Test Video',
thumbnail: 'https://example.com/thumb.jpg',
channel: { name: 'Test Channel' },
},
],
has_continuation: false,
}),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
const results = await innertube.search('test query');
expect(results.results).toHaveLength(1);
expect(results.results[0].title).toBe('Test Video');
});
it('should mock video info', async () => {
const mockInnertube = {
getBasicInfo: vi.fn().mockResolvedValue({
basic_info: {
id: 'video123',
title: 'Test Video',
short_description: 'Test Description',
duration: { seconds: 120 },
view_count: 5000,
upload_date: '2024-01-01',
thumbnail: [{ url: 'https://example.com/thumb.jpg' }],
channel_id: 'channel123',
channel: {
name: 'Test Channel',
thumbnails: [{ url: 'https://example.com/channel.jpg' }],
},
},
}),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
const info = await innertube.getBasicInfo('video123');
expect(info.basic_info.).();
(info...).();
});
it('should mock channel info', async () => {
const mockInnertube = {
getChannel: vi.fn().mockResolvedValue({
metadata: {
title: 'Test Channel',
description: 'Test Description',
thumbnail: [{ url: 'https://example.com/channel.jpg' }],
},
videos: [
{
id: 'video123',
title: 'Test Video',
duration: { seconds: 120 },
view_count: 5000,
thumbnails: [{ url: 'https://example.com/thumb.jpg' }],
upload_date: '2024-01-01',
},
],
}),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
const channel = await innertube.getChannel('channel123');
expect(channel.metadata.title).();
(channel.).();
});
it('should mock playlist info', async () => {
const mockInnertube = {
getPlaylist: vi.fn().mockResolvedValue({
info: {
title: 'Test Playlist',
description: 'Test Description',
thumbnails: [{ url: 'https://example.com/playlist.jpg' }],
total_items: 10,
author: {
name: 'Test Channel',
},
},
items: [
{
id: 'video123',
title: 'Test Video',
duration: { seconds: 120 },
thumbnails: [{ url: 'https://example.com/thumb.jpg' }],
index: 1,
},
],
}),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
const playlist = await innertube.getPlaylist('playlist123');
(playlist..).();
(playlist..).();
});
it('should mock home feed', async () => {
const mockInnertube = {
getHomeFeed: vi.fn().mockResolvedValue([
{
id: 'video123',
type: 'video',
title: 'Test Video',
thumbnail: 'https://example.com/thumb.jpg',
channel: { name: 'Test Channel' },
},
]),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
const feed = await innertube.getHomeFeed();
expect(feed).toHaveLength(1);
});
it('should mock API error', async () => {
const mockInnertube = {
search: vi.fn().mockRejectedValue(new Error('API Error')),
};
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
await expect(innertube.search('test query')).rejects.toThrow('API Error');
});
// tests/mocks/youtube-helpers.ts
export function createMockVideo(overrides = {}) {
return {
id: 'video123',
type: 'video',
title: 'Test Video',
description: 'Test Description',
duration: 120,
viewCount: 5000,
thumbnail: 'https://example.com/thumb.jpg',
channel: {
id: 'channel123',
name: 'Test Channel',
thumbnail: 'https://example.com/channel.jpg',
},
...overrides,
};
}
export function createMockChannel(overrides = {}) {
return {
id: 'channel123',
type: 'channel',
name: 'Test Channel',
subscribers: 1000,
thumbnail: 'https://example.com/channel.jpg',
...overrides,
};
}
export function createMockPlaylist(overrides = {}) {
return {
id: 'playlist123',
type: 'playlist',
: ,
: ,
: ,
: {
: ,
},
...overrides,
};
}
() {
{
: vi.(),
: vi.(),
: vi.(),
: vi.(),
: vi.(),
: vi.(),
: vi.(),
};
}
import { createMockVideo, createMockInnertube } from '@/tests/mocks/youtube-helpers';
it('should use mock helpers', async () => {
const mockInnertube = createMockInnertube();
mockInnertube.search.mockResolvedValue({
results: [createMockVideo()],
has_continuation: false,
});
const { getInnertube } = await import('@/lib/youtube');
vi.mocked(getInnertube).mockResolvedValue(mockInnertube as any);
const innertube = await getInnertube();
const results = await innertube.search('test query');
expect(results.results).toHaveLength(1);
expect(results.results[0].id).toBe('video123');
});
| Method | Description |
|---|---|
Innertube.create() | Create Innertube instance |
innertube.search() | Search for videos |
innertube.getBasicInfo() | Get video info |
innertube.getChannel() | Get channel info |
innertube.getPlaylist() | Get playlist info |
innertube.getHomeFeed() | Get home feed |
innertube.getTrending() | Get trending videos |
innertube.getSubscriptionsFeed() | Get subscriptions feed |
Related SKILLS: api-testing.md, testing-infrastructure.md, hook-testing.md