99 lines
2.7 KiB
TypeScript
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();
|
|
});
|