-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Copy implementation of R70 * Update documentation * Comments implemented * Update alfa-rules.api.md * Update rule.ts * Update alfa-rules.api.md Co-authored-by: elenamongelli <[email protected]>
- Loading branch information
1 parent
3ea3457
commit 170bb71
Showing
5 changed files
with
258 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { Rule, Diagnostic } from "@siteimprove/alfa-act"; | ||
import { Array } from "@siteimprove/alfa-array"; | ||
import { Document, Element, Namespace } from "@siteimprove/alfa-dom"; | ||
import { Iterable } from "@siteimprove/alfa-iterable"; | ||
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 { hasChild, isRendered, isDocumentElement } from "../common/predicate"; | ||
|
||
const { isElement, hasName, hasNamespace } = Element; | ||
const { and, test } = Predicate; | ||
|
||
const isDeprecated = hasName( | ||
"acronym", | ||
"applet", | ||
"basefont", | ||
"bgsound", | ||
"big", | ||
"blink", | ||
"center", | ||
"content", | ||
"dir", | ||
"font", | ||
"frame", | ||
"frameset", | ||
"hgroup", | ||
"image", | ||
"keygen", | ||
"marquee", | ||
"menuitem", | ||
"nobr", | ||
"noembed", | ||
"noframes", | ||
"plaintext", | ||
"rb", | ||
"rtc", | ||
"shadow", | ||
"spacer", | ||
"strike", | ||
"tt", | ||
"xmp" | ||
); | ||
|
||
export default Rule.Atomic.of<Page, Document>({ | ||
uri: "https://alfa.siteimprove.com/rules/sia-r70", | ||
evaluate({ device, document }) { | ||
return { | ||
applicability() { | ||
return test(hasChild(isDocumentElement), document) ? [document] : []; | ||
}, | ||
|
||
expectations(target) { | ||
const deprecatedElements = target | ||
.descendants({ flattened: true, nested: true }) | ||
.filter(isElement) | ||
.filter( | ||
and(hasNamespace(Namespace.HTML), isDeprecated, isRendered(device)) | ||
); | ||
|
||
return { | ||
1: expectation( | ||
deprecatedElements.isEmpty(), | ||
() => Outcomes.HasNoDeprecatedElement, | ||
() => Outcomes.HasDeprecatedElements(deprecatedElements) | ||
), | ||
}; | ||
}, | ||
}; | ||
}, | ||
}); | ||
|
||
export namespace Outcomes { | ||
export const HasNoDeprecatedElement = Ok.of( | ||
Diagnostic.of(`The document doesn't contain any deprecated elements`) | ||
); | ||
|
||
export const HasDeprecatedElements = (errors: Iterable<Element>) => | ||
Err.of( | ||
DeprecatedElements.of(`The document contains deprecated elements`, errors) | ||
); | ||
} | ||
|
||
class DeprecatedElements extends Diagnostic implements Iterable<Element> { | ||
public static of( | ||
message: string, | ||
errors: Iterable<Element> = [] | ||
): DeprecatedElements { | ||
return new DeprecatedElements(message, Array.from(errors)); | ||
} | ||
|
||
private _errors: ReadonlyArray<Element>; | ||
|
||
private constructor(message: string, errors: Array<Element>) { | ||
super(message); | ||
this._errors = errors; | ||
} | ||
|
||
public get errors(): ReadonlyArray<Element> { | ||
return this._errors; | ||
} | ||
|
||
public equals(value: DeprecatedElements): boolean; | ||
|
||
public equals(value: unknown): value is this; | ||
|
||
public equals(value: unknown): boolean { | ||
return ( | ||
value instanceof DeprecatedElements && | ||
value._message === this._message && | ||
Array.equals(value._errors, this._errors) | ||
); | ||
} | ||
|
||
public *[Symbol.iterator](): Iterator<Element> { | ||
yield* this._errors; | ||
} | ||
|
||
public toJSON(): DeprecatedElements.JSON { | ||
return { | ||
...super.toJSON(), | ||
errors: this._errors.map((element) => element.path()), | ||
}; | ||
} | ||
} | ||
|
||
namespace DeprecatedElements { | ||
export interface JSON extends Diagnostic.JSON { | ||
errors: Array<string>; | ||
} | ||
|
||
export function isDeprecatedElements( | ||
value: unknown | ||
): value is DeprecatedElements { | ||
return value instanceof DeprecatedElements; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { h } from "@siteimprove/alfa-dom"; | ||
import { test } from "@siteimprove/alfa-test"; | ||
|
||
import R70, { Outcomes } from "../../src/sia-r70/rule"; | ||
|
||
import { evaluate } from "../common/evaluate"; | ||
import { passed, failed, inapplicable } from "../common/outcome"; | ||
|
||
test("evaluate() passes a page with no deprecated / obsolete elements ", async (t) => { | ||
const target = ( | ||
<html> | ||
<p>Lorem ipsum.</p> | ||
</html> | ||
); | ||
|
||
const document = h.document([target]); | ||
|
||
t.deepEqual(await evaluate(R70, { document }), [ | ||
passed(R70, document, { | ||
1: Outcomes.HasNoDeprecatedElement, | ||
}), | ||
]); | ||
}); | ||
|
||
test("evaluate() passes a page with a deprecated but not rendered element", async (t) => { | ||
const target = ( | ||
<html> | ||
<p> | ||
Lorem <blink hidden>ipsum</blink> | ||
</p> | ||
</html> | ||
); | ||
|
||
const document = h.document([target]); | ||
|
||
t.deepEqual(await evaluate(R70, { document }), [ | ||
passed(R70, document, { | ||
1: Outcomes.HasNoDeprecatedElement, | ||
}), | ||
]); | ||
}); | ||
|
||
test("evaluate() fails a page with deprecated and rendered element", async (t) => { | ||
const blink = <blink>not</blink>; | ||
const target = ( | ||
<html> | ||
<p>Schrödinger's cat is {blink} dead.</p> | ||
</html> | ||
); | ||
|
||
const document = h.document([target]); | ||
|
||
t.deepEqual(await evaluate(R70, { document }), [ | ||
failed(R70, document, { | ||
1: Outcomes.HasDeprecatedElements([blink]), | ||
}), | ||
]); | ||
}); | ||
|
||
test("evaluate() fails a page with deprecated visible element", async (t) => { | ||
const blink = <blink aria-hidden="true">not</blink>; | ||
const target = ( | ||
<html> | ||
<p>Schrödinger's cat is {blink} dead.</p> | ||
</html> | ||
); | ||
|
||
const document = h.document([target]); | ||
|
||
t.deepEqual(await evaluate(R70, { document }), [ | ||
failed(R70, document, { | ||
1: Outcomes.HasDeprecatedElements([blink]), | ||
}), | ||
]); | ||
}); | ||
|
||
test("evaluate() fails a page with two deprecated elements in the accessibility tree", async (t) => { | ||
const menuitem1 = <menuitem role="menuitem">Foo</menuitem>; | ||
const menuitem2 = <menuitem role="menuitem">Bar</menuitem>; | ||
const target = ( | ||
<html> | ||
<ul role="menu" style={{ position: "absolute", left: "-9999px" }}> | ||
{menuitem1} | ||
{menuitem2} | ||
</ul> | ||
</html> | ||
); | ||
|
||
const document = h.document([target]); | ||
|
||
t.deepEqual(await evaluate(R70, { document }), [ | ||
failed(R70, document, { | ||
1: Outcomes.HasDeprecatedElements([menuitem1, menuitem2]), | ||
}), | ||
]); | ||
}); | ||
|
||
test("evaluate() is inapplicable to non-HTML documents", async (t) => { | ||
const document = h.document([ | ||
<svg xmlns="http://www.w3.org/2000/svg"> | ||
<title>This is a circle</title> | ||
<circle cx="150" cy="75" r="50" fill="green"></circle> | ||
</svg>, | ||
]); | ||
|
||
t.deepEqual(await evaluate(R70, { document }), [inapplicable(R70)]); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters