Files
BIPMaterialManager/tests/unit/update-service.test.ts
Misaka d7ebb10f38 fix(test): replace meaningless assertions and silent skips with proper test semantics
- Replace 4x expect(true).toBe(true) in audit-logger.test.ts with
  applyAuditConfig() + app.getVersion call count assertions
- Replace if(!hasCredentials){return} pattern with it.skipIf() in
  3 integration test files (cleaner, erp-auth, extractor) so Vitest
  correctly reports 12 tests as "skipped" instead of "passed"
- Remove placeholder assertion from skipped update-service test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 21:11:12 +08:00

168 lines
4.8 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { UpdateConfig } from '../../src/main/types/config.schema'
import type { UpdateCatalog, UpdateRelease, UpdateStatus } from '../../src/main/types/update.types'
const mockPublishUpdateStatus = vi.fn()
const mockReadText = vi.fn()
const mockDownloadToFile = vi.fn()
const mockLoadCatalog = vi.fn()
const mockGetDialogCatalog = vi.fn()
const mockResolveUserStatus = vi.fn()
const mockResolveAdminStatus = vi.fn()
const mockGetDownloadPath = vi.fn()
const mockCalculateSha256 = vi.fn()
const mockInstallDownloadedRelease = vi.fn()
const mockGetValidDownloadedRelease = vi.fn()
let currentUpdateConfig: UpdateConfig = {
enabled: true,
allowDevMode: true,
endpoint: 'http://localhost:9000',
accessKey: 'key',
secretKey: 'secret',
bucket: 'bucket',
region: 'us-east-1',
basePrefix: 'updates/win-portable',
checkIntervalMinutes: 30,
maxAdminHistoryPerChannel: 10
}
function createRelease(version: string, channel: 'stable' | 'preview' = 'stable'): UpdateRelease {
return {
version,
channel,
artifactKey: `${channel}/${version}.exe`,
sha256: `${channel}-${version}-sha`,
size: 1,
publishedAt: '2026-03-21T10:00:00Z',
changelogKey: `${channel}/${version}.md`
}
}
vi.mock('../../src/main/services/config/config-manager', () => ({
ConfigManager: {
getInstance: vi.fn(() => ({
getConfig: () => ({ update: currentUpdateConfig })
}))
}
}))
vi.mock('../../src/main/services/logger', () => ({
createLogger: vi.fn(() => ({
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn()
}))
}))
vi.mock('../../src/main/services/update/update-status-publisher', () => ({
publishUpdateStatus: mockPublishUpdateStatus
}))
vi.mock('../../src/main/services/update/update-storage-client', () => ({
UpdateStorageClient: class {
readText = mockReadText
downloadToFile = mockDownloadToFile
}
}))
vi.mock('../../src/main/services/update/update-catalog-service', () => ({
UpdateCatalogService: class {
loadCatalog = mockLoadCatalog
getDialogCatalog = mockGetDialogCatalog
resolveUserStatus = mockResolveUserStatus
resolveAdminStatus = mockResolveAdminStatus
}
}))
vi.mock('../../src/main/services/update/update-installer', () => ({
UpdateInstaller: class {
getDownloadPath = mockGetDownloadPath
calculateSha256 = mockCalculateSha256
installDownloadedRelease = mockInstallDownloadedRelease
getValidDownloadedRelease = mockGetValidDownloadedRelease
}
}))
describe('UpdateService', () => {
beforeEach(() => {
vi.clearAllMocks()
currentUpdateConfig = {
enabled: true,
allowDevMode: true,
endpoint: 'http://localhost:9000',
accessKey: 'key',
secretKey: 'secret',
bucket: 'bucket',
region: 'us-east-1',
basePrefix: 'updates/win-portable',
checkIntervalMinutes: 30,
maxAdminHistoryPerChannel: 10
}
mockReadText.mockReset()
mockDownloadToFile.mockReset()
mockLoadCatalog.mockReset()
mockGetDialogCatalog.mockReset()
mockResolveUserStatus.mockReset()
mockResolveAdminStatus.mockReset()
mockGetDownloadPath.mockReset()
mockCalculateSha256.mockReset()
mockInstallDownloadedRelease.mockReset()
mockGetValidDownloadedRelease.mockReset()
})
async function loadService() {
vi.resetModules()
const module = await import('../../src/main/services/update/update-service')
;(module.UpdateService as unknown as { instance: unknown }).instance = null
return module.UpdateService.getInstance()
}
it('initializes enabled update status from config', async () => {
const service = await loadService()
service.initialize()
expect(service.getStatus()).toMatchObject({
enabled: true,
supported: true
})
})
it('clears update state when user context becomes guest-like', async () => {
const service = await loadService()
await service.setUserContext(null)
expect(service.getStatus()).toMatchObject({
currentUserType: null,
phase: 'idle',
recommendedRelease: undefined,
downloadedRelease: undefined
})
expect(mockPublishUpdateStatus).toHaveBeenCalled()
})
// Note: This integration scenario is complex to test in unit tests.
// Moved to integration tests: tests/integration/update-workflow.test.ts
it.skip('checks updates for user and auto-downloads available recommendation', async () => {
// Covered by integration tests
})
it('returns disabled catalog when update services are unavailable', async () => {
currentUpdateConfig = {
...currentUpdateConfig,
enabled: false,
allowDevMode: false
}
const service = await loadService()
service.initialize()
const result = service.getCatalog()
expect(result).toEqual({ mode: 'disabled' })
expect(mockGetDialogCatalog).not.toHaveBeenCalled()
})
})