mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Retire the registry entry the hardcoded null needed
The destructive-control registry carried this card because a detector read its hardcoded `expiresAt: null` as a field being blanked, and an entry explained at length why blanking was harmless here. The explanation was right and the cause was not: the null was there because nobody could set a date, not because none was wanted. With the control wired the detector no longer fires, so the entry no longer matches anything and the registry's own staleness check asked for it back.
This commit is contained in:
1 parent
6780e54036
commit
cb8e886ffc
2 files changed
+34
-14
No files matched your search
@@ -172,6 +172,13 @@ test.describe("account sharing", () => {
|
||||
await ownerContext.close();
|
||||
});
|
||||
|
||||
/** A `YYYY-MM-DD` day the date input accepts, N days from now. */
|
||||
function isoDayFromNow(days: number): string {
|
||||
const d = new Date();
|
||||
d.setDate(d.getDate() + days);
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
test("the owner invites, and the invitation confers nothing yet", async () => {
|
||||
await ownerPage.goto("/settings/access");
|
||||
|
||||
@@ -187,7 +194,34 @@ test.describe("account sharing", () => {
|
||||
await identifier.fill(E2E_USER.username);
|
||||
await expect(submit).toBeEnabled({ timeout: 1000 });
|
||||
}).toPass({ timeout: 15_000 });
|
||||
|
||||
// The lapse date, through the real form and onto the real wire.
|
||||
//
|
||||
// `expiresAt` was accepted, stored and annotated on by the route from the
|
||||
// day the grant model shipped, while the card sent a hardcoded `null`. The
|
||||
// component test cannot see that: it renders the control and checks the
|
||||
// date mapping, and BOTH still pass with the card wired back to `null`.
|
||||
// Only reading the posted body proves the value a person typed is the
|
||||
// value the server receives, which is the half that was missing.
|
||||
const lapse = ownerPage.locator('[data-slot="grant-invite-expires"]');
|
||||
await expect(lapse).toBeVisible();
|
||||
const chosenDay = isoDayFromNow(30);
|
||||
await lapse.fill(chosenDay);
|
||||
|
||||
const invitePost = ownerPage.waitForRequest(
|
||||
(req) =>
|
||||
req.method() === "POST" && req.url().endsWith("/api/account/grants"),
|
||||
);
|
||||
await submit.click();
|
||||
const posted = JSON.parse((await invitePost).postData() ?? "{}") as {
|
||||
expiresAt?: string | null;
|
||||
};
|
||||
expect(
|
||||
posted.expiresAt,
|
||||
"the invitation must carry the day the owner chose",
|
||||
).toBeTruthy();
|
||||
// End of the chosen day, not the midnight that starts it.
|
||||
expect(posted.expiresAt).toContain(chosenDay.slice(0, 8));
|
||||
|
||||
const row = ownerPage
|
||||
.locator('[data-slot="grants-given-list"] [data-slot="grant-row"]')
|
||||
|
||||
@@ -519,20 +519,6 @@ const REGISTRY: DestructiveEntry[] = [
|
||||
undetected:
|
||||
"Same shape as the card above, and one step further out of reach: renouncing is a POST, so not even a DELETE goes out. The path (`/api/account/grants/{id}/renounce`) names an act the D2 vocabulary does not carry, and it lives in the hook regardless. Registered by hand.",
|
||||
},
|
||||
{
|
||||
file: "components/settings/access/grant-invite-card.tsx",
|
||||
destroys:
|
||||
"nothing — it offers access, and the offer confers nothing until the other person accepts it",
|
||||
recovery: "permanent",
|
||||
confirm: [],
|
||||
unconfirmed: [
|
||||
{
|
||||
control: "the invitation form",
|
||||
reason:
|
||||
"D3 flags this file for `expiresAt: null` in the invite payload, reading it as a field being blanked. It is not: null means the grant runs until somebody ends it, which is the common household case and the absence of an expiry rather than the removal of one. The form creates a pending row and destroys nothing, and gating a creation behind a confirmation dialog would teach people to click through the dialogs that do guard a loss.",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ── Admin ───────────────────────────────────────────────────────────────
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user