mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
test(sharing): follow the invite form's new scope default and one-line copy
The access options render as a row with an info affordance rather than a wrapping label, the scope question preselects nothing, and the write and manage detail moved behind the (i). Point the consent-copy and form-reset guards at the shipped bundle for the detail text and at the unset scope default.
This commit is contained in:
1 parent
e0692efba8
commit
f6a4acf779
2 files changed
+46
-18
No files matched your search
@@ -353,8 +353,9 @@ describe("a refused invitation keeps what was typed", () => {
|
||||
const split = INVITE_CARD.indexOf("onError:", start);
|
||||
// The options object ends at the first ` },` after the error arm, so
|
||||
// the slice stops at the mutation rather than running into the JSX below,
|
||||
// where a `setNarrowed(false)` on a radio would satisfy the matcher for
|
||||
// the wrong reason.
|
||||
// where a `setNarrowed(false)` / `setNarrowed(true)` on a radio would
|
||||
// satisfy the matcher for the wrong reason. The success reset returns the
|
||||
// scope to unset (`null`), which the JSX never writes.
|
||||
const end = INVITE_CARD.indexOf("\n },", split);
|
||||
const onSuccess = INVITE_CARD.slice(start, split);
|
||||
const onError = INVITE_CARD.slice(split, end);
|
||||
@@ -367,7 +368,7 @@ describe("a refused invitation keeps what was typed", () => {
|
||||
'setIdentifier("")',
|
||||
'setExpiresOn("")',
|
||||
'setAccess("READ")',
|
||||
"setNarrowed(false)",
|
||||
"setNarrowed(null)",
|
||||
"setSections([])",
|
||||
]) {
|
||||
expect(onSuccess, reset).toContain(reset);
|
||||
|
||||
@@ -16,11 +16,20 @@
|
||||
* a rewrite that quietly drops it should fail here.
|
||||
*/
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import type { GrantList, GrantRow } from "@/lib/queries/use-account-grants";
|
||||
|
||||
/** The shipped English invite copy, the source of truth for the consent text. */
|
||||
const inviteBundle = (
|
||||
JSON.parse(readFileSync(join(process.cwd(), "messages/en.json"), "utf8")) as {
|
||||
recordSharing: { invite: Record<string, string> };
|
||||
}
|
||||
).recordSharing.invite;
|
||||
|
||||
const grantsRef: { value: GrantList } = { value: grantList() };
|
||||
/**
|
||||
* A grant payload, with the audit window every real one carries.
|
||||
@@ -110,8 +119,11 @@ describe("offering a level", () => {
|
||||
// second group of radios in the same idiom, and a group that lost the ring
|
||||
// would be the same defect shipped again one section further down.
|
||||
const html = render(<GrantInviteCard />);
|
||||
// Access options carry an (i) sibling now, so the row is a `<div>` with the
|
||||
// radio in a nested `<label>`; scope options stay a wrapping `<label>`. The
|
||||
// focus ring rides the row in both, which is what this pins.
|
||||
const levels = html.match(
|
||||
/<label[^>]*data-slot="grant-invite-access-option"[^>]*>/g,
|
||||
/<div[^>]*data-slot="grant-invite-access-option"[^>]*>/g,
|
||||
);
|
||||
const scopes = html.match(
|
||||
/<label[^>]*data-slot="grant-invite-scope-option"[^>]*>/g,
|
||||
@@ -126,39 +138,54 @@ describe("offering a level", () => {
|
||||
|
||||
it("says plainly that manage can change and delete what the owner wrote", () => {
|
||||
const html = render(<GrantInviteCard />);
|
||||
// The clause that separates this level from the one below it. A rewrite
|
||||
// that keeps "manage" and drops this is a rewrite that stops describing
|
||||
// a delete button.
|
||||
expect(html).toContain("add, change and remove entries in your record");
|
||||
// The clause that separates this level from the one below it, on the label
|
||||
// where somebody decides. A rewrite that keeps "manage" and drops this is a
|
||||
// rewrite that stops describing a delete button.
|
||||
expect(html).toContain("add, change and remove entries");
|
||||
expect(html).toContain("including ones you entered yourself");
|
||||
// And the fence, in the same breath. Consent to management is only
|
||||
// meaningful beside what management does not reach.
|
||||
expect(html).toContain("They cannot change your login");
|
||||
expect(html).toContain("who else has access");
|
||||
expect(html).toContain("You can end this at any time.");
|
||||
// And the fence, in the same breath — now one tap behind the (i) rather
|
||||
// than a wall inline, but still shipped consent copy, not docs. Consent to
|
||||
// management is only meaningful beside what management does not reach.
|
||||
expect(inviteBundle.accessManageDetail).toContain(
|
||||
"They cannot change your login",
|
||||
);
|
||||
expect(inviteBundle.accessManageDetail).toContain("who else has access");
|
||||
expect(inviteBundle.accessManageDetail).toContain(
|
||||
"You can end this at any time.",
|
||||
);
|
||||
});
|
||||
|
||||
it("says what the wider level actually does, and what it does not", () => {
|
||||
const html = render(<GrantInviteCard />);
|
||||
// The thing a person reading "write access" gets wrong.
|
||||
// The thing a person reading "write access" gets wrong, inline on the label.
|
||||
expect(html).toContain("cannot edit or delete anything");
|
||||
expect(html).toContain("marking a dose taken or skipped");
|
||||
// The exact list of what write may add rides the (i) detail now.
|
||||
expect(inviteBundle.accessWriteDetail).toContain(
|
||||
"mark a dose taken or skipped",
|
||||
);
|
||||
// v1.36.1 — the copy named allergies, which left the admitted set before
|
||||
// this shipped, and it did so on the one screen where somebody decides who
|
||||
// may write into their health record. Assert the withdrawal too, not only
|
||||
// the presence of the rest: a consent notice that over-promises is worse
|
||||
// than one that is merely incomplete.
|
||||
// than one that is merely incomplete. Neither the inline line nor the
|
||||
// detail may name it.
|
||||
expect(html).not.toContain("allergies");
|
||||
expect(inviteBundle.accessWriteDetail).not.toContain("allergies");
|
||||
// v1.36.x — and the same again for logging a value on a tracked metric.
|
||||
// The route was admitted, the copy promised it, and no delegate could
|
||||
// reach a surface that posts one: `/custom-metrics/{id}` is not a
|
||||
// shared-record destination, so the shell answers before the form does.
|
||||
// The permission and the sentence went together.
|
||||
expect(html).not.toContain("a metric you track yourself");
|
||||
expect(inviteBundle.accessWriteDetail).not.toContain(
|
||||
"a metric you track yourself",
|
||||
);
|
||||
// Deferring a reminder is the capability the same request could reach and
|
||||
// delegation does not cover; the notice has to say so.
|
||||
expect(html).toContain("cannot defer one of your reminders");
|
||||
// And the narrow option still says it is narrow.
|
||||
expect(inviteBundle.accessWriteDetail).toContain(
|
||||
"cannot defer one of your reminders",
|
||||
);
|
||||
// And the narrow option still says it is narrow, inline.
|
||||
expect(html).toContain("They cannot add or change anything.");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user