/** * @license * Copyright 2025 AionUi (aionui.com) * SPDX-License-Identifier: Apache-2.0 */ import React from 'react'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import type { AutoUpdateStatus, UpdateDownloadProgressEvent, UpdateDownloadRequest } from '@/common/update/updateTypes'; const mocks = vi.hoisted(() => ({ manualProgressHandler: null as ((evt: UpdateDownloadProgressEvent) => void) | null, autoStatusHandler: null as ((evt: AutoUpdateStatus) => void) | null, autoUpdateCheckMock: vi.fn(), autoUpdateRestoreDownloadedMock: vi.fn(), updateCheckMock: vi.fn(), updateDownloadMock: vi.fn(), })); vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }), })); vi.mock('@/renderer/components/base/AionModal', () => ({ default: ({ children, visible }: { children: React.ReactNode; visible: boolean }) => visible ?
{children}
: null, })); vi.mock('@/renderer/components/Markdown', () => ({ default: ({ children }: { children: React.ReactNode }) =>
{children}
, })); vi.mock('@/common', () => ({ ipcBridge: { autoUpdate: { check: { invoke: mocks.autoUpdateCheckMock }, restoreDownloaded: { invoke: mocks.autoUpdateRestoreDownloadedMock }, download: { invoke: vi.fn() }, quitAndInstall: { invoke: vi.fn() }, status: { on: vi.fn((handler: (evt: AutoUpdateStatus) => void) => { mocks.autoStatusHandler = handler; return vi.fn(); }), }, }, update: { check: { invoke: mocks.updateCheckMock }, download: { invoke: mocks.updateDownloadMock }, downloadProgress: { on: vi.fn((handler: (evt: UpdateDownloadProgressEvent) => void) => { mocks.manualProgressHandler = handler; return vi.fn(); }), }, consumeInstallerLastFailure: { invoke: vi.fn().mockResolvedValue({ success: true, data: null }) }, open: { on: vi.fn(() => vi.fn()) }, }, shell: { openExternal: { invoke: vi.fn() }, openFile: { invoke: vi.fn() }, showItemInFolder: { invoke: vi.fn() }, }, }, })); import UpdateModal from '@/renderer/components/settings/UpdateModal'; describe('UpdateModal manual install fallback', () => { beforeEach(() => { vi.stubGlobal('__APP_VERSION__', '2.1.15'); mocks.manualProgressHandler = null; mocks.autoStatusHandler = null; mocks.autoUpdateCheckMock.mockResolvedValue({ success: true }); mocks.autoUpdateRestoreDownloadedMock.mockResolvedValue({ success: true, data: { ready: false } }); mocks.updateCheckMock.mockResolvedValue({ success: true, data: { currentVersion: '2.1.13', updateAvailable: true, latest: { tagName: 'v2.1.14', version: '2.1.14', name: 'v2.1.14', body: 'notes', htmlUrl: 'https://github.com/iOfficeAI/AionUi/releases/tag/v2.1.14', prerelease: false, draft: false, assets: [], recommendedAsset: { name: 'AionUi-2.1.14-mac-arm64.dmg', url: 'https://static.aionui.com/releases/2.1.14/AionUi-2.1.14-mac-arm64.dmg', fallbackUrl: 'https://github.com/iOfficeAI/AionUi/releases/download/v2.1.14/AionUi-2.1.14-mac-arm64.dmg', size: 123, }, }, }, }); mocks.updateDownloadMock.mockImplementation(async (request: UpdateDownloadRequest) => { const downloadId = request.downloadId ?? 'missing-download-id'; mocks.manualProgressHandler?.({ downloadId, status: 'completed', receivedBytes: 123, totalBytes: 123, percent: 100, file_path: '/tmp/AionUi-2.1.14-mac-arm64.dmg', }); return { success: true, data: { downloadId, file_path: '/tmp/AionUi-2.1.14-mac-arm64.dmg', }, }; }); }); afterEach(() => { cleanup(); vi.clearAllMocks(); vi.unstubAllGlobals(); }); it('keeps fast manual download completion matched to the caller-provided download id', async () => { const user = userEvent.setup(); render(); act(() => { window.dispatchEvent(new Event('aionui-open-update-modal')); }); const downloadAndInstall = await screen.findByText('update.downloadButton'); await user.click(downloadAndInstall); await waitFor(() => { expect(screen.getByText('update.restartNow')).toBeInTheDocument(); }); expect(mocks.updateDownloadMock).toHaveBeenCalledWith({ downloadId: expect.any(String), url: 'https://static.aionui.com/releases/2.1.14/AionUi-2.1.14-mac-arm64.dmg', fallbackUrl: 'https://github.com/iOfficeAI/AionUi/releases/download/v2.1.14/AionUi-2.1.14-mac-arm64.dmg', file_name: 'AionUi-2.1.14-mac-arm64.dmg', }); expect(screen.queryByText('update.manualInstall')).not.toBeInTheDocument(); }); it('loads release notes when auto-update status opens the modal', async () => { render(); act(() => { mocks.autoStatusHandler?.({ status: 'available', version: '2.1.14', currentVersion: '2.1.13', }); }); await waitFor(() => { expect(mocks.updateCheckMock).toHaveBeenCalled(); }); // Release notes now live in the Release Log modal, opened via the link. fireEvent.click(await screen.findByText('update.releaseLog')); expect(await screen.findByText('notes')).toBeInTheDocument(); expect(screen.getByText(/2\.1\.13/)).toBeInTheDocument(); }); });