/* @vitest-environment jsdom */ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { afterEach, describe, expect, test, vi } from 'vitest'; import * as clipboardService from '../../services/clipboard'; import { useCopyFeedback } from './useCopyFeedback'; vi.mock('../../services/clipboard', () => ({ copyTextToClipboard: vi.fn(), })); function CopyFeedbackHarness({ value, resetDelayMs = 1400, }: { value: string; resetDelayMs?: number; }) { const { copyState, copyText, resetCopyState } = useCopyFeedback({ resetDelayMs, }); return (
{copyState}
); } afterEach(() => { vi.clearAllMocks(); vi.useRealTimers(); }); describe('useCopyFeedback', () => { test('copies text and resets after the feedback delay', async () => { vi.useFakeTimers(); vi.mocked(clipboardService.copyTextToClipboard).mockResolvedValue(true); render(); fireEvent.click(screen.getByRole('button', { name: '复制' })); await act(async () => { await Promise.resolve(); }); expect(screen.getByTestId('copy-state').textContent).toBe('copied'); expect(clipboardService.copyTextToClipboard).toHaveBeenCalledWith( '作品号:PZ-1', ); act(() => { vi.advanceTimersByTime(10); }); expect(screen.getByTestId('copy-state').textContent).toBe('idle'); }); test('keeps failure state until reset or timeout', async () => { vi.mocked(clipboardService.copyTextToClipboard).mockResolvedValue(false); render(); fireEvent.click(screen.getByRole('button', { name: '复制' })); await waitFor(() => { expect(screen.getByTestId('copy-state').textContent).toBe('failed'); }); fireEvent.click(screen.getByRole('button', { name: '重置' })); expect(screen.getByTestId('copy-state').textContent).toBe('idle'); }); });