/* @vitest-environment jsdom */ import { fireEvent, render, screen, within } from '@testing-library/react'; import { useState } from 'react'; import { describe, expect, it, vi } from 'vitest'; import type { GenerateDialogState } from './ImageCanvasEditorTypes'; import { ImageCanvasGenerationImageOptionsView } from './ImageCanvasGenerationImageOptionsView'; import { calculateEditorImageGenerationPrice, IMAGE_MODEL_GPT_IMAGE_2, IMAGE_MODEL_NANOBANANA2, } from './ImageCanvasGenerationModel'; function ImageOptionsHarness({ initialDialog, includeDimensions = true, onRememberImageModel = vi.fn(), lockedModel, }: { initialDialog: GenerateDialogState; includeDimensions?: boolean; onRememberImageModel?: (model: string) => void; lockedModel?: string; }) { const [dialog, setDialog] = useState( initialDialog, ); return dialog ? (
{dialog.imageModel} {dialog.aspectRatio} {dialog.imageSize} {dialog.status} {dialog.errorMessage ?? '-'} {dialog.placeholder ? [ dialog.placeholder.x, dialog.placeholder.y, dialog.placeholder.width, dialog.placeholder.height, dialog.placeholder.originalWidth, dialog.placeholder.originalHeight, ].join(':') : '-'}
) : null; } describe('ImageCanvasGenerationImageOptionsView', () => { it('updates dimensions from a menu, keeps the menu open and marks the selection', () => { render( , ); fireEvent.click( screen.getByRole('button', { name: '生成图片尺寸 1:1·1K' }), ); const panel = screen.getByRole('menu', { name: '生成图片尺寸选项' }); fireEvent.click(within(panel).getByRole('button', { name: '16:9' })); fireEvent.click(within(panel).getByRole('button', { name: '2K' })); expect(screen.getByRole('menu', { name: '生成图片尺寸选项' })).toBeTruthy(); expect( within(panel) .getByRole('button', { name: '16:9' }) .getAttribute('aria-pressed'), ).toBe('true'); expect( within(panel) .getByRole('button', { name: '2K' }) .getAttribute('aria-pressed'), ).toBe('true'); expect( screen.getByRole('button', { name: '生成图片尺寸 16:9·2K' }), ).toBeTruthy(); expect(screen.getByLabelText('当前比例').textContent).toBe('16:9'); expect(screen.getByLabelText('当前尺寸').textContent).toBe('2K'); expect(screen.getByLabelText('当前状态').textContent).toBe('idle'); expect(screen.getByLabelText('当前错误').textContent).toBe('-'); }); it('closes option panels when clicking parent panel outside trigger buttons', () => { render( , ); fireEvent.click( screen.getByRole('button', { name: '生成图片尺寸 1:1·1K' }), ); expect(screen.getByRole('menu', { name: '生成图片尺寸选项' })).toBeTruthy(); fireEvent.click(screen.getByLabelText('当前模型')); expect(screen.queryByRole('menu', { name: '生成图片尺寸选项' })).toBeNull(); }); it('renders model choices as one model per row and uses a check mark for selection', () => { const rememberImageModel = vi.fn(); render( , ); fireEvent.click( screen.getByRole('button', { name: '生成图片模型 nanobanana2' }), ); const panel = screen.getByRole('menu', { name: '生成图片模型选项' }); expect( within(panel).getByRole('button', { name: 'nanobanana2' }), ).toBeTruthy(); fireEvent.click(within(panel).getByRole('button', { name: 'gpt-image-2' })); expect(screen.getByRole('menu', { name: '生成图片模型选项' })).toBeTruthy(); expect(rememberImageModel).toHaveBeenCalledWith(IMAGE_MODEL_GPT_IMAGE_2); expect(screen.getByLabelText('当前模型').textContent).toBe( IMAGE_MODEL_GPT_IMAGE_2, ); expect(screen.getByLabelText('当前比例').textContent).toBe('9:16'); expect(screen.getByLabelText('当前尺寸').textContent).toBe('1K'); expect( screen.getByRole('button', { name: '生成图片模型 gpt-image-2' }), ).toBeTruthy(); expect( screen.getByRole('button', { name: '生成角色形象' }).textContent, ).toBe('生成3泥点'); }); it('locks the model trigger when a fixed model is provided', () => { const rememberImageModel = vi.fn(); render( , ); const modelButton = screen.getByRole('button', { name: '生成图片模型 gpt-image-2', }) as HTMLButtonElement; expect(modelButton.disabled).toBe(true); expect(modelButton.closest('div')?.className).toContain( 'image-canvas-editor__readonly-generation-option', ); expect(modelButton.textContent).not.toContain('nanobanana2'); fireEvent.click(modelButton); expect(screen.queryByRole('menu', { name: '生成图片模型选项' })).toBeNull(); expect(rememberImageModel).not.toHaveBeenCalled(); }); it('renders option menus and shows mud point text in the submit button', () => { render( , ); fireEvent.click( screen.getByRole('button', { name: '生成图片尺寸 1:1·1K' }), ); expect(screen.getByRole('menu', { name: '生成图片尺寸选项' })).toBeTruthy(); const submit = screen.getByRole('button', { name: '生成角色形象' }); expect(submit.textContent).toBe('生成12泥点'); }); it('keeps fixed-card placeholders unchanged when model-only controls are shown', () => { render( , ); expect(screen.queryByRole('button', { name: /生成图片尺寸/u })).toBeNull(); fireEvent.click( screen.getByRole('button', { name: '生成图片模型 nanobanana2' }), ); fireEvent.click( within(screen.getByRole('menu', { name: '生成图片模型选项' })).getByRole( 'button', { name: 'gpt-image-2' }, ), ); expect(screen.getByLabelText('当前模型').textContent).toBe( IMAGE_MODEL_GPT_IMAGE_2, ); expect(screen.getByLabelText('当前比例').textContent).toBe('4:3'); expect(screen.getByLabelText('当前尺寸').textContent).toBe('1K'); expect(screen.getByLabelText('当前占位').textContent).toBe( '120:160:720:540:720:540', ); }); it('keeps the canvas placeholder centered while syncing its ratio and size selection', () => { render( , ); fireEvent.click( screen.getByRole('button', { name: '生成图片尺寸 1:1·1K' }), ); const panel = screen.getByRole('menu', { name: '生成图片尺寸选项' }); fireEvent.click(within(panel).getByRole('button', { name: '16:9' })); fireEvent.click(within(panel).getByRole('button', { name: '2K' })); expect(screen.getByLabelText('当前占位').textContent).toBe( '-714:-166:2048:1152:2048:1152', ); }); });