Weather

weather.test.js 56 lines

Files · 9
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556import { test, expect } from "bun:test";
import { Database } from "bun:sqlite";
import { readFileSync } from "node:fs";
import { setupWeather, saveWeather, loadWeather, conditionText, updateLocation } from "./weather.js";
import ddl from "./schema.js";

function mock() {
  const db = new Database(":memory:");
  db.exec("PRAGMA foreign_keys=ON");
  const L = { db: {
    exec: async (sql, params = []) => db.query(sql).run(...params),
    query: async (sql, params = []) => db.query(sql).all(...params),
  }};
  return { db, L };
}
const payload = (date = "2026-10-17") => ({
  current: { temperature_2m: 14, apparent_temperature: 12, relative_humidity_2m: 70,
    wind_speed_10m: 18, weather_code: 61, precipitation: 1 },
  daily: { time: [date], weather_code: [71], temperature_2m_max: [16],
    temperature_2m_min: [-2], precipitation_sum: [4.2] },
});

test("weather stores forecasts by local date, restores UI data and replaces only the refreshed location", async () => {
  expect(ddl).toBe(readFileSync(new URL("./schema.sql", import.meta.url), "utf8"));
  const { db, L } = mock();
  try {
    await setupWeather(L);
    await setupWeather(L);
    await L.db.exec("INSERT INTO locations (name,lat,lon) VALUES ('London',51,0),('Tokyo',35,139)");
    expect(await loadWeather(L, 1)).toBeNull();
    await saveWeather(L, 1, payload());
    await saveWeather(L, 2, payload());
    await saveWeather(L, 1, payload("2026-10-18"));
    const saved = await loadWeather(L, 1);
    expect(saved.current).toMatchObject({ temperature_2m: 14, apparent_temperature: 12, condition: "Rain", precipitation: 1 });
    expect(saved.daily.time).toEqual(["2026-10-18"]);
    expect((await loadWeather(L, 2)).daily.time).toEqual(["2026-10-17"]);
    expect(db.query("SELECT * FROM forecasts WHERE location_id=1").get()).toMatchObject({
      date: "2026-10-18", condition: conditionText(71), temperature_max_c: 16, temperature_min_c: -2, precipitation_mm: 4.2,
    });
    expect(db.query("SELECT count(*) AS n FROM weather_log WHERE location_id=1").get().n).toBe(2);
    const before = await loadWeather(L, 1);
    await expect(saveWeather(L, 1, { current: payload().current })).rejects.toThrow("incomplete");
    expect(await loadWeather(L, 1)).toEqual(before);
    db.exec("CREATE TRIGGER fail_forecast BEFORE INSERT ON forecasts BEGIN SELECT RAISE(ABORT,'disk error'); END");
    await expect(saveWeather(L, 1, payload())).rejects.toThrow("disk error");
    expect(await loadWeather(L, 1)).toEqual(before);
    const previous = { id: 1, name: "London", lat: 51, lon: 0 };
    await updateLocation(L, previous, { name: "Home", lat: 51, lon: 0 });
    expect(await loadWeather(L, 1)).toEqual(before);
    await updateLocation(L, previous, { name: "New location", lat: 52, lon: 1 });
    expect(await loadWeather(L, 1)).toBeNull();
    expect(db.query("SELECT count(*) AS n FROM forecasts WHERE location_id=1").get().n).toBe(0);
    expect((await loadWeather(L, 2)).daily.time).toEqual(["2026-10-17"]);
  } finally { db.close(); }
});