Add tests

This commit is contained in:
Ticruz
2025-02-04 13:21:23 +01:00
committed by Jon Staab
parent 917727c86f
commit 8a2b62f693
57 changed files with 9231 additions and 25 deletions
+1
View File
@@ -1,2 +1,3 @@
build
normalize-url
__tests__
+254
View File
@@ -0,0 +1,254 @@
import type {Repository, TrustedEvent} from "@welshman/util"
import {get} from "svelte/store"
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
import {
adapter,
custom,
deriveEvents,
deriveEventsMapped,
deriveIsDeleted,
getter,
synced,
throttled,
withGetter,
} from "../src/index"
// Mock localStorage
const localStorageMock = (() => {
let store: Record<string, string> = {}
return {
getItem: (key: string) => store[key] || null,
setItem: (key: string, value: string) => {
store[key] = value
},
clear: () => {
store = {}
},
}
})()
vi.stubGlobal("localStorage", localStorageMock)
describe("Store utilities", () => {
beforeEach(() => {
localStorage.clear()
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
describe("synced", () => {
it("should sync with localStorage", () => {
const store = synced("testKey", "default")
expect(get(store)).toBe("default")
store.set("new value")
expect(localStorage.getItem("testKey")).toBe(JSON.stringify("new value"))
})
it("should load existing value from localStorage", () => {
localStorage.setItem("testKey", JSON.stringify("existing"))
const store = synced("testKey", "default")
expect(get(store)).toBe("existing")
})
})
describe("getter", () => {
it("should return current store value", () => {
const store = synced("test", "initial")
const getValue = getter(store)
expect(getValue()).toBe("initial")
store.set("updated")
expect(getValue()).toBe("updated")
})
})
describe("withGetter", () => {
it("should add getter to writable store", () => {
const store = withGetter(synced("test", "initial"))
expect(store.get()).toBe("initial")
store.set("updated")
expect(store.get()).toBe("updated")
})
})
describe("throttled", () => {
it("should throttle updates", () => {
const mockFn = vi.fn()
const store = synced("test", 0)
const throttledStore = throttled(100, store)
throttledStore.subscribe(mockFn)
store.set(1)
store.set(2)
store.set(3)
expect(mockFn).toHaveBeenCalledTimes(1) // Initial call
vi.advanceTimersByTime(100)
expect(mockFn).toHaveBeenCalledTimes(2)
expect(mockFn).toHaveBeenLastCalledWith(3)
})
})
describe("custom", () => {
it("should handle updates correctly", () => {
const mockFn = vi.fn()
const store = custom<number>(set => {
set(0)
return () => {}
})
store.subscribe(mockFn)
store.set(1)
store.update(n => n + 1)
expect(mockFn).toHaveBeenCalledTimes(3) // Initial + set + update
expect(store.get()).toBe(2)
})
})
describe("adapter", () => {
it("should adapt between different types", () => {
const source = synced<number>("test", 0)
const adapted = adapter({
store: source,
forward: n => n.toString(),
backward: s => parseInt(s, 10),
})
const mockFn = vi.fn()
adapted.subscribe(mockFn)
adapted.set("42")
expect(get(source)).toBe(42)
expect(mockFn).toHaveBeenLastCalledWith("42")
adapted.update(s => (parseInt(s, 10) + 1).toString())
expect(get(source)).toBe(43)
expect(mockFn).toHaveBeenLastCalledWith("43")
})
})
describe("Event-related stores", () => {
const mockRepository = {
query: vi.fn(),
isDeleted: vi.fn(),
isDeletedByAddress: vi.fn(),
on: vi.fn(),
off: vi.fn(),
} satisfies Partial<Repository>
beforeEach(() => {
vi.clearAllMocks()
})
describe("deriveEvents", () => {
it("should derive events from repository", () => {
const mockEvent = {id: "1", content: "test"} as TrustedEvent
mockRepository.query.mockReturnValue([mockEvent])
const store = deriveEvents(mockRepository as any, {
filters: [],
})
const mockFn = vi.fn()
store.subscribe(mockFn)
expect(mockRepository.query).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledWith([mockEvent])
})
})
describe("deriveEventsMapped", () => {
it("should map events to items", async () => {
const mockEvent = {id: "1", content: "test"} as TrustedEvent
mockRepository.query.mockReturnValue([mockEvent])
const store = deriveEventsMapped(mockRepository as any, {
filters: [],
eventToItem: event => ({id: event.id, mapped: true}),
itemToEvent: item => ({id: item.id, content: ""}) as TrustedEvent,
})
const mockFn = vi.fn()
store.subscribe(mockFn)
expect(mockRepository.query).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledWith([{id: "1", mapped: true}])
})
it("should handle async eventToItem mapping", async () => {
const mockEvent = {id: "1", content: "test"} as TrustedEvent
mockRepository.query.mockReturnValue([mockEvent])
const store = deriveEventsMapped(mockRepository as any, {
filters: [],
eventToItem: async event => ({id: event.id, mapped: true}),
itemToEvent: item => ({id: item.id, content: ""}) as TrustedEvent,
})
const mockFn = vi.fn()
store.subscribe(mockFn)
// Wait for async operations to complete
await vi.runAllTimersAsync()
expect(mockRepository.query).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledWith([{id: "1", mapped: true}])
})
it("should handle repository updates", () => {
const mockEvent = {id: "1", content: "test"} as TrustedEvent
mockRepository.query.mockReturnValue([mockEvent])
const store = deriveEventsMapped(mockRepository as any, {
filters: [{}],
eventToItem: event => ({id: event.id, mapped: true}),
itemToEvent: item => ({id: item.id, content: ""}) as TrustedEvent,
})
const mockFn = vi.fn()
store.subscribe(mockFn)
const [[_, callback]] = mockRepository.on.mock.calls
callback({
added: new Set(),
removed: new Set([mockEvent.id]),
})
vi.advanceTimersByTime(300) // Wait for batch delay
expect(mockFn).toHaveBeenLastCalledWith([{id: "2", mapped: true}])
})
})
describe("deriveIsDeleted", () => {
it("should track deletion status", () => {
const mockEvent = {id: "1"} as TrustedEvent
mockRepository.isDeleted.mockReturnValue(false)
const store = deriveIsDeleted(mockRepository as any, mockEvent)
const mockFn = vi.fn()
store.subscribe(mockFn)
expect(mockRepository.isDeleted).toHaveBeenCalledWith(mockEvent)
expect(mockFn).toHaveBeenCalledWith(false)
const [[_, callback]] = mockRepository.on.mock.calls
callback()
expect(mockRepository.isDeleted).toHaveBeenCalledWith(mockEvent)
expect(mockFn).toHaveBeenCalledWith(false)
})
})
})
})