Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIA-R65: Provide classes and number of matches in diagnostic #1164

Merged
merged 15 commits into from
Jul 8, 2022
Merged
60 changes: 60 additions & 0 deletions packages/alfa-rules/src/sia-er65/diagnostics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Diagnostic } from "@siteimprove/alfa-act";

export type Reason = "auto-detected" | "user-answered" | "good-class";
zsofitoth marked this conversation as resolved.
Show resolved Hide resolved

/**
* @internal
*/
export class ExtendedDiagnostic extends Diagnostic {
public static of(
zsofitoth marked this conversation as resolved.
Show resolved Hide resolved
message: string,
reason: Reason = "good-class"
): ExtendedDiagnostic {
return new ExtendedDiagnostic(message, reason);
}

private readonly _reason: Reason;

private constructor(message: string, reason: Reason) {
super(message);
this._reason = reason;
}

public equals(value: ExtendedDiagnostic): boolean;

public equals(value: unknown): value is this;

public equals(value: unknown): boolean {
return (
value instanceof ExtendedDiagnostic && value._reason === this._reason
);
}

public toJSON(): ExtendedDiagnostic.JSON {
return {
...super.toJSON(),
reason: this._reason,
};
}
}

/**
* @internal
*/
export namespace ExtendedDiagnostic {
export interface JSON extends Diagnostic.JSON {}
zsofitoth marked this conversation as resolved.
Show resolved Hide resolved

export function isExtendedDiagnostic(
value: Diagnostic
): value is ExtendedDiagnostic;

export function isExtendedDiagnostic(
value: unknown
): value is ExtendedDiagnostic;

export function isExtendedDiagnostic(
value: unknown
): value is ExtendedDiagnostic {
return value instanceof ExtendedDiagnostic;
}
}
33 changes: 23 additions & 10 deletions packages/alfa-rules/src/sia-er65/rule.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Rule, Diagnostic } from "@siteimprove/alfa-act";
import { Rule } from "@siteimprove/alfa-act";
import { Keyword } from "@siteimprove/alfa-css";
import { Device } from "@siteimprove/alfa-device";
import { Document, Element } from "@siteimprove/alfa-dom";
Expand All @@ -16,6 +16,8 @@ import { expectation } from "../common/act/expectation";
import { Question } from "../common/act/question";
import { Scope, Stability, Version } from "../tags";

import { ExtendedDiagnostic, Reason } from "./diagnostics";

const { isElement } = Element;
const { isKeyword } = Keyword;
const { or, test, xor } = Predicate;
Expand Down Expand Up @@ -59,6 +61,9 @@ export default Rule.Atomic.of<
);

const askFocusIndicator = Question.of("has-focus-indicator", target);
const reason: Reason = hasFocusIndicator(device)(target)
zsofitoth marked this conversation as resolved.
Show resolved Hide resolved
? "auto-detected"
: "user-answered";

return {
1: askGoodClasses
Expand All @@ -77,8 +82,8 @@ export default Rule.Atomic.of<
.map((hasFocusIndicator) =>
expectation(
hasFocusIndicator,
() => Outcomes.HasFocusIndicator,
() => Outcomes.HasNoFocusIndicator
() => Outcomes.HasFocusIndicator(reason),
() => Outcomes.HasNoFocusIndicator(reason)
)
)
)
Expand All @@ -90,16 +95,24 @@ export default Rule.Atomic.of<
});

export namespace Outcomes {
export const HasFocusIndicator = Ok.of(
Diagnostic.of(`The element has a visible focus indicator`)
);
export const HasFocusIndicator = (reason: Reason) =>
Ok.of(
ExtendedDiagnostic.of(`The element has a visible focus indicator`, reason)
);

export const HasNoFocusIndicator = Err.of(
Diagnostic.of(`The element does not have a visible focus indicator`)
);
export const HasNoFocusIndicator = (reason: Reason) =>
Err.of(
ExtendedDiagnostic.of(
`The element does not have a visible focus indicator`,
reason
)
);

export const HasGoodClass = Ok.of(
Diagnostic.of("The element has a class ensuring a visible focus indicator")
ExtendedDiagnostic.of(
"The element has a class ensuring a visible focus indicator",
"good-class"
)
);
}

Expand Down
66 changes: 33 additions & 33 deletions packages/alfa-rules/test/sia-er65/rule.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ test(`evaluate() passes an <a> element that uses the default focus outline`, asy

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand All @@ -38,10 +38,10 @@ test(`evaluate() passes an <a> element that uses a non-default focus outline`, a

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand Down Expand Up @@ -71,10 +71,10 @@ test(`evaluate() fails an <a> element that removes the default focus outline and
),
[
failed(R65, target, {
1: Outcomes.HasNoFocusIndicator,
1: Outcomes.HasNoFocusIndicator("user-answered"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]
);
Expand Down Expand Up @@ -105,10 +105,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline
),
[
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("user-answered"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]
);
Expand Down Expand Up @@ -136,10 +136,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand All @@ -165,10 +165,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand Down Expand Up @@ -198,10 +198,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand All @@ -227,10 +227,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand Down Expand Up @@ -261,10 +261,10 @@ test(`evaluate() fails an <a> element that removes the default focus outline
),
[
failed(R65, target, {
1: Outcomes.HasNoFocusIndicator,
1: Outcomes.HasNoFocusIndicator("user-answered"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]
);
Expand Down Expand Up @@ -294,10 +294,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand Down Expand Up @@ -326,10 +326,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand All @@ -356,10 +356,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand All @@ -382,10 +382,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand All @@ -411,10 +411,10 @@ test(`evaluate() passes an <a> element that removes the default focus outline

t.deepEqual(await evaluate(R65, { document }), [
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]);
});
Expand Down Expand Up @@ -445,7 +445,7 @@ test(`evaluate() passes an <a> element that has a class determined to have some
1: Outcomes.HasGoodClass,
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]
);
Expand Down Expand Up @@ -474,10 +474,10 @@ test(`evaluate() passes an <a> element that does not have a class determined to
),
[
passed(R65, target, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]
);
Expand Down Expand Up @@ -516,10 +516,10 @@ test(`evaluate() falis an <a> element that does not have a class determined to h
),
[
failed(R65, target, {
1: Outcomes.HasNoFocusIndicator,
1: Outcomes.HasNoFocusIndicator("user-answered"),
}),
passed(R65, <button />, {
1: Outcomes.HasFocusIndicator,
1: Outcomes.HasFocusIndicator("auto-detected"),
}),
]
);
Expand Down
1 change: 1 addition & 0 deletions packages/alfa-rules/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"src/sia-er62/rule.ts",
"src/sia-er62/diagnostics.ts",
"src/sia-er62/serialise.ts",
"src/sia-er65/diagnostics.ts",
"src/sia-er65/rule.ts",
"src/sia-er87/rule.ts",
"src/sia-r1/rule.ts",
Expand Down