55 lines
2.6 KiB
TypeScript
55 lines
2.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|||
|
|
import { mount, flushPromises } from '@vue/test-utils'
|
||
|
|
import { computed, ref } from 'vue'
|
||
|
|
import SystemUpdates from '@/views/settings/SystemUpdates.vue'
|
||
|
|
import type { UpdateStatus } from '@/services/systemUpdates'
|
||
|
|
const state = ref<UpdateStatus>({ configured: true, can_manage: true })
|
||
|
|
const apply = vi.fn().mockResolvedValue(undefined)
|
||
|
|
const check = vi.fn().mockResolvedValue(undefined)
|
||
|
|
vi.mock('@/composables/useSystemUpdates', () => ({ useSystemUpdates: () => ({
|
||
|
|
state, busy: computed(() => state.value.update?.status === 'building'), error: ref(''),
|
||
|
|
refresh: vi.fn().mockResolvedValue(undefined), check, apply,
|
||
|
|
}) }))
|
||
|
|
vi.mock('@/layouts/DashboardLayout.vue', () => ({ default: { template: '<div><slot /></div>' } }))
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.clearAllMocks()
|
||
|
|
state.value = { configured: true, can_manage: true, current: { revision: 'a'.repeat(40), subject: 'current' },
|
||
|
|
latest: { revision: 'b'.repeat(40), subject: 'new' }, check_interval_minutes: 30, update_available: true,
|
||
|
|
update: { status: 'idle', message: '' } }
|
||
|
|
})
|
||
|
|
|
||
|
|
describe('SystemUpdates', () => {
|
||
|
|
it('requires explicit confirmation before starting an update', async () => {
|
||
|
|
const wrapper = mount(SystemUpdates)
|
||
|
|
await flushPromises()
|
||
|
|
const button = wrapper.findAll('button').find(b => b.text() === '更新到此版本')!
|
||
|
|
await button.trigger('click')
|
||
|
|
expect(wrapper.find('[role=dialog]').exists()).toBe(true)
|
||
|
|
expect(apply).not.toHaveBeenCalled()
|
||
|
|
await wrapper.findAll('button').find(b => b.text() === '备份并开始更新')!.trigger('click')
|
||
|
|
await flushPromises()
|
||
|
|
expect(apply).toHaveBeenCalledOnce()
|
||
|
|
wrapper.unmount()
|
||
|
|
})
|
||
|
|
it('disables installation when there is no newer version or an update is running', async () => {
|
||
|
|
state.value.update_available = false
|
||
|
|
const wrapper = mount(SystemUpdates)
|
||
|
|
await flushPromises()
|
||
|
|
expect(wrapper.find('.update-actions button').attributes('disabled')).toBeDefined()
|
||
|
|
state.value.update_available = true
|
||
|
|
state.value.update = { status: 'building', message: '正在构建' }
|
||
|
|
await flushPromises()
|
||
|
|
expect(wrapper.find('.update-actions button').attributes('disabled')).toBeDefined()
|
||
|
|
expect(wrapper.text()).toContain('正在构建')
|
||
|
|
wrapper.unmount()
|
||
|
|
})
|
||
|
|
it('shows a failed update and recovery result', async () => {
|
||
|
|
state.value.update = { status: 'rolled_back', message: '已恢复原版本', error: '构建失败' }
|
||
|
|
const wrapper = mount(SystemUpdates)
|
||
|
|
await flushPromises()
|
||
|
|
expect(wrapper.text()).toContain('已恢复原版本')
|
||
|
|
expect(wrapper.text()).toContain('构建失败')
|
||
|
|
wrapper.unmount()
|
||
|
|
})
|
||
|
|
})
|