mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
test(insights): pin the reduced-motion guard for .animate-insight-in
The 400 ms `.animate-insight-in` entrance keyframe is applied across five insight surfaces and is collapsed to `animation: none` once, centrally, in a `@media (prefers-reduced-motion: reduce)` block in globals.css. Extend the motion-reduce coverage test to assert that central guard so a future edit cannot silently drop it and replay the entrance motion for motion-sensitive users.
This commit is contained in:
1 parent
60b86f1ec9
commit
e63fae564b
1 file changed
+53
@@ -65,3 +65,56 @@ describe("motion-reduce coverage — every animate-spin pairs with motion-reduce
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* v1.11.3 — `.animate-insight-in` reduced-motion guard.
|
||||
*
|
||||
* Unlike `animate-spin` (a Tailwind utility paired with an inline
|
||||
* `motion-reduce:animate-none` per site), `.animate-insight-in` is a custom
|
||||
* keyframe utility defined in `globals.css` and applied across five insight
|
||||
* surfaces (recommendations-grid, recommendation-card, insight-status-card,
|
||||
* hero-strip, arztbericht-hero-card). Guarding it at each call site would be
|
||||
* fragile, so the guard lives once in `globals.css`: a
|
||||
* `@media (prefers-reduced-motion: reduce)` block collapses the animation to
|
||||
* `none`, covering every consumer at once. This test pins that central guard
|
||||
* so a future edit cannot drop it and silently re-introduce a 400 ms motion
|
||||
* for motion-sensitive users.
|
||||
*/
|
||||
describe("motion-reduce coverage — animate-insight-in collapses under prefers-reduced-motion", () => {
|
||||
const GLOBALS = join(process.cwd(), "src", "app", "globals.css");
|
||||
const css = readFileSync(GLOBALS, "utf8");
|
||||
|
||||
it("globals.css defines the .animate-insight-in utility", () => {
|
||||
expect(css).toMatch(/\.animate-insight-in\s*\{[^}]*animation:/);
|
||||
});
|
||||
|
||||
it("a prefers-reduced-motion block collapses .animate-insight-in to no motion", () => {
|
||||
// Locate the reduced-motion media query, then assert that within its
|
||||
// body `.animate-insight-in` is reset to `animation: none`. The check
|
||||
// is anchored on the media query so a stray `.animate-insight-in {
|
||||
// animation: none }` outside a reduced-motion context cannot satisfy it.
|
||||
const mediaStart = css.search(
|
||||
/@media\s*\(\s*prefers-reduced-motion:\s*reduce\s*\)/,
|
||||
);
|
||||
expect(
|
||||
mediaStart,
|
||||
"Expected a `@media (prefers-reduced-motion: reduce)` block in globals.css.",
|
||||
).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Scan from the media query to the end of the file — every motion the app
|
||||
// defers under reduced motion lives in such a block, and `.animate-insight-in`
|
||||
// must be one of them.
|
||||
const fromMedia = css.slice(mediaStart);
|
||||
const guarded = /\.animate-insight-in\s*\{\s*animation:\s*none/.test(
|
||||
fromMedia,
|
||||
);
|
||||
|
||||
expect(
|
||||
guarded,
|
||||
"Expected `.animate-insight-in { animation: none }` inside a " +
|
||||
"`@media (prefers-reduced-motion: reduce)` block in globals.css. " +
|
||||
"Without it the 400 ms entrance keyframe plays for motion-sensitive " +
|
||||
"users on every insight card.",
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user