SPB Git forge

spb/ka-maps

Public
6commits 1branches 0releases
448.0 KBsize
maindefault branch
29 days agolast push
TypeScript 87.7% CSS 12.3%
3.7 KB · 135 lines typescript
Raw Blame History
1/**2 * Author: Simon-Pierre Boucher3 * Contact: contact@spboucher.ai4 * Project: Groupe Ka / Ka Maps5 */67import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";8import {9  BoundsQueryScheduler,10  stableStringify,11} from "../src/services/boundsQuery.js";12import type {13  BoundsQuery,14  BoundsQueryResult,15  KaDataAdapter,16  MapProperty,17} from "../src/types/index.js";1819const BOX = { west: -71.4, south: 46.7, east: -71.1, north: 46.9 };2021function prop(id: string): MapProperty {22  return {23    id,24    appSource: "lou-ka",25    latitude: 46.8,26    longitude: -71.2,27    kind: "listing",28    price: 1000,29  };30}3132function makeAdapter(33  impl: (q: BoundsQuery) => Promise<BoundsQueryResult>,34): KaDataAdapter {35  return { id: "test", appSource: "lou-ka", fetchInBounds: impl };36}3738beforeEach(() => vi.useFakeTimers());39afterEach(() => vi.useRealTimers());4041describe("BoundsQueryScheduler", () => {42  it("debounces bursts into one fetch", async () => {43    const calls: BoundsQuery[] = [];44    const s = new BoundsQueryScheduler(45      makeAdapter(async (q) => {46        calls.push(q);47        return { properties: [prop("a")] };48      }),49      { debounceMs: 100 },50    );51    s.request({ bbox: BOX, zoom: 12 });52    s.request({ bbox: BOX, zoom: 12.5 });53    s.request({ bbox: BOX, zoom: 13 });54    await vi.advanceTimersByTimeAsync(150);55    expect(calls).toHaveLength(1);56    expect(calls[0]!.zoom).toBe(13);57    s.destroy();58  });5960  it("aborts the stale request and never delivers old results late", async () => {61    const results: string[] = [];62    let call = 0;63    const s = new BoundsQueryScheduler(64      makeAdapter((q) => {65        const mine = ++call;66        return new Promise((resolve, reject) => {67          q.signal.addEventListener("abort", () =>68            reject(new DOMException("aborted", "AbortError")),69          );70          // First call resolves slowly, second quickly.71          setTimeout(72            () => resolve({ properties: [prop(`r${mine}`)] }),73            mine === 1 ? 500 : 10,74          );75        });76      }),77      { debounceMs: 0, cacheTtlMs: 0 },78    );79    s.onResult((r) => results.push(r.properties[0]!.id));8081    s.requestNow({ bbox: BOX, zoom: 10 });82    await vi.advanceTimersByTimeAsync(5);83    s.requestNow({ bbox: { ...BOX, north: 47.0 }, zoom: 11 });84    await vi.advanceTimersByTimeAsync(600);8586    expect(results).toEqual(["r2"]);87    s.destroy();88  });8990  it("serves identical queries from cache", async () => {91    let fetches = 0;92    const s = new BoundsQueryScheduler(93      makeAdapter(async () => {94        fetches++;95        return { properties: [prop("a")], totalCount: 1 };96      }),97      { debounceMs: 0 },98    );99    const seen: number[] = [];100    s.onResult((r) => seen.push(r.totalCount ?? 0));101102    s.requestNow({ bbox: BOX, zoom: 12, filters: { city: "Québec" } });103    await vi.advanceTimersByTimeAsync(10);104    s.requestNow({ bbox: BOX, zoom: 12, filters: { city: "Québec" } });105    await vi.advanceTimersByTimeAsync(10);106107    expect(fetches).toBe(1);108    expect(seen).toHaveLength(2);109    s.destroy();110  });111112  it("reports errors only for the newest request", async () => {113    const errors: unknown[] = [];114    const s = new BoundsQueryScheduler(115      makeAdapter(async () => {116        throw new Error("boom");117      }),118      { debounceMs: 0 },119    );120    s.onError((e) => errors.push(e));121    s.requestNow({ bbox: BOX, zoom: 12 });122    await vi.advanceTimersByTimeAsync(10);123    expect(errors).toHaveLength(1);124    s.destroy();125  });126});127128describe("stableStringify", () => {129  it("is key-order independent", () => {130    expect(stableStringify({ b: 1, a: { d: 2, c: 3 } })).toBe(131      stableStringify({ a: { c: 3, d: 2 }, b: 1 }),132    );133  });134});135