/** * earth-now.co * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * File: apps/ingest/test/usgs.test.ts * Purpose: USGS FDSN parsers/fetcher tests — fixture-backed, no network */ import { readFileSync } from "node:fs"; import { describe, expect, it } from "vitest"; import type { FetchLike } from "../src/fetch-like"; import { fetchUsgsQuakeCount, parseUsgsCount, parseUsgsLastMajor, usgsCountUrl, } from "../src/sources/usgs"; const fixture = (name: string): string => readFileSync(new URL(`./fixtures/${name}`, import.meta.url), "utf8"); const fakeFetch = (body: string, ok = true, status = 200): FetchLike => async () => ({ ok, status, text: async () => body }); describe("usgsCountUrl", () => { it("builds a deterministic count URL from a parameterized now", () => { const nowMs = Date.parse("2026-08-09T12:00:00Z"); expect(usgsCountUrl(24, 4.5, nowMs)).toBe( "https://earthquake.usgs.gov/fdsnws/event/1/count?format=geojson" + "&starttime=2026-08-08T12%3A00%3A00.000Z&minmagnitude=4.5", ); }); }); describe("parseUsgsCount", () => { it("returns the count from a realistic payload", () => { expect(parseUsgsCount(JSON.parse(fixture("usgs_count_sample.json")))).toBe(132); }); it("throws descriptive errors on malformed payloads", () => { expect(() => parseUsgsCount(JSON.parse(fixture("usgs_count_malformed.json")))).toThrow( /'count' must be a non-negative integer/, ); expect(() => parseUsgsCount(null)).toThrow(/not an object/); expect(() => parseUsgsCount({ count: -3 })).toThrow(/non-negative/); expect(() => parseUsgsCount({ count: "132" })).toThrow(/non-negative integer/); }); }); describe("parseUsgsLastMajor", () => { it("extracts mag/place/timeIso from features[0]", () => { const result = parseUsgsLastMajor(JSON.parse(fixture("usgs_query_sample.json"))); expect(result).toEqual({ mag: 6.3, place: "142 km E of Petropavlovsk-Kamchatsky, Russia", timeIso: new Date(1754650000000).toISOString(), }); }); it("throws on the degraded fixture (missing mag, non-numeric time)", () => { expect(() => parseUsgsLastMajor(JSON.parse(fixture("usgs_query_malformed.json")))).toThrow( /mag is not a finite number/, ); }); it("throws on empty or missing features", () => { expect(() => parseUsgsLastMajor({ type: "FeatureCollection", features: [] })).toThrow( /'features' is missing or empty/, ); expect(() => parseUsgsLastMajor({})).toThrow(/'features' is missing or empty/); }); }); describe("fetchUsgsQuakeCount", () => { it("fetches and parses via an injected fetchImpl (no network)", async () => { const seen: string[] = []; const fetchImpl: FetchLike = async (url) => { seen.push(url); return { ok: true, status: 200, text: async () => fixture("usgs_count_sample.json") }; }; await expect(fetchUsgsQuakeCount(24, 4.5, fetchImpl)).resolves.toBe(132); expect(seen).toHaveLength(1); expect(seen[0]).toContain("/fdsnws/event/1/count?format=geojson"); expect(seen[0]).toContain("minmagnitude=4.5"); }); it("throws on HTTP errors", async () => { await expect(fetchUsgsQuakeCount(24, 4.5, fakeFetch("", false, 503))).rejects.toThrow( /HTTP 503/, ); }); it("throws on non-JSON bodies", async () => { await expect(fetchUsgsQuakeCount(24, 4.5, fakeFetch("oops"))).rejects.toThrow( /not valid JSON/, ); }); });