Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
eefc151
feat(vaccinations): add the immunization log route, nav entry and sha…
MBombeck Aug 8, 2026
1d07204
feat(vaccinations): group the log by component antigen with resolved …
MBombeck Aug 8, 2026
ff72917
feat(vaccinations): add the dose capture and edit form
MBombeck Aug 8, 2026
f540298
feat(vaccinations): render the catalogue's sourced schedule text
MBombeck Aug 8, 2026
b5ce446
feat(vaccinations): mint the booster reminder a logged dose suggests
MBombeck Aug 8, 2026
9b58394
feat(vaccinations): link documents to doses, with the upload suggestion
MBombeck Aug 8, 2026
2da0159
feat(vaccinations): add the immunization history to the doctor report
MBombeck Aug 8, 2026
4db70d3
feat(vaccinations): name the catalogue in six locales
MBombeck Aug 8, 2026
958f3bc
test(vaccinations): reconcile the structural guards with the new surf…
MBombeck Aug 8, 2026
a6a6571
test(vaccinations): cover the immunization log end to end
MBombeck Aug 8, 2026
3ad8332
test(vaccinations): prove the managed-profile and scoped-grant record…
MBombeck Aug 8, 2026
9992067
Merge remote-tracking branch 'origin/main' into feat/vaccinations-pha…
MBombeck Aug 8, 2026
5aa0367
test(e2e): click the always-present vaccination add button
MBombeck Aug 8, 2026
9f2cbcb
test(sharing): count the booster handler in the MANAGE matrix
MBombeck Aug 8, 2026
4766828
fix(reminders): keep a maximum-interval rolling reminder's next due a…
MBombeck Aug 8, 2026
e5072ba
fix(reminders): bound a rolling reminder's re-anchor by the notify-ho…
MBombeck Aug 8, 2026
77ba829
test(sharing): drive the booster admission through its owned effect
MBombeck Aug 8, 2026
34cd41a
fix(a11y): name the catalogue and practitioner combobox triggers
MBombeck Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ paths:
type: number
const: 2
leaves:
maxItems: 92
maxItems: 93
type: array
items:
type: string
Expand Down Expand Up @@ -1037,7 +1037,7 @@ paths:
type: number
const: 2
leaves:
maxItems: 92
maxItems: 93
type: array
items:
type: string
Expand Down Expand Up @@ -16157,7 +16157,7 @@ components:
type: number
const: 2
leaves:
maxItems: 92
maxItems: 93
type: array
items:
type: string
Expand Down
89 changes: 89 additions & 0 deletions e2e/setup/vaccination-fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* The immunization-log spec's account hygiene.
*
* `vaccinations.spec.ts` asserts GROUPED verdicts — a combination dose appears
* in each of its three component groups, one antigen holds at most one minted
* booster reminder, a logged next dose moves the reminder's due date forward.
* Every one of those is a count over the seeded e2e user's live rows, so the
* spec has to own the rows it counts against: a dose left by an earlier run, a
* Playwright retry, or a second project sharing the account would leave a
* stale group on the page and a second reminder in the antigen bucket, and the
* grouped assertions would read the wrong count.
*
* The reset is delete-then-assert-clean, keyed by the seeded user's id. Links
* go first for their foreign key; the minted booster reminders go last and are
* scoped to the ones this feature writes — `vaccination_antigen IS NOT NULL` —
* so an unrelated Vorsorge reminder another spec relies on is never touched.
*/
import pg from "pg";

import { E2E_USER } from "./global-setup";

async function getUserId(pool: pg.Pool): Promise<string> {
const res = await pool.query<{ id: string }>(
"SELECT id FROM users WHERE username = $1",
[E2E_USER.username],
);
const id = res.rows[0]?.id;
if (!id) {
throw new Error(
"[vaccination-fixture] e2e user not seeded — global-setup must run first",
);
}
return id;
}

/**
* Remove the seeded e2e user's vaccination rows, their document links, and the
* booster reminders they minted. Safe to call from every test's `beforeEach`.
*/
export async function resetVaccinations(): Promise<void> {
const url = process.env.DATABASE_URL;
if (!url) throw new Error("[vaccination-fixture] DATABASE_URL is not set");
const pool = new pg.Pool({ connectionString: url });
try {
const userId = await getUserId(pool);
// Links first — they FK into the record rows.
await pool.query(
"DELETE FROM vaccination_document_links WHERE user_id = $1",
[userId],
);
await pool.query("DELETE FROM vaccination_records WHERE user_id = $1", [
userId,
]);
// Only the reminders this feature mints. A booster reminder is the only
// kind that carries an antigen; a checkup another spec created has none and
// stays.
await pool.query(
"DELETE FROM measurement_reminders WHERE user_id = $1 AND vaccination_antigen IS NOT NULL",
[userId],
);
} finally {
await pool.end();
}
}

/**
* Put the seeded e2e user's `vaccinations` module back to its default-on state.
*
* The module-off test flips the toggle through the real settings UI, and that
* write persists on the shared account past the test that made it. Every other
* flow needs the surface reachable, so this clears the `vaccinations` key from
* the preferences blob — default-on is absence — leaving any other module the
* account carries (`nutrients`) untouched. Called from `beforeEach` so no test
* order can strand the surface off.
*/
export async function ensureVaccinationsModuleOn(): Promise<void> {
const url = process.env.DATABASE_URL;
if (!url) throw new Error("[vaccination-fixture] DATABASE_URL is not set");
const pool = new pg.Pool({ connectionString: url });
try {
const userId = await getUserId(pool);
await pool.query(
"UPDATE users SET module_preferences_json = module_preferences_json - 'vaccinations' WHERE id = $1 AND module_preferences_json ? 'vaccinations'",
[userId],
);
} finally {
await pool.end();
}
}
Loading
Loading