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',
}));
});
});