mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 13:22:14 +00:00
Make the delegated-write journey actually run
Every test in e2e/delegated-writes.spec.ts had been skipping since the day the invitation form shipped its level control. The skip guard looked for data-slot="grant-invite-level"; the control landed as "grant-invite-access-option". The file said out loud what to change and nobody changed it, so a quiet skip and a passing suite read the same in a CI summary. Two assertions inside it had never been executed and were both wrong: the header button reads "Add", not "Add measurement", and the form opens on blood pressure, which has no `value` field. Fixed against stable attributes rather than viewport text, with data-slot="measurement-add" added to the control the journey clicks. Adds the deep-link leg the SSR suite cannot hold: a query parameter is the same affordance as the button, and ?add= / ?new=1 open exactly what the resolved level admits.
This commit is contained in:
1 parent
ebf032158e
commit
0b1a6c1b09
3 files changed
+31
-48
No files matched your search
@@ -386,35 +386,6 @@ test.describe("account sharing", () => {
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("a query parameter opens nothing the button withholds", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Three deep links reach a create sheet without passing the control that
|
||||
// normally opens it. A parameter that opens a sheet is the same affordance
|
||||
// as the button, and the SSR suite cannot reach any of them: it holds the
|
||||
// paint of a component, never a URL.
|
||||
await page.goto("/measurements?add=WEIGHT");
|
||||
await expect(
|
||||
page.locator('[data-slot="shared-record-banner"]'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.locator('[data-slot="responsive-sheet-content"]'),
|
||||
).toHaveCount(0);
|
||||
// And the button it stands in for is gone too, so nothing on this page
|
||||
// offers the form by either route.
|
||||
await expect(
|
||||
page.getByRole("button", { name: /add measurement/i }),
|
||||
).toHaveCount(0);
|
||||
|
||||
await page.goto("/medications?new=1");
|
||||
await expect(
|
||||
page.locator('[data-slot="shared-record-banner"]'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.locator('[data-slot="medication-wizard-dialog"]'),
|
||||
).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("revoking from the owner's browser drops the delegate out", async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
@@ -9,19 +9,22 @@
|
||||
*
|
||||
* ## Why it gates itself instead of seeding a WRITE grant directly
|
||||
*
|
||||
* The grant level is chosen in the invitation form, which is another chunk's
|
||||
* work. Rather than mint a WRITE row behind the UI's back — which would prove
|
||||
* the journey works for a grant no person can create — the journey looks for
|
||||
* the level control and stands down when it is not there yet.
|
||||
* The grant level is chosen in the invitation form. Rather than mint a WRITE
|
||||
* row behind the UI's back — which would prove the journey works for a grant
|
||||
* no person can create — the journey looks for the level control and stands
|
||||
* down when it is not there yet.
|
||||
*
|
||||
* **To enable this once the invite form ships its level control:** if it lands
|
||||
* under a different `data-slot` than the constant below, change that one
|
||||
* string. Nothing else in this file assumes anything about the control except
|
||||
* that picking WRITE and submitting mints a WRITE grant.
|
||||
* That guard was written against a `data-slot` the form never shipped under
|
||||
* (`grant-invite-level`; the control landed as `grant-invite-access-option`),
|
||||
* so from the day the control arrived until 2026-08-03 every test in this file
|
||||
* skipped and the whole delegated-write journey ran nowhere. The file said out
|
||||
* loud what to change and nobody changed it, which is the standing lesson
|
||||
* about a check that cannot fail: the skip is quiet, and a quiet skip and a
|
||||
* passing suite look identical in a CI summary.
|
||||
*
|
||||
* The skip is deliberately loud rather than silent: it names the missing
|
||||
* control, so a run where the control exists and the journey still does not
|
||||
* execute reads as a bug in this file rather than as an absence upstream.
|
||||
* The constant is the real one now. If it moves again, change that one string:
|
||||
* nothing else here assumes anything about the control except that choosing
|
||||
* WRITE and submitting mints a WRITE grant.
|
||||
*
|
||||
* ## What this spec cannot cover
|
||||
*
|
||||
@@ -45,10 +48,10 @@ import {
|
||||
* The invitation form's grant-level control. The journey runs when this is on
|
||||
* the page and stands down when it is not. One string, one place.
|
||||
*/
|
||||
const GRANT_LEVEL_SLOT = "grant-invite-level";
|
||||
const GRANT_LEVEL_SLOT = "grant-invite-access-option";
|
||||
|
||||
/** The value the level control carries for a grant that may add entries. */
|
||||
const WRITE_LEVEL_VALUE = "write";
|
||||
const WRITE_LEVEL_VALUE = "WRITE";
|
||||
|
||||
test.describe("delegated writes", () => {
|
||||
// One journey in order, like the read-only sibling: each step is the next
|
||||
@@ -110,9 +113,11 @@ test.describe("delegated writes", () => {
|
||||
await expect(submit).toBeEnabled({ timeout: 1000 });
|
||||
}).toPass({ timeout: 15_000 });
|
||||
|
||||
await ownerPage
|
||||
.locator(`[data-slot="${GRANT_LEVEL_SLOT}"]`)
|
||||
.selectOption(WRITE_LEVEL_VALUE);
|
||||
const writeOption = ownerPage.locator(
|
||||
`[data-slot="${GRANT_LEVEL_SLOT}"][data-access="${WRITE_LEVEL_VALUE}"]`,
|
||||
);
|
||||
await writeOption.click();
|
||||
await expect(writeOption).toHaveAttribute("data-selected", "true");
|
||||
|
||||
// Read the posted body: a level control that renders and sends a hardcoded
|
||||
// level would pass every render assertion and ship a read-only grant.
|
||||
@@ -125,7 +130,7 @@ test.describe("delegated writes", () => {
|
||||
access?: string;
|
||||
};
|
||||
expect(
|
||||
posted.access?.toLowerCase(),
|
||||
posted.access,
|
||||
"the invitation must carry the level the owner chose",
|
||||
).toBe(WRITE_LEVEL_VALUE);
|
||||
});
|
||||
@@ -162,8 +167,14 @@ test.describe("delegated writes", () => {
|
||||
res.request().method() === "POST" &&
|
||||
res.url().endsWith("/api/measurements"),
|
||||
);
|
||||
await page.getByRole("button", { name: /add measurement/i }).click();
|
||||
await page.locator('input[name="value"], #value').first().fill("71.5");
|
||||
// Stable attributes and the form's real fields, neither of which this
|
||||
// step had. It looked for a button named "Add measurement" (the header
|
||||
// reads "Add") and then for a `value` input (the form opens on blood
|
||||
// pressure, which has three). Both were wrong from the day they were
|
||||
// written and nobody found out, because the whole file was skipping.
|
||||
await page.locator('[data-slot="measurement-add"]').click();
|
||||
await page.locator("#sys").fill("124");
|
||||
await page.locator("#dia").fill("78");
|
||||
await page.getByRole("button", { name: /^save$/i }).click();
|
||||
expect((await post).status(), "the write must be accepted").toBeLessThan(
|
||||
300,
|
||||
|
||||
@@ -157,6 +157,7 @@ export default function MeasurementsPage() {
|
||||
actions={
|
||||
canAdd ? (
|
||||
<Button
|
||||
data-slot="measurement-add"
|
||||
className="min-h-11 sm:min-h-9"
|
||||
onClick={() => {
|
||||
setReturnTo(null);
|
||||
|
||||
Reference in new issue
Block a user