Skip to content

Commit

Permalink
Merge branch 'develop' into improve-ja-translation-20230427-squashed
Browse files Browse the repository at this point in the history
  • Loading branch information
ma10 committed Aug 22, 2023
2 parents 141ba17 + 381b2c3 commit 380bf35
Show file tree
Hide file tree
Showing 81 changed files with 4,083 additions and 2,215 deletions.
3 changes: 2 additions & 1 deletion axe.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ declare namespace axe {
type AxeReporter<T = unknown> = (
rawResults: RawResult[],
option: RunOptions,
callback: (report: T) => void
resolve: (report: T) => void,
reject: (error: Error) => void
) => void;

interface VirtualNode {
Expand Down
37 changes: 19 additions & 18 deletions doc/examples/jsdom/test/a11y.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* global describe, it */
const axe = require('axe-core');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
const assert = require('assert');

describe('axe', () => {
const { window } = new JSDOM(`<!DOCTYPE html>
const { document } = new JSDOM(`<!DOCTYPE html>
<html lang="en">
<head>
<title>JSDOM Example</title>
Expand All @@ -18,30 +19,30 @@ describe('axe', () => {
<p>Not a label</p><input type="text" id="no-label">
</div>
</body>
</html>`);

const axe = require('axe-core');
</html>`).window;
const config = {
rules: {
'color-contrast': { enabled: false }
}
};

it('should report that good HTML is good', function (done) {
var n = window.document.getElementById('working');
axe.run(n, config, function (err, result) {
assert.equal(err, null, 'Error is not null');
assert.equal(result.violations.length, 0, 'Violations is not empty');
done();
});
it('reports that good HTML is good', async () => {
const node = document.getElementById('working');
const result = await axe.run(node, config);
assert.equal(result.violations.length, 0, 'Violations is not empty');
});

it('reports that bad HTML is bad', async () => {
const node = document.getElementById('broken');
const results = await axe.run(node, config);
assert.equal(results.violations.length, 1, 'Violations.length is not 1');
});

it('should report that bad HTML is bad', function (done) {
var n = window.document.getElementById('broken');
axe.run(n, config, function (err, result) {
assert.equal(err, null, 'Error is not null');
assert.equal(result.violations.length, 1, 'Violations.length is not 1');
done();
});
it('allows commons after axe.setup() is called', () => {
axe.setup(document);
const input = document.querySelector('input');
const role = axe.commons.aria.getRole(input);
assert.equal(role, 'textbox');
axe.teardown();
});
});
2 changes: 1 addition & 1 deletion doc/rule-descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
| :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [area-alt](https://dequeuniversity.com/rules/axe/4.7/area-alt?application=RuleDescription) | Ensures &lt;area&gt; elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag244, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.2.4.4, EN-9.4.1.2, ACT | failure, needs&nbsp;review | [c487ae](https://act-rules.github.io/rules/c487ae) |
| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.7/aria-allowed-attr?application=RuleDescription) | Ensures an element&apos;s role supports its ARIA attributes | Critical | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure, needs&nbsp;review | [5c01ea](https://act-rules.github.io/rules/5c01ea) |
| [aria-braille-equivalent](https://dequeuniversity.com/rules/axe/4.7/aria-braille-equivalent?application=RuleDescription) | Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure, needs&nbsp;review | |
| [aria-braille-equivalent](https://dequeuniversity.com/rules/axe/4.7/aria-braille-equivalent?application=RuleDescription) | Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | needs&nbsp;review | |
| [aria-command-name](https://dequeuniversity.com/rules/axe/4.7/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, ACT | failure, needs&nbsp;review | [97a4e1](https://act-rules.github.io/rules/97a4e1) |
| [aria-conditional-attr](https://dequeuniversity.com/rules/axe/4.7/aria-conditional-attr?application=RuleDescription) | Ensures ARIA attributes are used as described in the specification of the element&apos;s role | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure | [5c01ea](https://act-rules.github.io/rules/5c01ea) |
| [aria-deprecated-role](https://dequeuniversity.com/rules/axe/4.7/aria-deprecated-role?application=RuleDescription) | Ensures elements do not use deprecated roles | Minor | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2 | failure | [674b10](https://act-rules.github.io/rules/674b10) |
Expand Down
2 changes: 2 additions & 0 deletions doc/run-partial.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const axeResults = await axe.finishRun(partialResults, options);

**note**: The code in this page uses native DOM methods. This will only work on frames with the same origin. Scripts do not have access to `contentWindow` of cross-origin frames. Use of `runPartial` and `finishRun` in browser drivers like Selenium and Puppeteer works in the same way.

**note**: Because `axe.runPartial()` is designed to be serialized, it will not return element references even if the `elementRef` option is set.

## axe.runPartial(context, options): Promise<PartialResult>

When using `axe.runPartial()` it is important to keep in mind that the `context` may be different for different frames. For example, `context` can be done in such a way that in frame A, `main` is excluded, and in frame B `footer` is. The `axe.utils.getFrameContexts` method will provide a list of frames that must be tested, and what context to test it with.
Expand Down
4 changes: 3 additions & 1 deletion lib/checks/mobile/target-offset-evaluate.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export default function targetOffsetEvaluate(node, options, vNode) {
if (getRoleType(vNeighbor) !== 'widget' || !isFocusable(vNeighbor)) {
continue;
}
const offset = roundToSingleDecimal(getOffset(vNode, vNeighbor));
// the offset code works off radius but we want our messaging to reflect diameter
const offset =
roundToSingleDecimal(getOffset(vNode, vNeighbor, minOffset / 2)) * 2;
if (offset + roundingMargin >= minOffset) {
continue;
}
Expand Down
8 changes: 4 additions & 4 deletions lib/checks/mobile/target-offset.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
"metadata": {
"impact": "serious",
"messages": {
"pass": "Target has sufficient offset from its closest neighbor (${data.closestOffset}px should be at least ${data.minOffset}px)",
"fail": "Target has insufficient offset from its closest neighbor (${data.closestOffset}px should be at least ${data.minOffset}px)",
"pass": "Target has sufficient space from its closest neighbors (${data.closestOffset}px should be at least ${data.minOffset}px)",
"fail": "Target has insufficient space to its closest neighbors. Safe clickable space has a diameter of {$data.closestOffset}px instead of at least ${data.minOffset}px)",
"incomplete": {
"default": "Element with negative tabindex has insufficient offset from its closest neighbor (${data.closestOffset}px should be at least ${data.minOffset}px). Is this a target?",
"nonTabbableNeighbor": "Target has insufficient offset from a neighbor with negative tabindex (${data.closestOffset}px should be at least ${data.minOffset}px). Is the neighbor a target?"
"default": "Element with negative tabindex has insufficient space to its closest neighbors. Safe clickable space has a diameter of {$data.closestOffset}px instead of at least ${data.minOffset}px). Is this a target?",
"nonTabbableNeighbor": "Target has insufficient space to its closest neighbors. Safe clickable space has a diameter of {$data.closestOffset}px instead of at least ${data.minOffset}px). Is the neighbor a target?"
}
}
}
Expand Down
14 changes: 5 additions & 9 deletions lib/checks/mobile/target-size-evaluate.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { findNearbyElms, isFocusable, isInTabOrder } from '../../commons/dom';
import { getRoleType } from '../../commons/aria';
import { splitRects, hasVisualOverlap } from '../../commons/math';

const roundingMargin = 0.05;
import {
splitRects,
rectHasMinimumSize,
hasVisualOverlap
} from '../../commons/math';

/**
* Determine if an element has a minimum size, taking into account
Expand Down Expand Up @@ -165,12 +167,6 @@ function isDescendantNotInTabOrder(vAncestor, vNode) {
);
}

function rectHasMinimumSize(minSize, { width, height }) {
return (
width + roundingMargin >= minSize && height + roundingMargin >= minSize
);
}

function mapActualNodes(vNodes) {
return vNodes.map(({ actualNode }) => actualNode);
}
38 changes: 38 additions & 0 deletions lib/commons/dom/get-target-rects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import findNearbyElms from './find-nearby-elms';
import isInTabOrder from './is-in-tab-order';
import { splitRects, hasVisualOverlap } from '../math';
import memoize from '../../core/utils/memoize';

export default memoize(getTargetRects);

/**
* Return all unobscured rects of a target.
* @see https://www.w3.org/TR/WCAG22/#dfn-bounding-boxes
* @param {VitualNode} vNode
* @return {DOMRect[]}
*/
function getTargetRects(vNode) {
const nodeRect = vNode.boundingClientRect;
const overlappingVNodes = findNearbyElms(vNode).filter(vNeighbor => {
return (
hasVisualOverlap(vNode, vNeighbor) &&
vNeighbor.getComputedStylePropertyValue('pointer-events') !== 'none' &&
!isDescendantNotInTabOrder(vNode, vNeighbor)
);
});

if (!overlappingVNodes.length) {
return [nodeRect];
}

const obscuringRects = overlappingVNodes.map(
({ boundingClientRect: rect }) => rect
);
return splitRects(nodeRect, obscuringRects);
}

function isDescendantNotInTabOrder(vAncestor, vNode) {
return (
vAncestor.actualNode.contains(vNode.actualNode) && !isInTabOrder(vNode)
);
}
29 changes: 29 additions & 0 deletions lib/commons/dom/get-target-size.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import getTargetRects from './get-target-rects';
import { rectHasMinimumSize } from '../math';
import memoize from '../../core/utils/memoize';

export default memoize(getTargetSize);

/**
* Compute the target size of an element.
* @see https://www.w3.org/TR/WCAG22/#dfn-targets
*/
function getTargetSize(vNode, minSize) {
const rects = getTargetRects(vNode);
return getLargestRect(rects, minSize);
}

// Find the largest rectangle in the array, prioritize ones that meet a minimum size
function getLargestRect(rects, minSize) {
return rects.reduce((rectA, rectB) => {
const rectAisMinimum = rectHasMinimumSize(minSize, rectA);
const rectBisMinimum = rectHasMinimumSize(minSize, rectB);
// Prioritize rects that pass the minimum
if (rectAisMinimum !== rectBisMinimum) {
return rectAisMinimum ? rectA : rectB;
}
const areaA = rectA.width * rectA.height;
const areaB = rectB.width * rectB.height;
return areaA > areaB ? rectA : rectB;
});
}
2 changes: 2 additions & 0 deletions lib/commons/dom/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export { default as getOverflowHiddenAncestors } from './get-overflow-hidden-anc
export { default as getRootNode } from './get-root-node';
export { default as getScrollOffset } from './get-scroll-offset';
export { default as getTabbableElements } from './get-tabbable-elements';
export { default as getTargetRects } from './get-target-rects';
export { default as getTargetSize } from './get-target-size';
export { default as getTextElementStack } from './get-text-element-stack';
export { default as getViewportSize } from './get-viewport-size';
export { default as getVisibleChildTextRects } from './get-visible-child-text-rects';
Expand Down
Loading

0 comments on commit 380bf35

Please sign in to comment.