Files
waooplus/tests/unit/helpers/update-check.test.ts
2026-03-08 17:10:06 +08:00

123 lines
3.7 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import {
checkGithubReleaseUpdate,
compareSemver,
normalizeSemverTag,
shouldPulseUpdate,
} from '@/lib/update-check'
describe('update-check semver helpers', () => {
it('normalizes semver tag with v prefix', () => {
expect(normalizeSemverTag('v0.3.0')).toBe('0.3.0')
})
it('supports prerelease suffix while comparing base semver', () => {
expect(normalizeSemverTag('v0.3.0-rc.1')).toBe('0.3.0')
expect(compareSemver('0.3.0-rc.1', '0.2.9')).toBe(1)
})
it('throws for malformed semver', () => {
expect(() => normalizeSemverTag('0.3')).toThrowError('Invalid semver tag: 0.3')
})
it('compares semver in numeric order', () => {
expect(compareSemver('0.3.0', '0.2.9')).toBe(1)
expect(compareSemver('0.2.0', '0.2.0')).toBe(0)
expect(compareSemver('0.1.9', '0.2.0')).toBe(-1)
})
it('pulses only when this version was not muted', () => {
expect(shouldPulseUpdate('0.3.0', null)).toBe(true)
expect(shouldPulseUpdate('0.3.0', '0.2.9')).toBe(true)
expect(shouldPulseUpdate('0.3.0', '0.3.0')).toBe(false)
})
})
describe('checkGithubReleaseUpdate', () => {
it('returns no-release when GitHub has no releases yet', async () => {
const fetchMock = vi.fn<typeof fetch>().mockResolvedValue(new Response(null, { status: 404 }))
const result = await checkGithubReleaseUpdate({
repository: 'owner/repo',
currentVersion: '0.2.0',
fetchImpl: fetchMock,
})
expect(result).toEqual({ kind: 'no-release' })
})
it('returns update-available when latest release is newer', async () => {
const fetchMock = vi.fn<typeof fetch>().mockResolvedValue(new Response(
JSON.stringify({
tag_name: 'v0.3.0',
html_url: 'https://github.com/owner/repo/releases/tag/v0.3.0',
name: 'v0.3.0',
published_at: '2026-03-03T10:00:00Z',
}),
{ status: 200 },
))
const result = await checkGithubReleaseUpdate({
repository: 'owner/repo',
currentVersion: '0.2.0',
fetchImpl: fetchMock,
})
expect(result.kind).toBe('update-available')
if (result.kind !== 'update-available') {
throw new Error('expected update-available result')
}
expect(result.latestVersion).toBe('0.3.0')
expect(result.release.tagName).toBe('v0.3.0')
})
it('returns no-update when latest release equals current version', async () => {
const fetchMock = vi.fn<typeof fetch>().mockResolvedValue(new Response(
JSON.stringify({
tag_name: 'v0.2.0',
html_url: 'https://github.com/owner/repo/releases/tag/v0.2.0',
name: 'v0.2.0',
published_at: '2026-03-03T10:00:00Z',
}),
{ status: 200 },
))
const result = await checkGithubReleaseUpdate({
repository: 'owner/repo',
currentVersion: '0.2.0',
fetchImpl: fetchMock,
})
expect(result.kind).toBe('no-update')
if (result.kind !== 'no-update') {
throw new Error('expected no-update result')
}
expect(result.latestVersion).toBe('0.2.0')
})
it('returns error when release tag is not valid semver', async () => {
const fetchMock = vi.fn<typeof fetch>().mockResolvedValue(new Response(
JSON.stringify({
tag_name: 'release-2026-03-03',
html_url: 'https://github.com/owner/repo/releases/tag/release-2026-03-03',
}),
{ status: 200 },
))
const result = await checkGithubReleaseUpdate({
repository: 'owner/repo',
currentVersion: '0.2.0',
fetchImpl: fetchMock,
})
expect(result.kind).toBe('error')
if (result.kind !== 'error') {
throw new Error('expected error result')
}
expect(result.reason).toBe('invalid-version')
})
})