import { cleanup, fireEvent, screen, waitFor } from '@testing-library/react'; import { renderWithIntl } from '@/utils/test/renderWithIntl'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import UpdateSnapshotButton from './UpdateSnapshotButton'; const mocks = vi.hoisted(() => ({ createOrUpdateSnapshot: vi.fn(), refresh: vi.fn(), })); vi.mock('@/app/(authenticated)/shared/lib/actions', () => ({ createOrUpdateSnapshot: mocks.createOrUpdateSnapshot, })); vi.mock('next/navigation', () => ({ useRouter: () => ({ refresh: mocks.refresh }), })); describe('UpdateSnapshotButton', () => { beforeEach(() => { cleanup(); vi.clearAllMocks(); mocks.createOrUpdateSnapshot.mockResolvedValue(undefined); }); it('updates the snapshot and refreshes the route on click', async () => { renderWithIntl(); fireEvent.click(screen.getByRole('button')); await waitFor(() => expect(screen.getByText('Updated!')).toBeInTheDocument()); expect(mocks.createOrUpdateSnapshot).toHaveBeenCalledWith('share-1'); expect(mocks.refresh).toHaveBeenCalledOnce(); }); it('disables the button while the update is in flight', async () => { let finish: () => void = () => {}; mocks.createOrUpdateSnapshot.mockReturnValue( new Promise((resolve) => { finish = resolve; }), ); renderWithIntl(); const button = screen.getByRole('button'); fireEvent.click(button); await waitFor(() => expect(button).toBeDisabled()); finish(); await waitFor(() => expect(button).toBeEnabled()); }); it('keeps the button usable when the action fails', async () => { const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}); mocks.createOrUpdateSnapshot.mockRejectedValue(new Error('boom')); renderWithIntl(); fireEvent.click(screen.getByRole('button')); await waitFor(() => expect(consoleError).toHaveBeenCalled()); expect(screen.queryByText('Updated!')).not.toBeInTheDocument(); expect(screen.getByRole('button')).toBeEnabled(); expect(mocks.refresh).not.toHaveBeenCalled(); consoleError.mockRestore(); }); it('shows the formatted snapshot date when provided', () => { const date = new Date('2026-03-04T10:30:00Z'); renderWithIntl(); const expected = new Intl.DateTimeFormat(undefined, { dateStyle: 'short', timeStyle: 'short', }).format(date); expect(screen.getByText(`Snapshot: ${expected}`)).toBeInTheDocument(); }); it('omits the snapshot date when there is none', () => { renderWithIntl(); expect(screen.queryByText(/^Snapshot:/)).not.toBeInTheDocument(); }); it('renders the table variant as an icon-only button', () => { renderWithIntl(); expect(screen.getByTitle('Update')).toBeInTheDocument(); // No visible label: the title attribute is the only accessible name. expect(screen.queryByText('Update')).not.toBeInTheDocument(); }); });