SPB Git

spb/earth-now Public License

earth-now.co — real-time planetary dashboard: live world metrics modeled, not streamed.

TypeScript 93% Shell 2.3% SQL 1.4% JavaScript 1.3% Dockerfile 1.2% CSS 0.8%
3.5 KB · 108 lines typescript
Raw Blame History
1/**2 * earth-now.co3 * Author:  Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File:    packages/counter/test/consistency.test.ts6 * Purpose: Client/server consistency — jsdom (browser-like) and a spawned Node process must produce bit-identical values7 *8 * @vitest-environment jsdom9 */1011import { execFileSync } from "node:child_process";12import { fileURLToPath } from "node:url";13import { dirname, join } from "node:path";14import { describe, expect, it } from "vitest";15import { type CounterModel, counterValue } from "../src/index";1617const MODELS: CounterModel[] = [18  {19    metricId: "consistency_linear",20    anchorValue: 12345.678,21    anchorTime: "2026-01-01T00:00:00.000Z",22    rateFn: { kind: "linear", perSecond: 1.2345 },23    observedAt: "2026-01-01T00:00:00.000Z",24    sourceId: "test",25    modelVersion: "test-v1",26    displayHints: { decimals: 0, unit: "u" },27  },28  {29    metricId: "consistency_seasonal",30    anchorValue: 1e9,31    anchorTime: "2026-01-01T00:00:00.000Z",32    rateFn: {33      kind: "seasonal",34      base: 4.17,35      harmonics: [36        { period: "year", order: 1, amplitude: 0.146, phase: 1.8449 },37        { period: "day", order: 1, amplitude: 0.02, phase: 2.88 },38      ],39    },40    observedAt: "2025-07-01T00:00:00.000Z",41    sourceId: "test",42    modelVersion: "test-v1",43    displayHints: { decimals: 0, unit: "u" },44  },45  {46    metricId: "consistency_spline",47    anchorValue: 8231000000,48    anchorTime: "2025-07-01T00:00:00.000Z",49    rateFn: {50      kind: "spline",51      knots: [52        ["2023-07-01T00:00:00.000Z", 8091000000],53        ["2024-07-01T00:00:00.000Z", 8161000000],54        ["2025-07-01T00:00:00.000Z", 8231000000],55        ["2026-07-01T00:00:00.000Z", 8299000000],56      ],57    },58    observedAt: "2025-07-01T00:00:00.000Z",59    sourceId: "test",60    modelVersion: "test-v1",61    displayHints: { decimals: 0, unit: "u" },62  },63];6465const INSTANTS = [66  "2026-01-01T00:00:00.000Z",67  "2026-03-14T15:09:26.535Z",68  "2026-08-09T12:00:00.000Z",69  "2026-12-31T23:59:59.999Z",70  "2027-06-15T06:30:00.000Z",71].map((iso) => Date.parse(iso));7273describe("client/server consistency (bit-identical values)", () => {74  it("runs under jsdom", () => {75    expect(typeof document).toBe("object");76  });7778  it("jsdom and a separate Node process agree exactly on every model × instant", () => {79    const here = counterValue !== undefined;80    expect(here).toBe(true);8182    const inJsdom = MODELS.map((m) => INSTANTS.map((t) => counterValue(m, t)));8384    // Evaluate the SAME models in a plain Node child process against the built dist.85    const distIndex = join(dirname(fileURLToPath(import.meta.url)), "..", "dist", "index.js");86    const script = `87      const { counterValue } = await import(${JSON.stringify(distIndex)});88      const models = ${JSON.stringify(MODELS)};89      const instants = ${JSON.stringify(INSTANTS)};90      const out = models.map((m) => instants.map((t) => counterValue(m, t)));91      console.log(JSON.stringify(out));92    `;93    const stdout = execFileSync(process.execPath, ["--input-type=module", "-e", script], {94      encoding: "utf8",95    });96    const inNode = JSON.parse(stdout) as number[][];9798    // JSON round-trips finite doubles exactly (shortest round-trip repr), so99    // toEqual here really is bit-identity.100    expect(inNode).toEqual(inJsdom);101    for (let i = 0; i < MODELS.length; i++) {102      for (let j = 0; j < INSTANTS.length; j++) {103        expect(Object.is(inNode[i]![j]!, inJsdom[i]![j]!)).toBe(true);104      }105    }106  });107});108