From 1a82d77d4275f3252a0dea16f15b5eaaf10357d9 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Tue, 14 Apr 2020 09:20:37 +0200 Subject: [PATCH 1/7] Try to write some test --- packages/alfa-rules/src/sia-r56/rule.ts | 98 +++++++++++++++++++ .../alfa-rules/test/sia-r56/rule.spec.tsx | 43 ++++++++ packages/alfa-rules/tsconfig.json | 2 + 3 files changed, 143 insertions(+) create mode 100644 packages/alfa-rules/src/sia-r56/rule.ts create mode 100644 packages/alfa-rules/test/sia-r56/rule.spec.tsx diff --git a/packages/alfa-rules/src/sia-r56/rule.ts b/packages/alfa-rules/src/sia-r56/rule.ts new file mode 100644 index 0000000000..8aaa99a702 --- /dev/null +++ b/packages/alfa-rules/src/sia-r56/rule.ts @@ -0,0 +1,98 @@ +import { Rule } from "@siteimprove/alfa-act"; +import { Node, Role } from "@siteimprove/alfa-aria"; +import { Branched } from "@siteimprove/alfa-branched"; +import { Device } from "@siteimprove/alfa-device"; +import { Element, Namespace } from "@siteimprove/alfa-dom"; +import { Predicate } from "@siteimprove/alfa-predicate"; +import { Err, Ok } from "@siteimprove/alfa-result"; +import { Page } from "@siteimprove/alfa-web"; +import { expectation } from "../common/expectation"; + +import { hasName } from "../common/predicate/has-name"; +import { hasNamespace } from "../common/predicate/has-namespace"; +import { hasRole } from "../common/predicate/has-role"; +import { isPerceivable } from "../common/predicate/is-perceivable"; + +const { and, equals } = Predicate; + +export default Rule.Atomic.of>({ + uri: "https://siteimprove.github.io/sanshikan/rules/sia-r56.html", + evaluate({ device, document }) { + return { + applicability() { + const elements = document + .descendants({ flattened: true, nested: true }) + .filter( + and( + and(Element.isElement, hasNamespace(equals(Namespace.HTML))), + and(isPerceivable(device), hasLandmarkRole(device)) + ) + ); + + console.dir(elements.map((elt) => elt.id.get()).toJSON()); + + const groups = elements + .groupBy((landmark) => Role.from(landmark)) + ; + + console.dir(groups.map(seq => seq.map(elt => elt.id.get())).toJSON(), {depth:4}); + + console.dir([...groups.values()].map(seq => seq.map(elt => elt.id.get()).toJSON())); + + return groups.values(); + }, + + expectations(target) { + const names = arrayBranchedToBranchedArray( + [...target].map((landmark) => + Node.from(landmark, device).map((accNode) => + accNode.name().map((str) => str.toLocaleLowerCase()) + ) + ) + ); + + return { + "1": expectation( + names.every((namesArray) => + namesArray.every( + (opt, idx) => namesArray.findIndex(equals(opt)) === idx + ) + ), + () => Outcomes.differentNames, + () => Outcomes.sameNames + ), + }; + }, + }; + }, +}); + +export namespace Outcomes { + export const differentNames = Ok.of( + "No two same landmarks have the same name." + ); + + export const sameNames = Err.of( + "Some identical landmarks have the same name." + ); +} + +function hasLandmarkRole(device: Device): Predicate { + return hasRole((role) => role.inheritsFrom(hasName(equals("landmark")))); +} + +function addToBranchedArray( + belt: Branched, + barr: Branched, B> +): Branched, B> { + return barr.flatMap((arr) => belt.map((elt) => arr.concat(elt))); +} + +function arrayBranchedToBranchedArray( + arr: Array> +): Branched, B> { + return arr.reduce, B>>( + (acc, cur) => addToBranchedArray(cur, acc), + Branched.of([]) + ); +} diff --git a/packages/alfa-rules/test/sia-r56/rule.spec.tsx b/packages/alfa-rules/test/sia-r56/rule.spec.tsx new file mode 100644 index 0000000000..8bb15d2fa7 --- /dev/null +++ b/packages/alfa-rules/test/sia-r56/rule.spec.tsx @@ -0,0 +1,43 @@ +import { Device } from "@siteimprove/alfa-device"; +import { Document, Element } from "@siteimprove/alfa-dom"; +import { jsx } from "@siteimprove/alfa-dom/jsx"; +import { Iterable } from "@siteimprove/alfa-iterable"; +import { Predicate } from "@siteimprove/alfa-predicate"; +import { test } from "@siteimprove/alfa-test"; +import { hasName } from "../../src/common/predicate/has-name"; + +import R56, { Outcomes } from "../../src/sia-r56/rule"; + +import { evaluate } from "../common/evaluate"; +import { passed, failed, inapplicable } from "../common/outcome"; + +const { and, equals } = Predicate; + +const device = Device.standard(); + +test("Passes when same landmarks have different names", async (t) => { + const document = Document.of((self) => [ + Element.fromElement( + +