mirror of
https://github.com/kennethnym/aris.git
synced 2026-02-02 05:01:17 +00:00
151 lines
3.9 KiB
TypeScript
151 lines
3.9 KiB
TypeScript
|
|
import { describe, expect, mock, test } from "bun:test"
|
||
|
|
|
||
|
|
import { LocationKey, LocationSource, type Location } from "./location-source.ts"
|
||
|
|
|
||
|
|
function createLocation(overrides: Partial<Location> = {}): Location {
|
||
|
|
return {
|
||
|
|
lat: 37.7749,
|
||
|
|
lng: -122.4194,
|
||
|
|
accuracy: 10,
|
||
|
|
timestamp: new Date(),
|
||
|
|
...overrides,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
describe("LocationSource", () => {
|
||
|
|
describe("FeedSource interface", () => {
|
||
|
|
test("has correct id", () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
expect(source.id).toBe("location")
|
||
|
|
})
|
||
|
|
|
||
|
|
test("fetchItems always returns empty array", async () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
source.pushLocation(createLocation())
|
||
|
|
|
||
|
|
const items = await source.fetchItems()
|
||
|
|
expect(items).toEqual([])
|
||
|
|
})
|
||
|
|
|
||
|
|
test("fetchContext returns empty when no location", async () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
|
||
|
|
const context = await source.fetchContext()
|
||
|
|
expect(context).toEqual({})
|
||
|
|
})
|
||
|
|
|
||
|
|
test("fetchContext returns location when available", async () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
const location = createLocation()
|
||
|
|
source.pushLocation(location)
|
||
|
|
|
||
|
|
const context = await source.fetchContext()
|
||
|
|
expect(context).toEqual({ [LocationKey]: location })
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
describe("pushLocation", () => {
|
||
|
|
test("updates lastLocation", () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
expect(source.lastLocation).toBeNull()
|
||
|
|
|
||
|
|
const location = createLocation()
|
||
|
|
source.pushLocation(location)
|
||
|
|
|
||
|
|
expect(source.lastLocation).toEqual(location)
|
||
|
|
})
|
||
|
|
|
||
|
|
test("notifies listeners", () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
const listener = mock()
|
||
|
|
|
||
|
|
source.onContextUpdate(listener)
|
||
|
|
|
||
|
|
const location = createLocation()
|
||
|
|
source.pushLocation(location)
|
||
|
|
|
||
|
|
expect(listener).toHaveBeenCalledTimes(1)
|
||
|
|
expect(listener).toHaveBeenCalledWith({ [LocationKey]: location })
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
describe("history", () => {
|
||
|
|
test("default historySize is 1", () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
|
||
|
|
source.pushLocation(createLocation({ lat: 1 }))
|
||
|
|
source.pushLocation(createLocation({ lat: 2 }))
|
||
|
|
|
||
|
|
expect(source.locationHistory).toHaveLength(1)
|
||
|
|
expect(source.lastLocation?.lat).toBe(2)
|
||
|
|
})
|
||
|
|
|
||
|
|
test("respects configured historySize", () => {
|
||
|
|
const source = new LocationSource({ historySize: 3 })
|
||
|
|
|
||
|
|
const loc1 = createLocation({ lat: 1 })
|
||
|
|
const loc2 = createLocation({ lat: 2 })
|
||
|
|
const loc3 = createLocation({ lat: 3 })
|
||
|
|
|
||
|
|
source.pushLocation(loc1)
|
||
|
|
source.pushLocation(loc2)
|
||
|
|
source.pushLocation(loc3)
|
||
|
|
|
||
|
|
expect(source.locationHistory).toEqual([loc1, loc2, loc3])
|
||
|
|
})
|
||
|
|
|
||
|
|
test("evicts oldest when exceeding historySize", () => {
|
||
|
|
const source = new LocationSource({ historySize: 2 })
|
||
|
|
|
||
|
|
const loc1 = createLocation({ lat: 1 })
|
||
|
|
const loc2 = createLocation({ lat: 2 })
|
||
|
|
const loc3 = createLocation({ lat: 3 })
|
||
|
|
|
||
|
|
source.pushLocation(loc1)
|
||
|
|
source.pushLocation(loc2)
|
||
|
|
source.pushLocation(loc3)
|
||
|
|
|
||
|
|
expect(source.locationHistory).toEqual([loc2, loc3])
|
||
|
|
})
|
||
|
|
|
||
|
|
test("locationHistory is readonly", () => {
|
||
|
|
const source = new LocationSource({ historySize: 3 })
|
||
|
|
source.pushLocation(createLocation())
|
||
|
|
|
||
|
|
const history = source.locationHistory
|
||
|
|
expect(Array.isArray(history)).toBe(true)
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
describe("onContextUpdate", () => {
|
||
|
|
test("returns cleanup function", () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
const listener = mock()
|
||
|
|
|
||
|
|
const cleanup = source.onContextUpdate(listener)
|
||
|
|
|
||
|
|
source.pushLocation(createLocation({ lat: 1 }))
|
||
|
|
expect(listener).toHaveBeenCalledTimes(1)
|
||
|
|
|
||
|
|
cleanup()
|
||
|
|
|
||
|
|
source.pushLocation(createLocation({ lat: 2 }))
|
||
|
|
expect(listener).toHaveBeenCalledTimes(1)
|
||
|
|
})
|
||
|
|
|
||
|
|
test("supports multiple listeners", () => {
|
||
|
|
const source = new LocationSource()
|
||
|
|
const listener1 = mock()
|
||
|
|
const listener2 = mock()
|
||
|
|
|
||
|
|
source.onContextUpdate(listener1)
|
||
|
|
source.onContextUpdate(listener2)
|
||
|
|
|
||
|
|
source.pushLocation(createLocation())
|
||
|
|
|
||
|
|
expect(listener1).toHaveBeenCalledTimes(1)
|
||
|
|
expect(listener2).toHaveBeenCalledTimes(1)
|
||
|
|
})
|
||
|
|
})
|
||
|
|
})
|