import { mount, flushPromises } from '@vue/test-utils' import { afterEach, beforeEach, expect, it, vi } from 'vitest' import UpdateCheckDialog from '@/components/app/UpdateCheckDialog.vue' import { checkSystemUpdate, systemUpdateStatus, type SystemUpdateStatus } from '@/api/systemUpdate' vi.mock('@/api/systemUpdate', () => ({ checkSystemUpdate: vi.fn(), systemUpdateStatus: vi.fn() })) const current = { schemaVersion: 1 as const, webVersion: '0.4.17', releaseVersion: '0.4.17', gitTag: 'v0.4.17' } const status: SystemUpdateStatus = { current, latest: current, updateAvailable: false, installationMode: 'source', supported: true, canRollback: false } const render = () => mount(UpdateCheckDialog, { global: { stubs: { StandaloneDialog: { template: '
' }, AppIcon: true } } }) beforeEach(() => { vi.mocked(systemUpdateStatus).mockResolvedValue(status); vi.mocked(checkSystemUpdate).mockResolvedValue(status) }) afterEach(() => vi.resetAllMocks()) it('checks immediately, keeps the installed version visible and disables repeat checks until finished', async () => { let finish!: (value: SystemUpdateStatus) => void vi.mocked(checkSystemUpdate).mockReturnValue(new Promise(resolve => { finish = resolve })) const wrapper = render() await flushPromises() expect(wrapper.text()).toContain('正在检测更新') expect(wrapper.text()).toContain('0.4.17') expect(wrapper.get('button').attributes()).toHaveProperty('disabled') finish(status); await flushPromises() expect(wrapper.get('[role="status"]').text()).toBe('当前已是最新版本') expect(checkSystemUpdate).toHaveBeenCalledTimes(1) wrapper.unmount() }) it('shows a new version and opens update management only on request', async () => { vi.mocked(checkSystemUpdate).mockResolvedValue({ ...status, latest: { ...current, webVersion: '0.4.18' }, updateAvailable: true, releasePageUrl: 'https://github.com/Lsamien/yaoyao/releases/tag/v0.4.18' }) const wrapper = render(); await flushPromises() expect(wrapper.text()).toContain('发现新版本 0.4.18') expect(wrapper.get('a').attributes('href')).toContain('/releases/tag/v0.4.18') expect(wrapper.emitted('manage')).toBeUndefined() await wrapper.findAll('button')[1]!.trigger('click') expect(wrapper.emitted('manage')).toHaveLength(1) wrapper.unmount() }) it('reports failed checks without claiming the cached version is latest and supports retry', async () => { vi.mocked(checkSystemUpdate).mockRejectedValueOnce(new Error('无法连接 GitHub')) const wrapper = render(); await flushPromises() expect(wrapper.get('[role="alert"]').text()).toBe('无法连接 GitHub') expect(wrapper.text()).not.toContain('已是最新') expect(wrapper.text()).toContain('未获取') await wrapper.get('button').trigger('click'); await flushPromises() expect(wrapper.text()).toContain('当前已是最新版本') wrapper.unmount() }) it('explains externally managed installations without offering an unsupported update', async () => { vi.mocked(checkSystemUpdate).mockResolvedValue({ ...status, latest: { ...current, webVersion: '0.4.18' }, updateAvailable: true, supported: false, unsupportedReason: '请使用 Docker Compose 更新', releasePageUrl: 'javascript:alert(1)' }) const wrapper = render(); await flushPromises() expect(wrapper.text()).toContain('请使用 Docker Compose 更新') expect(wrapper.text()).not.toContain('前往更新') expect(wrapper.find('a').exists()).toBe(false) wrapper.unmount() })