119 lines
4.7 KiB
TypeScript
119 lines
4.7 KiB
TypeScript
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(
|
|
<ApiDocsPage
|
|
activeDocSection={activeDocSection}
|
|
apiKeySecretsById={{}}
|
|
apiKeys={[]}
|
|
canRun
|
|
coreMessage=""
|
|
coreState="idle"
|
|
selectedApiKeyId=""
|
|
taskForm={taskForm}
|
|
taskResult={null}
|
|
onApiKeyChange={vi.fn()}
|
|
onCreateApiKey={vi.fn()}
|
|
onDocSectionChange={vi.fn()}
|
|
onLogin={vi.fn()}
|
|
onSubmitTask={vi.fn()}
|
|
onTaskFormChange={vi.fn()}
|
|
/>,
|
|
);
|
|
}
|