import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it, vi } from 'vitest'; import type { ApiDocSection, TaskForm } from '../types'; import { ApiDocsPage } from './ApiDocsPage'; describe('ApiDocsPage extended task documentation', () => { it.each([ ['guideBaseUrl', '前往创建 API Key'], ['guideWebhook', 'TASK_PROGRESS_CALLBACK_ENABLED'], ['guideErrors', '400 invalid_parameter'], ['guideTesting', 'simulated=true'], ] as const)('renders the clickable guide page %s', (section, expectedContent) => { const html = renderDocs(section, { kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '你好' }); expect(html).toContain('data-active="true"'); expect(html).toContain(expectedContent); expect(html).toContain('指南导航'); expect(html).not.toContain('/v1/chat/completions'); }); it('documents the OpenAI-compatible Responses request and continuity fields', () => { const html = renderDocs('responses', { kind: 'responses', model: 'gpt-4o-mini', prompt: '你好' }); expect(html).toContain('/v1/responses'); expect(html).toContain('previous_response_id'); expect(html).toContain('X-Async'); expect(html).toContain('连续对话与状态归属'); }); it('documents video generation parameters and async retrieval guidance', () => { const html = renderDocs('videoGeneration', { kind: 'videos.generations', model: '豆包Seedance-2.0', prompt: '雪山日出' }); expect(html).toContain('/api/v1/videos/generations'); expect(html).toContain('aspect_ratio'); expect(html).toContain('reference_image'); expect(html).toContain('任务取回接口'); }); it('defaults the online runner to test mode and offers an explicit real submission mode', () => { const html = renderDocs('imageEdit', { kind: 'images.edits', model: 'gpt-image-1', prompt: '移除背景' }); expect(html).toContain('运行模式'); expect(html).toContain('测试模式'); expect(html).toContain('真实提交'); expect(html).toContain('aria-pressed="true"'); expect(html).toContain('"runMode": "simulation"'); expect(html).toContain('"simulation": true'); }); it('documents async mode as a body-independent capability', () => { const html = renderDocs('asyncMode', { kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '你好' }); expect(html).toContain('X-Async'); expect(html).toContain('原请求 Header'); expect(html).toContain('同步与异步的区别'); expect(html).toContain('异步受理响应'); expect(html).not.toContain('/api/v1/videos/generations'); expect(html).not.toContain('Body 参数'); expect(html).not.toContain('视频模型 ID'); }); it.each(['chat', 'responses', 'embeddings', 'reranks', 'imageGeneration', 'imageEdit', 'videoGeneration'] as const)( 'shows the shared X-Async switch on the %s task API', (section) => { const html = renderDocs(section, { kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '你好' }); expect(html).toContain('X-Async'); }, ); it('renders nested objects and object arrays recursively', () => { const html = renderDocs('videoGeneration', { kind: 'videos.generations', model: '豆包Seedance-2.0', prompt: '雪山日出' }); expect(html).toContain('array<object>'); expect(html).toContain('data-depth="1"'); expect(html).toContain('data-depth="4"'); expect(html).toContain('inline_element'); expect(html).toContain('refer_images'); expect(html).toContain('slot_key'); }); it('renders task retrieval as GET with a path parameter instead of a request body', () => { const html = renderDocs('taskRetrieve', { kind: 'tasks.retrieve', model: 'task', prompt: '', taskId: 'task-123' }); expect(html).toContain('GET'); expect(html).toContain('/api/v1/tasks/task-123'); expect(html).toContain('Path 参数'); expect(html).toContain('响应 Body'); expect(html).toContain('result'); expect(html).toContain('billingSummary'); expect(html).toContain('attempts'); expect(html).toContain('成功响应示例'); expect(html).toContain('Task ID'); expect(html).not.toContain('请求 Body'); }); }); function renderDocs(activeDocSection: ApiDocSection, taskForm: TaskForm) { return renderToStaticMarkup( , ); }