test: add unit tests for hooks (useBookmarks, useUpdateCheck)

- Export loadBookmarks/saveBookmarks and isNewer for testability
- Add 12 tests covering bookmark persistence and semver comparison
- Total: 165 tests passing
This commit is contained in:
Nicolas Varrot
2026-02-20 09:04:38 +00:00
parent 295ba7b3e5
commit 3970e8a00c
4 changed files with 92 additions and 3 deletions

View File

@@ -0,0 +1,56 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { loadBookmarks, saveBookmarks, type Bookmark } from '../useBookmarks';
const STORAGE_KEY = 'pinchchat-bookmarks';
// Mock localStorage
const store: Record<string, string> = {};
const localStorageMock = {
getItem: vi.fn((key: string) => store[key] ?? null),
setItem: vi.fn((key: string, value: string) => { store[key] = value; }),
removeItem: vi.fn((key: string) => { delete store[key]; }),
};
Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock });
beforeEach(() => {
for (const key of Object.keys(store)) delete store[key];
vi.clearAllMocks();
});
describe('loadBookmarks', () => {
it('returns empty array when nothing stored', () => {
expect(loadBookmarks()).toEqual([]);
});
it('returns parsed bookmarks from localStorage', () => {
const bookmarks: Bookmark[] = [
{ messageId: 'msg1', sessionKey: 'sess1', preview: 'Hello', timestamp: 1000, bookmarkedAt: 2000 },
];
store[STORAGE_KEY] = JSON.stringify(bookmarks);
expect(loadBookmarks()).toEqual(bookmarks);
});
it('returns empty array on corrupt JSON', () => {
store[STORAGE_KEY] = '{broken';
expect(loadBookmarks()).toEqual([]);
});
});
describe('saveBookmarks', () => {
it('persists bookmarks to localStorage', () => {
const bookmarks: Bookmark[] = [
{ messageId: 'msg1', sessionKey: 'sess1', preview: 'Test', timestamp: 1000, bookmarkedAt: 2000 },
];
saveBookmarks(bookmarks);
expect(JSON.parse(store[STORAGE_KEY]!)).toEqual(bookmarks);
});
it('overwrites existing bookmarks', () => {
saveBookmarks([{ messageId: 'old', sessionKey: 's', preview: '', timestamp: 0, bookmarkedAt: 0 }]);
saveBookmarks([{ messageId: 'new', sessionKey: 's', preview: '', timestamp: 0, bookmarkedAt: 0 }]);
const stored = JSON.parse(store[STORAGE_KEY]!);
expect(stored).toHaveLength(1);
expect(stored[0].messageId).toBe('new');
});
});

View File

@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest';
import { isNewer } from '../useUpdateCheck';
describe('isNewer', () => {
it('returns true when remote major is higher', () => {
expect(isNewer('2.0.0', '1.0.0')).toBe(true);
});
it('returns true when remote minor is higher', () => {
expect(isNewer('1.5.0', '1.4.0')).toBe(true);
});
it('returns true when remote patch is higher', () => {
expect(isNewer('1.4.2', '1.4.1')).toBe(true);
});
it('returns false when versions are equal', () => {
expect(isNewer('1.4.1', '1.4.1')).toBe(false);
});
it('returns false when remote is older', () => {
expect(isNewer('1.3.9', '1.4.0')).toBe(false);
});
it('handles missing patch segments', () => {
expect(isNewer('1.1', '1.0.9')).toBe(true);
});
it('handles large version numbers', () => {
expect(isNewer('1.66.1', '1.66.0')).toBe(true);
expect(isNewer('1.66.0', '1.66.1')).toBe(false);
});
});

View File

@@ -10,7 +10,7 @@ export interface Bookmark {
bookmarkedAt: number;
}
function loadBookmarks(): Bookmark[] {
export function loadBookmarks(): Bookmark[] {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) return JSON.parse(raw) as Bookmark[];
@@ -18,7 +18,7 @@ function loadBookmarks(): Bookmark[] {
return [];
}
function saveBookmarks(bookmarks: Bookmark[]) {
export function saveBookmarks(bookmarks: Bookmark[]) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(bookmarks));
} catch { /* noop */ }

View File

@@ -54,7 +54,7 @@ export function useUpdateCheck(currentVersion: string): UpdateInfo {
}
/** True if remote is newer than local (semver compare) */
function isNewer(remote: string, local: string): boolean {
export function isNewer(remote: string, local: string): boolean {
const r = remote.split('.').map(Number);
const l = local.split('.').map(Number);
for (let i = 0; i < 3; i++) {