Skip to content

Commit

Permalink
SIA-R8: add type="password" (and more) to applicability (#1667)
Browse files Browse the repository at this point in the history
* adding failing unit test.

* adding more fialing tests.

* adding type="password" fields to the applicability.  seems to work i.e. make the tests pass.

* adding expecations Outcomes specifically for the input type="password" case.

* - expanded applicability to include many more type="" attribute values.  inspired act-rules/act-rules.github.io#2123 (comment)
- added corresponding unit tests.  they pass.

* changeset.

* changeset.

* Update packages/alfa-rules/src/sia-r8/rule.ts

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* fixing recently-introduced compilation error, I think.

* fixing recently-introduced error in test.

* changing import style as per review advice at #1667 (comment)

* tightening up the types by using the same InputType type that hasInputType uses (instead of string).
as per review comment at #1667 (comment)

* removing unused import.

* Update packages/alfa-rules/test/sia-r8/rule.spec.tsx

Co-authored-by: Jean-Yves Moyen <[email protected]>

* making new experimental rule: sia-er8.
(as per review comment at #1667 (review) )
so this commit effectively reverts sia-r8.

* changeset.

* refactoring as per review comment at #1667 (comment)

* Extract API

* Update .changeset/swift-meals-check.md

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/src/experimental.ts

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/src/sia-er8/rule.ts

Co-authored-by: Jean-Yves Moyen <[email protected]>

* Update packages/alfa-rules/src/sia-er8/rule.ts

Co-authored-by: Jean-Yves Moyen <[email protected]>

* minor fixes - consequent to the review at #1667 (review)

* Extract API

---------

Co-authored-by: Jean-Yves Moyen <[email protected]>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent ff43035 commit 15fabab
Show file tree
Hide file tree
Showing 9 changed files with 485 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-meals-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@siteimprove/alfa-rules": minor
---

**Added:** Experimental rule SIA-ER8. It adds support for type="password" and more.
8 changes: 5 additions & 3 deletions docs/review/api/alfa-dom.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ export namespace Element {
// @internal (undocumented)
export function fromElement<N extends string = string>(json: JSON<N>, device?: Device): Trampoline<Element<N>>;
// (undocumented)
export type InputType = helpers.InputType;
// (undocumented)
export function isElement(value: unknown): value is Element;
// (undocumented)
export interface JSON<N extends string = string> extends Node.JSON<"element"> {
Expand All @@ -362,9 +364,6 @@ export namespace Element {
// (undocumented)
style: Block.JSON | string | null;
}
// (undocumented)
export interface MinimalJSON extends Node.JSON<"element"> {
}
const // Warning: (ae-forgotten-export) The symbol "predicate_3" needs to be exported by the entry point index.d.ts
//
// (undocumented)
Expand All @@ -391,6 +390,9 @@ export namespace Element {
//
// (undocumented)
inputType: typeof helpers.inputType;
// (undocumented)
export interface MinimalJSON extends Node.JSON<"element"> {
}
}

// @public (undocumented)
Expand Down
42 changes: 23 additions & 19 deletions docs/review/api/alfa-rules.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,44 @@ import { Text } from '@siteimprove/alfa-dom';
// @public (undocumented)
export const alfaVersion = "0.92.0";

// @public (undocumented)
const _default: Rule.Atomic<Page, Element<string>, {}, Element<string>>;

// @public @deprecated (undocumented)
const _default_10: Rule.Atomic<Page, Text, Question.Metadata, Text>;

// @public
const _default: Rule.Atomic<Page, Document, Question.Metadata, Element<string>>;
const _default_2: Rule.Atomic<Page, Document, Question.Metadata, Element<string>>;

// @public
const _default_2: Rule.Atomic<Page, Element<string>, Question.Metadata, Node<string> | Array_2<Node<string>>>;
const _default_3: Rule.Atomic<Page, Element<string>, Question.Metadata, Node<string> | Array_2<Node<string>>>;

// @public
const _default_3: Rule.Atomic<Page, Document, Question.Metadata, Document>;
const _default_4: Rule.Atomic<Page, Document, Question.Metadata, Document>;

// @public @deprecated (undocumented)
const _default_4: Rule.Atomic<Page, Element<string>, {}, Element<string>>;
const _default_5: Rule.Atomic<Page, Element<string>, {}, Element<string>>;

// @public @deprecated (undocumented)
const _default_5: Rule.Atomic<Page, Attribute<string>, {}, Attribute<string>>;

// @public (undocumented)
const _default_6: Rule.Atomic<Page, Element<string>, Question.Metadata, Element<string>>;
const _default_6: Rule.Atomic<Page, Attribute<string>, {}, Attribute<string>>;

// @public (undocumented)
const _default_7: Rule.Atomic<Page, Element<string>, Question.Metadata, Element<string>>;

// @public @deprecated (undocumented)
const _default_8: Rule.Atomic<Page, Text, Question.Metadata, Text>;
// @public (undocumented)
const _default_8: Rule.Atomic<Page, Element<string>, Question.Metadata, Element<string>>;

// @public @deprecated (undocumented)
const _default_9: Rule.Atomic<Page, Text, Question.Metadata, Text>;

declare namespace deprecatedRules {
export {
_default_4 as DR6,
_default_5 as DR18,
_default_6 as DR34,
_default_7 as DR36,
_default_8 as DR66,
_default_9 as DR69
_default_5 as DR6,
_default_6 as DR18,
_default_7 as DR34,
_default_8 as DR36,
_default_9 as DR66,
_default_10 as DR69
}
}
export { deprecatedRules }
Expand Down Expand Up @@ -93,9 +96,10 @@ export namespace Diagnostic {

declare namespace experimentalRules {
export {
_default as ER87,
_default_2 as R82,
_default_3 as R109
_default as ER8,
_default_2 as ER87,
_default_3 as R82,
_default_4 as R109
}
}
export { experimentalRules }
Expand Down
2 changes: 2 additions & 0 deletions packages/alfa-dom/src/node/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,4 +573,6 @@ export namespace Element {
} = predicate;

export const { inputType } = helpers;

export type InputType = helpers.InputType;
}
3 changes: 2 additions & 1 deletion packages/alfa-rules/src/experimental.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ER8 from "./sia-er8/rule.js";
import ER87 from "./sia-er87/rule.js";

import R82 from "./sia-r82/rule.js";
import R109 from "./sia-r109/rule.js";

export { ER87, R82, R109 };
export { ER8, ER87, R82, R109 };
96 changes: 96 additions & 0 deletions packages/alfa-rules/src/sia-er8/rule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Diagnostic, Rule } from "@siteimprove/alfa-act";
import type { Role } from "@siteimprove/alfa-aria";
import * as aria from "@siteimprove/alfa-aria"
import { Element, Namespace, Node, Query } from "@siteimprove/alfa-dom";
import { Predicate } from "@siteimprove/alfa-predicate";
import { Err, Ok } from "@siteimprove/alfa-result";
import { Criterion } from "@siteimprove/alfa-wcag";
import type { Page } from "@siteimprove/alfa-web";

import { expectation } from "../common/act/expectation.js";

import { Scope, Stability, Version } from "../tags/index.js";
import { WithRole } from "../common/diagnostic.js";

const { hasNonEmptyAccessibleName, hasRole, isIncludedInTheAccessibilityTree } = aria.DOM;
const { hasInputType, hasNamespace } = Element;
const { and, or } = Predicate;
const { getElementDescendants } = Query;

export default Rule.Atomic.of<Page, Element>({
uri: "https://alfa.siteimprove.com/rules/sia-r8",
requirements: [Criterion.of("4.1.2")],
tags: [Scope.Component, Stability.Experimental, Version.of(2)],
evaluate({ device, document }) {
return {
applicability() {
return getElementDescendants(document, Node.fullTree).filter(
and(
hasNamespace(Namespace.HTML),
or(
hasRole(
device,
"checkbox",
"combobox",
"listbox",
"menuitemcheckbox",
"menuitemradio",
"radio",
"searchbox",
"slider",
"spinbutton",
"switch",
"textbox",
),
hasInputType("password", "color", "date", "datetime-local", "file", "month", "time", "week"),
),
isIncludedInTheAccessibilityTree(device),
),
);
},

expectations(target) {
const role = aria.Node.from(target, device).role;
if(role.isSome()) {
const roleName = role.get().name;
return {
1: expectation(
hasNonEmptyAccessibleName(device)(target),
() => Outcomes.FormFieldWithAriaRoleHasName(roleName),
() => Outcomes.FormFieldWithAriaRoleHasNoName(roleName),
),
};
} else {
// We know the type attribute has a correct value because of the applicability.
const inputType = target.attribute("type").map(attr => attr.value).getUnsafe(`R8v2 found an element with no role nor 'type' attribute: ${target.path()}`) as Element.InputType;
return {
1: expectation(
hasNonEmptyAccessibleName(device)(target),
() => Outcomes.InputElementWithNoAriaRoleHasName(inputType),
() => Outcomes.InputElementWithNoAriaRoleHasNoName(inputType),
),
};
}
},
};
},
});

/**
* @public
*/
export namespace Outcomes {
export const FormFieldWithAriaRoleHasName = (role: Role.Name) =>
Ok.of(WithRole.of(`The form field has an accessible name`, role));

export const FormFieldWithAriaRoleHasNoName = (role: Role.Name) =>
Err.of(
WithRole.of(`The form field does not have an accessible name`, role),
);

export const InputElementWithNoAriaRoleHasName = (typeAttribValue: Element.InputType) =>
Ok.of(Diagnostic.of(`The type="${typeAttribValue}" form field has an accessible name`));

export const InputElementWithNoAriaRoleHasNoName = (typeAttribValue: Element.InputType) =>
Err.of(Diagnostic.of(`The type="${typeAttribValue}" form field does not have an accessible name`));
}
1 change: 1 addition & 0 deletions packages/alfa-rules/src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"./sia-dr36/rule.ts",
"./sia-dr66/rule.ts",
"./sia-dr69/rule.ts",
"./sia-er8/rule.ts",
"./sia-er87/rule.ts",
"./sia-r1/rule.ts",
"./sia-r10/rule.ts",
Expand Down
Loading

0 comments on commit 15fabab

Please sign in to comment.