diff --git a/docs/output.md b/docs/output.md
index 71b0ccd..18219b7 100644
--- a/docs/output.md
+++ b/docs/output.md
@@ -289,15 +289,22 @@ style rule in each side's stylesheets and lists the groups of rules only one sid
```
rules: 3 changed groups, 1 never matched, 2 matched on some shots
+chat.css (1 rule) matched nothing: /help@1440,375
- +docs.css @media (width >= 60em) (5 rules) matched /a@960,1440 /b@960; nothing /a@959,375
+ +docs.css @media (min-width: 60em) (5 rules) matched /a@960,1440 /b@960; nothing /a@959,375
-docs.css @media (min-width: 60em) (5 rules) matched /a@960,1440 /b@960; nothing /a@959,375
```
- A rule is its enclosing at-rules, selector (nesting resolved) and declarations, as Chrome
- serializes them. So pure notation changes Chrome normalizes (`rgb(0 0 0)` and
- `rgb(0, 0, 0)`) are no change, while `min-width:` against `width >=` is. Asset hashes in
- `url()` and the left origin are read as on the other side. A rule moved to another file is
- no change. Only style rules count: not `@font-face`, `@keyframes` or `@property`.
+ serializes them, compared by meaning. So notation Chrome normalizes (`rgb(0 0 0)` and
+ `rgb(0, 0, 0)`, hex case, `0` and `0px`, merged shorthands) is no change, and neither is
+ declaration order or `@media (min-width: 60em)` against `(width >= 60em)`, or `max-width:`
+ against `<=`. A shorthand and longhand that swap order are a change, since that changes
+ what the rule does. A rule with a logical (`margin-inline-start`) or `-webkit-` property
+ keeps its order, since `-webkit-border-image` and `border-image` set the same thing and the
+ later wins, so reordering one is a change even where it does nothing. The reversed
+ `(60em <= width)` and the two-sided `(60em <= width <= 80em)` aren't read as `min-width:`.
+ Asset hashes in `url()` and the left origin are read as on the other side. A rule moved to
+ another file is no change. Only style rules count: not `@font-face`, `@keyframes` or
+ `@property`.
- `+` rules only the left (your change) has, `-` only the right. A group is a stylesheet's file
name (asset hash as `#`; a `
Rule coverage guard rail
-
The two sides write one breakpoint in different notation and render the same, so only rule coverage tells the rewritten rule apart, and whether any shot reached it.
+
The two sides write their breakpoints in different notation and render the same, so only rule coverage tells a rule that really changed from one rewritten, and whether any shot reached it.
The two sides write one breakpoint in different notation and render the same, so only rule coverage tells the rewritten rule apart, and whether any shot reached it.
+
The two sides write their breakpoints in different notation and render the same, so only rule coverage tells a rule that really changed from one rewritten, and whether any shot reached it.
Install
diff --git a/tests/visual/guardrails.test.ts b/tests/visual/guardrails.test.ts
index 8179918..822f601 100644
--- a/tests/visual/guardrails.test.ts
+++ b/tests/visual/guardrails.test.ts
@@ -414,15 +414,21 @@ describe("consent chrome", () => {
});
});
-test("--computed shows whether a rewritten breakpoint, and a rule nothing has, ever applied", async () => {
+test("--computed lists rules that changed meaning, not ones reordered or rewritten as ranges, and whether each applied", async () => {
const run = await capture(["/rules"], { widths: [960, 959], extra: ["--computed"] });
assert.equal(run.code, 0, context(run));
const at = (widths: number[]) => (widths.length ? [{ url: "/rules", widths }] : []);
- const group = (side: string, conditions: string[], matched: number[], unmatched: number[]) => ({
+ const group = (
+ side: string,
+ conditions: string[],
+ matched: number[],
+ unmatched: number[],
+ rules = 1,
+ ) => ({
side,
sheet: "inline#",
conditions,
- rules: conditions[0] === "@media screen" ? 2 : 1,
+ rules,
matched: at(matched),
unmatched: at(unmatched),
});
@@ -433,26 +439,28 @@ test("--computed shows whether a rewritten breakpoint, and a rule nothing has, e
rules.every((g) => /^inline#[0-9a-f]{6}$/.test(g.sheet)),
context(run),
);
- // The rgb() and url() hash rewrites mean the same, so they are no group; state-only rules match.
+ // Rewrites that mean the same are no group; state-only rules match.
assert.deepEqual(
rules.map((g) => ({ ...g, sheet: g.sheet.replace(hash, "inline#") })),
[
- group("left", [], [], [960, 959]),
+ group("left", [], [], [960, 959], 7),
+ group("right", [], [], [960, 959], 6),
group("left", ["@media (width >= 960px)"], [960], [959]),
group("right", ["@media (min-width: 960px)"], [960], [959]),
- group("left", ["@media screen"], [960, 959], []),
+ group("left", ["@media screen"], [960, 959], [], 2),
],
context(run),
);
assert.deepEqual(
result(results(run.outDir), "/rules", 960).computed?.rules?.map((g) => g.elements > 0),
- [true, false, true, true],
+ [true, false, true, true, false],
);
assert.deepEqual(
parseSummary(run.stdout).rules.map((l) => l.replace(hash, "inline#")),
[
- "rules: 4 changed groups, 1 never matched, 2 matched on some shots",
- " +inline# (1 rule) matched nothing: /rules@960,959",
+ "rules: 5 changed groups, 2 never matched, 2 matched on some shots",
+ " +inline# (7 rules) matched nothing: /rules@960,959",
+ " -inline# (6 rules) matched nothing: /rules@960,959",
" +inline# @media (width >= 960px) (1 rule) matched /rules@960; nothing /rules@959",
" -inline# @media (min-width: 960px) (1 rule) matched /rules@960; nothing /rules@959",
],