Initial TrueGrowth source import

This commit is contained in:
2026-07-07 09:36:36 +08:00
commit 3b6781d695
2283 changed files with 691996 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import type React from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { AssetItem } from './AssetItem';
import { AssetSource, AssetType, type Asset } from '../../types/asset.types';
vi.mock('tdesign-react', () => ({
Checkbox: ({ checked, onChange }: any) => (
<input
aria-label="选择资产"
type="checkbox"
checked={checked}
onChange={(event) => onChange?.(event.target.checked)}
/>
),
}));
vi.mock('../lazy-image', () => ({
LazyImage: ({ src, alt, className }: any) => (
<img src={src} alt={alt} className={className} />
),
}));
vi.mock('../shared/VideoPosterPreview', () => ({
VideoPosterPreview: ({ src, poster, alt, className }: any) => (
<img
src={poster || src}
alt={alt}
className={`video-poster-preview__media ${className || ''}`}
/>
),
}));
vi.mock('../shared/hover', () => ({
HoverTip: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}));
vi.mock('../../hooks/useAssetSize', () => ({
useAssetSize: (_id: string, _url: string, size?: number) => size,
}));
vi.mock('../../hooks/useThumbnailUrl', () => ({
useThumbnailUrl: (url: string) => url,
}));
vi.mock('../../hooks/useUnifiedCache', () => ({
useUnifiedCache: () => ({
isCached: true,
cacheWarning: undefined,
}),
}));
const baseAsset = {
source: AssetSource.LOCAL,
createdAt: 1,
size: 4096,
};
const videoAsset: Asset = {
...baseAsset,
id: 'video-asset',
type: AssetType.VIDEO,
url: '/media/demo.mp4',
thumbnail: '/media/demo-poster.jpg',
name: '视频素材',
mimeType: 'video/mp4',
};
const audioAsset: Asset = {
...baseAsset,
id: 'audio-asset',
type: AssetType.AUDIO,
url: '/media/demo.mp3',
thumbnail: '/media/demo-cover.jpg',
name: '音频素材',
mimeType: 'audio/mpeg',
};
function renderAssetItem(asset: Asset) {
return render(
<AssetItem
asset={asset}
viewMode="grid"
isSelected={false}
onSelect={vi.fn()}
/>
);
}
describe('AssetItem hover preview', () => {
beforeEach(() => {
vi.spyOn(window.HTMLMediaElement.prototype, 'play').mockResolvedValue();
vi.spyOn(window.HTMLMediaElement.prototype, 'pause').mockImplementation(
() => undefined
);
});
afterEach(() => {
vi.restoreAllMocks();
});
it('plays video on hover and restores the poster on mouse leave', async () => {
const { container } = renderAssetItem(videoAsset);
const item = container.querySelector('.asset-item') as HTMLElement;
expect(container.querySelector('.asset-item__hover-video')).toBeNull();
fireEvent.mouseEnter(item);
const hoverVideo = await waitFor(() => {
const node = container.querySelector('.asset-item__hover-video');
expect(node).toBeInstanceOf(HTMLVideoElement);
return node as HTMLVideoElement;
});
expect(hoverVideo.getAttribute('src')).toBe(videoAsset.url);
expect(hoverVideo.muted).toBe(true);
expect(hoverVideo.loop).toBe(true);
await waitFor(() => {
expect(window.HTMLMediaElement.prototype.play).toHaveBeenCalled();
});
fireEvent.mouseLeave(item);
await waitFor(() => {
expect(container.querySelector('.asset-item__hover-video')).toBeNull();
});
expect(screen.getByAltText(videoAsset.name)).not.toBeNull();
});
it('plays audio on hover and restores the cover on mouse leave', async () => {
const { container } = renderAssetItem(audioAsset);
const item = container.querySelector('.asset-item') as HTMLElement;
expect(container.querySelector('.asset-item__hover-audio')).toBeNull();
expect(screen.getByAltText(audioAsset.name)).not.toBeNull();
fireEvent.mouseEnter(item);
const hoverAudio = await waitFor(() => {
const node = container.querySelector('.asset-item__hover-audio');
expect(node).toBeInstanceOf(HTMLAudioElement);
return node as HTMLAudioElement;
});
expect(hoverAudio.getAttribute('src')).toBe(audioAsset.url);
await waitFor(() => {
expect(window.HTMLMediaElement.prototype.play).toHaveBeenCalled();
});
fireEvent.mouseLeave(item);
await waitFor(() => {
expect(container.querySelector('.asset-item__hover-audio')).toBeNull();
});
expect(screen.getByAltText(audioAsset.name)).not.toBeNull();
});
});