import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { SidebarUpdateButton } from '@/components/layout/SidebarUpdateButton'; import { useUpdateStore } from '@/stores/update'; const toastError = vi.hoisted(() => vi.fn()); vi.mock('sonner', () => ({ toast: { error: toastError, success: vi.fn() } })); describe('SidebarUpdateButton', () => { const init = vi.fn().mockResolvedValue(undefined); const downloadUpdate = vi.fn().mockResolvedValue(undefined); const installUpdate = vi.fn(); beforeEach(() => { vi.clearAllMocks(); downloadUpdate.mockResolvedValue(undefined); useUpdateStore.setState({ status: 'idle', currentVersion: '0.9.1', updateInfo: null, progress: null, error: null, isInitialized: true, isInitializing: false, autoInstallCountdown: null, init, downloadUpdate, installUpdate, }); }); it.each(['idle', 'checking', 'not-available', 'error'] as const)( 'stays hidden while the update status is %s', (status) => { useUpdateStore.setState({ status }); render(); expect(screen.queryByTestId('sidebar-update-button')).not.toBeInTheDocument(); }, ); it('initializes update discovery even while the control is hidden', async () => { render(); expect(screen.queryByTestId('sidebar-update-button')).not.toBeInTheDocument(); await waitFor(() => expect(init).toHaveBeenCalledTimes(1)); }); it('shows the download action when an update is available', () => { useUpdateStore.setState({ status: 'available', updateInfo: { version: '0.9.2' } }); render(); expect(screen.getByTestId('sidebar-update-button')).toHaveAccessibleName('下载新版本 0.9.2'); }); it('downloads an available version on the first click', async () => { useUpdateStore.setState({ status: 'available', updateInfo: { version: '0.9.2' } }); render(); fireEvent.click(screen.getByRole('button', { name: '下载新版本 0.9.2' })); await waitFor(() => expect(downloadUpdate).toHaveBeenCalledTimes(1)); expect(installUpdate).not.toHaveBeenCalled(); }); it('disables duplicate actions while downloading', () => { useUpdateStore.setState({ status: 'downloading', updateInfo: { version: '0.9.2' } }); render(); expect(screen.getByTestId('sidebar-update-button')).toBeDisabled(); expect(screen.getByTestId('sidebar-update-button')).toHaveAccessibleName('正在下载新版本 0.9.2'); }); it('installs only after the update is downloaded', () => { useUpdateStore.setState({ status: 'downloaded', updateInfo: { version: '0.9.2' } }); render(); fireEvent.click(screen.getByRole('button', { name: '重启并安装新版本 0.9.2' })); expect(installUpdate).toHaveBeenCalledTimes(1); expect(downloadUpdate).not.toHaveBeenCalled(); }); it('shows a bounded toast when download fails', async () => { downloadUpdate.mockImplementationOnce(async () => { useUpdateStore.setState({ status: 'error', error: 'Remote update download failed' }); }); useUpdateStore.setState({ status: 'available', updateInfo: { version: '0.9.2' } }); render(); fireEvent.click(screen.getByRole('button', { name: '下载新版本 0.9.2' })); await waitFor(() => expect(toastError).toHaveBeenCalledWith('更新下载失败', { description: 'Remote update download failed', })); }); });