mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-04-27 04:15:38 +00:00
104 lines
4.1 KiB
JavaScript
104 lines
4.1 KiB
JavaScript
import { describe, it, expect, vi } from "vitest";
|
|
import {
|
|
buildNominatimSearchUrl,
|
|
normalizeHttpBaseUrl,
|
|
fetchTileBlobWithRetry,
|
|
fetchJsonWithRetry,
|
|
TILE_FETCH_TIMEOUT_MS,
|
|
} from "@/js/mapTileNetwork";
|
|
|
|
describe("mapTileNetwork", () => {
|
|
describe("normalizeHttpBaseUrl", () => {
|
|
it("strips trailing slash", () => {
|
|
expect(normalizeHttpBaseUrl("http://127.0.0.1:8080/nominatim/")).toBe("http://127.0.0.1:8080/nominatim");
|
|
});
|
|
});
|
|
|
|
describe("buildNominatimSearchUrl", () => {
|
|
it("builds search URL for public nominatim", () => {
|
|
const u = buildNominatimSearchUrl("https://nominatim.openstreetmap.org", "Paris", 5);
|
|
expect(u).toBe("https://nominatim.openstreetmap.org/search?format=json&q=Paris&limit=5&addressdetails=1");
|
|
});
|
|
|
|
it("supports custom local mesh nominatim base", () => {
|
|
const u = buildNominatimSearchUrl("http://192.168.44.1:3000/", "camp", 10);
|
|
expect(u.startsWith("http://192.168.44.1:3000/search?")).toBe(true);
|
|
expect(u).toContain(encodeURIComponent("camp"));
|
|
});
|
|
|
|
it("encodes query parameters safely", () => {
|
|
const u = buildNominatimSearchUrl("http://localhost/nom", "a&b=c", 10);
|
|
expect(u).toContain(encodeURIComponent("a&b=c"));
|
|
expect(u).not.toContain("a&b=c&");
|
|
});
|
|
});
|
|
|
|
describe("fetchTileBlobWithRetry", () => {
|
|
it("returns blob on first successful response", async () => {
|
|
const blob = new Blob([new Uint8Array([1, 2, 3])], { type: "image/png" });
|
|
global.fetch = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
blob: () => Promise.resolve(blob),
|
|
});
|
|
const r = await fetchTileBlobWithRetry("https://tile.example/0/0/0.png", {}, { retries: 0 });
|
|
expect(r.ok).toBe(true);
|
|
expect(r.blob).toBe(blob);
|
|
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
delete global.fetch;
|
|
});
|
|
|
|
it("retries after failure then succeeds", async () => {
|
|
const blob = new Blob([], { type: "image/png" });
|
|
global.fetch = vi
|
|
.fn()
|
|
.mockRejectedValueOnce(new TypeError("Failed to fetch"))
|
|
.mockResolvedValueOnce({
|
|
ok: true,
|
|
blob: () => Promise.resolve(blob),
|
|
});
|
|
const r = await fetchTileBlobWithRetry(
|
|
"https://tile.example/1/1/1.png",
|
|
{},
|
|
{ retries: 2, retryBaseDelayMs: 0 }
|
|
);
|
|
expect(r.ok).toBe(true);
|
|
expect(global.fetch).toHaveBeenCalledTimes(2);
|
|
delete global.fetch;
|
|
});
|
|
|
|
it("returns ok false after exhausting retries", async () => {
|
|
global.fetch = vi.fn().mockRejectedValue(new TypeError("network"));
|
|
const r = await fetchTileBlobWithRetry(
|
|
"https://tile.example/z/x/y.png",
|
|
{},
|
|
{ retries: 1, retryBaseDelayMs: 0, timeoutMs: TILE_FETCH_TIMEOUT_MS }
|
|
);
|
|
expect(r.ok).toBe(false);
|
|
expect(r.error).toBeDefined();
|
|
delete global.fetch;
|
|
});
|
|
});
|
|
|
|
describe("fetchJsonWithRetry", () => {
|
|
it("returns response on HTTP 200", async () => {
|
|
global.fetch = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
json: () => Promise.resolve([]),
|
|
});
|
|
const r = await fetchJsonWithRetry("http://127.0.0.1:9999/search?q=x", {}, { retries: 0 });
|
|
expect(r.ok).toBe(true);
|
|
expect(r.response.ok).toBe(true);
|
|
delete global.fetch;
|
|
});
|
|
|
|
it("does not retry on HTTP 404", async () => {
|
|
global.fetch = vi.fn().mockResolvedValue({ ok: false, status: 404 });
|
|
const r = await fetchJsonWithRetry("http://localhost/n/search", {}, { retries: 2, retryBaseDelayMs: 0 });
|
|
expect(r.ok).toBe(false);
|
|
expect(r.status).toBe(404);
|
|
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
delete global.fetch;
|
|
});
|
|
});
|
|
});
|