diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ImageAssetSelector.tsx b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ImageAssetSelector.tsx index 0e44b2406..6ec0e1517 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ImageAssetSelector.tsx +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ImageAssetSelector.tsx @@ -3,7 +3,6 @@ import { useState } from 'react'; import { ThemedModal } from '../../../../../components/modal/ThemedModal'; import type { SpriteAsset } from '../../../../../features/ui-editor/types/SpriteAsset'; -import { ComponentField } from './ComponentField'; export function ImageAssetSelector({ value, @@ -50,7 +49,8 @@ export function ImageAssetSelector({ return ( <> - +
+ 目标素材
- +
= {}, +) { + return render( + , + ); +} + +describe('ImageAssetSelector', () => { + afterEach(() => cleanup()); + + it('selects a sprite and clears the selection from the modal', async () => { + const user = userEvent.setup(); + const onChange = vi.fn(); + renderSelector(null, onChange); + + await user.click(screen.getByRole('button', { name: '选择素材' })); + expect(screen.getByRole('dialog', { name: '选择图片素材' })).toBeTruthy(); + await user.click(screen.getByRole('button', { name: /主角/ })); + expect(onChange).toHaveBeenCalledWith('hero'); + expect(screen.queryByRole('dialog')).toBeNull(); + + await user.click(screen.getByRole('button', { name: '选择素材' })); + await user.click(screen.getByRole('button', { name: /清除选择/ })); + expect(onChange).toHaveBeenLastCalledWith(null); + }); + + it('shows preview images, placeholders, and invalid references', async () => { + const user = userEvent.setup(); + renderSelector('missing', vi.fn(), { hero: 'data:image/png;base64,abc' }); + + expect(screen.getByText('素材不存在(missing)')).toBeTruthy(); + await user.click(screen.getByRole('button', { name: '更换素材' })); + const dialog = screen.getByRole('dialog', { name: '选择图片素材' }); + expect(within(dialog).getByAltText('主角')).toBeTruthy(); + expect(within(dialog).getByText('素材不存在')).toBeTruthy(); + expect( + within(dialog).getByRole('button', { name: /清除选择/ }), + ).toBeTruthy(); + }); + + it('cannot open while read only', () => { + render( + , + ); + + expect(screen.getByRole('button', { name: '更换素材' })).toHaveProperty( + 'disabled', + true, + ); + }); + + it('supports keyboard activation for sprite cards', async () => { + const user = userEvent.setup(); + const onChange = vi.fn(); + renderSelector(null, onChange); + await user.click(screen.getByRole('button', { name: '选择素材' })); + const hero = screen.getByRole('button', { name: /主角/ }); + hero.focus(); + await user.keyboard('{Enter}'); + expect(onChange).toHaveBeenCalledWith('hero'); + }); +});