diff --git a/.changeset/pretty-scissors-explode.md b/.changeset/pretty-scissors-explode.md new file mode 100644 index 0000000000..9ccb899ad8 --- /dev/null +++ b/.changeset/pretty-scissors-explode.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-device": patch +--- + +**Fixed:** Values of undefined user preferences are now correctly set to their default. diff --git a/.changeset/short-bees-behave.md b/.changeset/short-bees-behave.md new file mode 100644 index 0000000000..b37e2ebbc6 --- /dev/null +++ b/.changeset/short-bees-behave.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css-feature": patch +--- + +**Fixed:** Matching of user-preferences in the boolean context now correctly handles `none` defaults. diff --git a/packages/alfa-css-feature/src/media/feature/discrete.ts b/packages/alfa-css-feature/src/media/feature/discrete.ts index f1cf7b67b6..48f2e5e58e 100644 --- a/packages/alfa-css-feature/src/media/feature/discrete.ts +++ b/packages/alfa-css-feature/src/media/feature/discrete.ts @@ -1,5 +1,5 @@ import { Keyword, type Parser as CSSParser } from "@siteimprove/alfa-css"; -import type { Device} from "@siteimprove/alfa-device"; +import type { Device } from "@siteimprove/alfa-device"; import { Preference } from "@siteimprove/alfa-device"; import { None, Option } from "@siteimprove/alfa-option"; @@ -41,7 +41,7 @@ export namespace Discrete { return this._value .map((value) => value.matches(Keyword.of(deviceValue))) - .getOr(deviceValue !== booleanFalse ?? "none"); + .getOr(deviceValue !== (booleanFalse ?? "none")); } private static _from(value: Option>>): Discrete { diff --git a/packages/alfa-css-feature/test/media.spec.ts b/packages/alfa-css-feature/test/media.spec.ts index 5bf4257bef..b15eaa205d 100644 --- a/packages/alfa-css-feature/test/media.spec.ts +++ b/packages/alfa-css-feature/test/media.spec.ts @@ -1,7 +1,12 @@ import { test } from "@siteimprove/alfa-test"; import { Lexer } from "@siteimprove/alfa-css"; -import { Device, Viewport, Display } from "@siteimprove/alfa-device"; +import { + Device, + Display, + Preference, + Viewport, +} from "@siteimprove/alfa-device"; import { Feature } from "../dist/index.js"; @@ -460,7 +465,7 @@ test("#matches() matches ranges", (t) => { t.deepEqual(isGoldylocks.matches(largeLandscape), false); }); -test("#matches correctly behave at boundaries", (t) => { +test("#matches() correctly behave at boundaries", (t) => { // Inclusive bound is matched inclusively const isLarge = parse(`(width >= ${width}px)`).getUnsafe(); // Exclusive bound is matched exclusively @@ -472,3 +477,19 @@ test("#matches correctly behave at boundaries", (t) => { t.deepEqual(isSmall.matches(largeLandscape), false); t.deepEqual(isLargeToo.matches(largeLandscape), true); }); + +test("#matches() matches boolean prefers-reduced-motion", (t) => { + const prefersReducedMotion = parse("(prefers-reduced-motion)").getUnsafe(); + + t.deepEqual(prefersReducedMotion.matches(smallPortrait), false); + + const withReducedMotion = Device.of( + Device.Type.Screen, + Viewport.of(200, 400, Viewport.Orientation.Portrait), + Display.of(300), + undefined, + [Preference.of("prefers-reduced-motion", "reduce")], + ); + + t.deepEqual(prefersReducedMotion.matches(withReducedMotion), true); +}); diff --git a/packages/alfa-device/src/device.ts b/packages/alfa-device/src/device.ts index e1a0c86d3a..ffbb51e1c5 100644 --- a/packages/alfa-device/src/device.ts +++ b/packages/alfa-device/src/device.ts @@ -84,7 +84,9 @@ export class Device implements Equatable, Hashable, Serializable { public preference(name: N): Preference { return this._preferences .get(name) - .getOrElse(() => Preference.unset(name)) as Preference; + .getOrElse(() => + Preference.of(name, Preference.unset(name)), + ) as Preference; } public equals(value: unknown): value is this {