visual-journal / src /components /workbench-pro-dock.test.tsx
Visual Journal deploy
Deploy 5554830 to Docker Space
e4e0afe
Raw
History Blame Contribute Delete
22.5 kB
import { WorkbenchProDock } from './workbench-pro-dock';
import { I18nProvider } from '@/lib/i18n';
import { isImageUpstreamStreamingStrategySelectable } from '@/lib/image-upstream-form';
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import * as React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
const setOutputFormat: React.Dispatch<React.SetStateAction<'png' | 'jpeg' | 'webp'>> = () => {};
const setQuality: React.Dispatch<React.SetStateAction<'low' | 'medium' | 'high' | 'auto'>> = () => {};
const setModel: React.Dispatch<
React.SetStateAction<'gpt-image-2' | 'gpt-image-1.5' | 'gpt-image-1' | 'gpt-image-1-mini'>
> = () => {};
const setStreamMode: React.Dispatch<React.SetStateAction<'auto' | 'stream' | 'non_stream'>> = () => {};
const setEnableParallelBatch: React.Dispatch<React.SetStateAction<boolean>> = () => {};
const setImageBackend: React.Dispatch<
React.SetStateAction<'server-default' | 'images-api' | 'responses-image-generation'>
> = () => {};
const setStreamingStrategy: React.Dispatch<
React.SetStateAction<
'server-default' | 'auto' | 'off' | 'openai-sse' | 'newapi-keepalive-sse' | 'responses-sse' | 'force-sse'
>
> = () => {};
const setResponsesModel: React.Dispatch<React.SetStateAction<string>> = () => {};
function assertProParallelBatchCheckboxDisabled(html: string) {
assert.match(
html,
/<button[^>]*(?:disabled=""[^>]*id="pro-parallel-batch-enabled"|id="pro-parallel-batch-enabled"[^>]*disabled="")/
);
}
describe('WorkbenchProDock', () => {
it('uses the shared upstream compatibility rule for professional route strategies', () => {
assert.equal(
isImageUpstreamStreamingStrategySelectable({
imageBackend: 'responses-image-generation',
streamingStrategy: 'openai-sse',
allowResponsesImageBackend: true
}),
false
);
assert.equal(
isImageUpstreamStreamingStrategySelectable({
imageBackend: 'server-default',
streamingStrategy: 'responses-sse',
allowResponsesImageBackend: true
}),
false
);
});
it('defaults to easy mode and keeps professional controls collapsed', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
/>
</I18nProvider>
);
assert.match(html, /省心模式/);
assert.match(html, /专业模式/);
assert.match(html, /workbench-panel/);
assert.match(html, /mt-4/);
assert.match(html, /rounded-lg/);
assert.match(html, /xl:max-h-80/);
assert.match(html, /xl:overflow-y-auto/);
assert.match(html, /aria-pressed="true"[^>]*>省心模式/);
assert.match(html, /输出格式/);
assert.match(html, /gpt-image-2/);
assert.doesNotMatch(html, /pro-output-format-select/);
assert.doesNotMatch(html, /水印/);
assert.doesNotMatch(html, /EXIF/);
});
it('uses the shared localized label for a custom resolution', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='custom'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
/>
</I18nProvider>
);
assert.match(html, /自定义/);
});
it('renders interactive professional groups without fake output switches', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
/>
</I18nProvider>
);
for (const label of ['输出', '模型', '流式', '路由', '输出格式', '清晰度', '色彩空间', '分辨率']) {
assert.match(html, new RegExp(label));
}
assert.match(html, /aria-pressed="true"[^>]*>专业模式/);
assert.match(html, /pro-output-format-select/);
assert.match(html, /pro-quality-select/);
assert.doesNotMatch(html, /水印/);
assert.doesNotMatch(html, /EXIF/);
});
it('renders route controls as real professional selectors', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend
upstreamProfileMixed
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='route'
/>
</I18nProvider>
);
assert.match(html, /pro-image-backend-select/);
assert.match(html, /pro-streaming-strategy-select/);
assert.match(html, /图片生成后端/);
assert.match(html, /流式兼容模式/);
assert.match(html, /影响说明/);
assert.match(html, /服务端默认会沿用当前部署配置/);
assert.match(html, /当前服务端渠道包含不同上游模式/);
assert.match(html, /费用主要由模型、尺寸、数量和预览图数量决定/);
});
it('explains the resolved desktop server default streaming strategy', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='off'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='route'
/>
</I18nProvider>
);
assert.match(html, /关闭流式会减少长连接不稳定因素/);
assert.doesNotMatch(html, /自动或服务端默认会优先使用当前推荐的流式策略/);
});
it('disables the experimental Responses backend when runtime capabilities do not allow it', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend={false}
hasDefaultResponsesModel={false}
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='route'
/>
</I18nProvider>
);
assert.match(html, /当前运行时或默认服务器渠道未开放 Responses image_generation/);
assert.doesNotMatch(html, /GPT 顶层模型/);
});
it('renders a desktop parallel batch switch in stream settings', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={true}
enableParallelBatch={true}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={2}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='stream'
/>
</I18nProvider>
);
assert.match(html, /pro-parallel-batch-enabled/);
assert.match(html, /并发批量/);
assert.match(html, /多张图或多条提示词会按当前渠道容量并发执行/);
assert.match(html, /aria-checked="true"/);
});
it('keeps enabled parallel batch visible in easy mode summary', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={true}
enableParallelBatch={true}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={2}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
/>
</I18nProvider>
);
assert.match(html, /自动 \/ 并发已启用/);
});
it('keeps the desktop parallel batch switch disabled when streaming strategy is off', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={true}
enableParallelBatch={true}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={2}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='off'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='stream'
/>
</I18nProvider>
);
assert.match(html, /pro-parallel-batch-enabled/);
assert.match(html, /并发批量需要流式模式;非流式会保持顺序执行。/);
assert.match(html, /aria-checked="false"/);
assertProParallelBatchCheckboxDisabled(html);
});
it('keeps the desktop parallel batch switch disabled when the server default streaming strategy is off', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={true}
enableParallelBatch={true}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={2}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='off'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='stream'
/>
</I18nProvider>
);
assert.match(html, /pro-parallel-batch-enabled/);
assert.match(html, /并发批量需要流式模式;非流式会保持顺序执行。/);
assert.match(html, /aria-checked="false"/);
assertProParallelBatchCheckboxDisabled(html);
});
it('disables the desktop stream mode selector when the server default streaming strategy is off', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={true}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={2}
allowResponsesImageBackend
hasDefaultResponsesModel
imageBackend='server-default'
onImageBackendChange={setImageBackend}
streamingStrategy='server-default'
defaultStreamingStrategy='off'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='stream'
/>
</I18nProvider>
);
assert.match(
html,
/<button[^>]*(?:disabled=""[^>]*id="pro-stream-mode-select"|id="pro-stream-mode-select"[^>]*disabled="")/
);
});
it('renders a desktop Responses top-level model input when the Responses backend is selected', () => {
const html = renderToStaticMarkup(
<I18nProvider>
<WorkbenchProDock
outputFormat='png'
onOutputFormatChange={setOutputFormat}
quality='high'
onQualityChange={setQuality}
model='gpt-image-2'
onModelChange={setModel}
size='auto'
streamMode='auto'
onStreamModeChange={setStreamMode}
allowStreamingBatch={false}
enableParallelBatch={false}
onEnableParallelBatchChange={setEnableParallelBatch}
parallelBatchTargetCount={1}
allowResponsesImageBackend
hasDefaultResponsesModel={false}
imageBackend='responses-image-generation'
onImageBackendChange={setImageBackend}
streamingStrategy='responses-sse'
defaultStreamingStrategy='auto'
onStreamingStrategyChange={setStreamingStrategy}
responsesModel=''
onResponsesModelChange={setResponsesModel}
defaultMode='pro'
defaultProTab='route'
/>
</I18nProvider>
);
assert.match(html, /pro-responses-model-input/);
assert.match(html, /GPT 顶层模型/);
assert.match(html, /Responses image_generation 需要填写 GPT 顶层模型/);
assert.match(html, /col-span-full grid grid-cols-1 gap-2/);
assert.match(html, /sm:grid-cols-2/);
assert.doesNotMatch(html, /md:grid-cols-\[auto_1fr_1fr_1fr\]/);
});
});