/* @vitest-environment jsdom */ import { render, screen } from '@testing-library/react'; import { createRef, type ImgHTMLAttributes } from 'react'; import { expect, test, vi } from 'vitest'; import { PlatformMediaFrame } from './PlatformMediaFrame'; vi.mock('../ResolvedAssetImage', () => ({ ResolvedAssetImage: ({ src, fallbackSrc, alt, className, refreshKey, ...imageProps }: { src?: string; fallbackSrc?: string; alt: string; className?: string; refreshKey?: string | number | null; } & ImgHTMLAttributes) => ( {alt} ), })); test('renders warm media frame with image and landscape aspect', () => { render( , ); const image = screen.getByRole('img', { name: '潮灯居' }); const frame = image.closest('div'); expect(frame?.className).toContain('platform-media-frame'); expect(frame?.className).toContain('aspect-[16/9]'); expect(frame?.className).toContain( 'border-[var(--platform-subpanel-border)]', ); expect(frame?.className).toContain('radial-gradient'); expect(image.className).toContain('object-cover'); }); test('renders fallback label when no image source is available', () => { render( , ); const fallback = screen.getByText('角色'); const frame = fallback.closest('div.relative'); expect(frame?.className).toContain('aspect-square'); expect(frame?.className).toContain('bg-[var(--platform-subpanel-fill)]'); expect(fallback.className).toContain('tracking-[0.18em]'); }); test('supports custom fallback content', () => { render( 图标} aspect="standard" surface="plain" fallbackShellClassName="bg-rainbow" fallbackClassName="tracking-normal" />, ); const fallbackIcon = screen.getByTestId('fallback-icon'); const fallback = fallbackIcon.closest('div'); const frame = fallbackIcon.closest('div.relative'); expect(fallbackIcon.textContent).toBe('图标'); expect(screen.queryByText('封面图占位')).toBeNull(); expect(fallback?.className).toContain('bg-rainbow'); expect(fallback?.className).toContain('tracking-normal'); expect(frame?.className).toContain('aspect-[4/3]'); }); test('supports soft media frame surface', () => { render( , ); const image = screen.getByRole('img', { name: '创意模板' }); const frame = image.closest('div'); expect(frame?.className).toContain('aspect-[16/9]'); expect(frame?.className).toContain( 'border-[var(--platform-subpanel-border)]', ); expect(frame?.className).toContain('bg-white/68'); }); test('supports bright media frame surface', () => { render( , ); const image = screen.getByRole('img', { name: '物品素材' }); const frame = image.closest('div'); expect(frame?.className).toContain('aspect-square'); expect(frame?.className).toContain( 'border-[var(--platform-subpanel-border)]', ); expect(frame?.className).toContain('bg-white/82'); }); test('passes div attributes to the media frame container', () => { render( , ); const frame = screen.getByTestId('match3d-preview-frame'); expect(frame.getAttribute('aria-label')).toBe('物品素材预览'); expect(frame.className).toContain('bg-white/82'); }); test('supports none surface for nested interactive shells', () => { render( , ); const image = screen.getByRole('img', { name: '缩略图' }); const frame = image.closest('div'); expect(frame?.className).toContain('aspect-square'); expect(frame?.className).toContain('rounded-[0.65rem]'); expect(frame?.className).not.toContain('border-['); expect(frame?.className).not.toContain('bg-white'); }); test('supports editor dark surface, fallback source and overlay', () => { render( 覆盖层} />, ); const image = screen.getByRole('img', { name: '第1幕' }); const frame = image.closest('div'); const overlay = screen.getByText('覆盖层').parentElement; expect(image.getAttribute('src')).toBe('/fallback.png'); expect(frame?.className).toContain('border-white/10'); expect(frame?.className).toContain('rgba(19,24,39,0.95)'); expect(overlay?.className).toContain('pointer-events-auto'); }); test('supports standard aspect, bare surface and refresh key', () => { render( , ); const image = screen.getByRole('img', { name: '雨夜猫街' }); const frame = image.closest('div'); expect(frame?.className).toContain('aspect-[4/3]'); expect(frame?.className).toContain('bg-[var(--platform-subpanel-fill)]'); expect(frame?.className).not.toContain('border'); expect(image.getAttribute('data-refresh-key')).toBe('session-1:level-1'); }); test('supports portrait aspect for vertical preview assets', () => { render( , ); const image = screen.getByRole('img', { name: '场地底图' }); const frame = image.closest('div'); expect(frame?.className).toContain('aspect-[9/16]'); expect(frame?.className).toContain('bg-white/80'); expect(frame?.className).toContain('rounded-none'); }); test('supports wide aspect for broad preview assets', () => { render( , ); const image = screen.getByRole('img', { name: '大鱼素材候选' }); const frame = image.closest('div'); expect(frame?.className).toContain('aspect-[9/5]'); expect(frame?.className).toContain( 'border-[var(--platform-subpanel-border)]', ); }); test('supports auto aspect, image props and container refs', () => { const frameRef = createRef(); render( , ); const frame = screen.getByTestId('cover-crop-frame'); const image = screen.getByRole('img', { name: '封面裁剪预览' }); expect(frameRef.current).toBe(frame); expect(frame.className).toContain('platform-media-frame'); expect(frame.className).not.toContain('aspect-['); expect(frame.className).not.toContain('aspect-square'); expect(image.getAttribute('draggable')).toBe('false'); expect(image.getAttribute('style')).toContain('left: -10%'); expect(image.className).toContain('absolute max-w-none object-fill'); });