Files
Genarrative/src/components/puzzle-gallery/PuzzleGalleryDetailView.test.tsx

99 lines
2.7 KiB
TypeScript

/* @vitest-environment jsdom */
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { afterEach, expect, test, vi } from 'vitest';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
import { PuzzleGalleryDetailView } from './PuzzleGalleryDetailView';
vi.mock('../ResolvedAssetImage', () => ({
ResolvedAssetImage: () => null,
}));
const originalClipboard = navigator.clipboard;
const detailItem = {
workId: 'puzzle-work-public-1',
profileId: 'puzzle-profile-public-1',
ownerUserId: 'user-2',
sourceSessionId: 'puzzle-session-1',
authorDisplayName: '拼图玩家',
levelName: '奇幻拼图',
summary: '一张用于公开分享的拼图作品。',
themeTags: ['奇幻'],
coverImageSrc: null,
coverAssetId: null,
publicationStatus: 'published',
updatedAt: '2026-04-25T10:00:00.000Z',
publishedAt: '2026-04-25T10:00:00.000Z',
playCount: 7,
publishReady: true,
} satisfies PuzzleWorkSummary;
afterEach(() => {
vi.clearAllMocks();
Object.defineProperty(navigator, 'clipboard', {
configurable: true,
value: originalClipboard,
});
});
test('shows and copies puzzle public work code in detail view', async () => {
const user = userEvent.setup();
const writeText = vi.fn(async () => undefined);
Object.defineProperty(navigator, 'clipboard', {
configurable: true,
value: { writeText },
});
render(
<PuzzleGalleryDetailView
item={detailItem}
onBack={vi.fn()}
onStartGame={vi.fn()}
/>,
);
expect(screen.getByText('作品号')).toBeTruthy();
expect(screen.getByText('PZ-EPUBLIC1')).toBeTruthy();
await user.click(
screen.getByRole('button', { name: '复制作品号 PZ-EPUBLIC1' }),
);
expect(writeText).toHaveBeenCalledWith('PZ-EPUBLIC1');
});
test('falls back to legacy selection copy when clipboard api rejects', async () => {
const user = userEvent.setup();
const writeText = vi.fn(async () => {
throw new Error('clipboard denied');
});
const execCommand = vi.fn(() => true);
Object.defineProperty(navigator, 'clipboard', {
configurable: true,
value: { writeText },
});
Object.defineProperty(document, 'execCommand', {
configurable: true,
value: execCommand,
});
render(
<PuzzleGalleryDetailView
item={detailItem}
onBack={vi.fn()}
onStartGame={vi.fn()}
/>,
);
await user.click(
screen.getByRole('button', { name: '复制作品号 PZ-EPUBLIC1' }),
);
expect(writeText).toHaveBeenCalledWith('PZ-EPUBLIC1');
expect(execCommand).toHaveBeenCalledWith('copy');
expect(await screen.findByText('已复制')).toBeTruthy();
});