Files
HealthLog/src/components/dashboard/__tests__/environment-chip.test.tsx
T
Marc-André Bombeck 3c98d95a40 feat(environment): air quality, pollen and UV per day, locations sealed at rest
Fetch the Open-Meteo air-quality feed (CAMS, domains=auto) with the weather:
17 hourly variables folded into local days by fixed rules (means and maxima
only with 18 of 24 hours, ozone as the highest 8-hour running mean, UV only
with the midday hours), a value the feed did not cover stored as null, never
as zero. Requests are cut into 90-day chunks, newest first, and chunks before
mid 2022 ask for the eight pollutant and index variables only. An air-quality
failure never costs the weather row; the day stays unfetched and the nightly
gap fill (up to 90 days per account, newest first) asks for it again.

Every Open-Meteo request asks an instance-wide budget kept in Postgres first
(500 a minute, 4000 an hour, 8000 a day, weighted by the hosted pricing
rule). A refused request is not sent and the run ends as done with
budget_blocked. OPENMETEO_AIR_QUALITY_URL and ENVIRONMENT_AIR_QUALITY_DISABLED
are honoured; the account switch lives on PATCH /api/environment/preferences.

The home, each dated location period and each stored day keep their coarse
location sealed as one value under healthlog/environment-location/v1. The
writers write the sealed value only, the readers open it and fall back to the
readable columns for rows the free-text encryption backfill has not reached,
and the backfill now seals all three and clears the readable columns. The
backup carries the location readable in a portable file and sealed in a
disaster-recovery file; a restore seals either under the receiving key.

Three correlation channels join the environment family (PM2.5, the ozone
8-hour high, the day's highest pollen count), read through the averaged
same-day window and left empty while air quality is off. The Coach and MCP
gain get_environment: module-gated, clamped to the lookback limit, no
coordinate or place name anywhere, with provenance and the attribution
lines. The settings section gets the switch, the coverage and the newest
day's values; the dashboard shows a quiet chip on a day with high pollen,
a warm night or very poor air. Copernicus and Open-Meteo are credited next
to the values.
2026-10-08 10:02:39 +02:00

53 lines
1.2 KiB
TypeScript

/**
* v1.42 (#615) — the dashboard environment chip stays quiet: no flag, no
* chip; an unfetched air-quality part raises no air or pollen flag.
*/
import { describe, expect, it } from "vitest";
import { environmentChipFlags } from "../environment-chip";
const POLLEN = {
alder: 0,
birch: 0,
grass: 0,
mugwort: 0,
olive: 0,
ragweed: 0,
};
describe("environmentChipFlags", () => {
it("raises nothing on an ordinary day", () => {
expect(
environmentChipFlags({
date: "2026-10-07",
tempMin: 9,
airQuality: { eaqiMax: 35, pollen: POLLEN },
}),
).toEqual([]);
});
it("names the high pollen kinds, the warm night and the very poor air", () => {
expect(
environmentChipFlags({
date: "2026-07-20",
tempMin: 21,
airQuality: { eaqiMax: 84, pollen: { ...POLLEN, grass: 70 } },
}),
).toEqual([
{ kind: "pollen", kinds: ["grass"] },
{ kind: "hotNight" },
{ kind: "veryPoorAir" },
]);
});
it("raises no air flag for a day whose air quality was not fetched", () => {
expect(
environmentChipFlags({
date: "2026-07-20",
tempMin: 10,
airQuality: null,
}),
).toEqual([]);
});
});