diff --git a/CHANGELOG.md b/CHANGELOG.md
index f0fe5c41da..6fa5753efc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,16 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+### [4.8.4](https://github.com/dequelabs/axe-core/compare/v4.8.3...v4.8.4) (2024-02-07)
+
+### Bug Fixes
+
+- Add LICENSE-3RD-PARTY.txt file ([#4304](https://github.com/dequelabs/axe-core/issues/4304)) ([139c553](https://github.com/dequelabs/axe-core/commit/139c5535c72e926f03bb37a9ba0b7fd6b97cba8c))
+- avoid reading element-specific node properties of non-element node types ([#4317](https://github.com/dequelabs/axe-core/issues/4317)) ([a2a6935](https://github.com/dequelabs/axe-core/commit/a2a69355ea5aafce14367cf967153f7958a8878c)), closes [#4316](https://github.com/dequelabs/axe-core/issues/4316) [#4316](https://github.com/dequelabs/axe-core/issues/4316)
+- **d.ts:** RawNodesResult issues ([#4229](https://github.com/dequelabs/axe-core/issues/4229)) ([f105266](https://github.com/dequelabs/axe-core/commit/f1052662b3b8b57d520fcbd23a3e9d4a5660a7e1))
+- **d.ts:** RunOptions.reporter can be any string ([#4218](https://github.com/dequelabs/axe-core/issues/4218)) ([80de793](https://github.com/dequelabs/axe-core/commit/80de793362bbbffde85654e874942a26df0108a8))
+- **utils/get-selector:** ignore 'xmlns' attribute when generating a selector ([#4303](https://github.com/dequelabs/axe-core/issues/4303)) ([8c68546](https://github.com/dequelabs/axe-core/commit/8c6854661f4613d0b7a6ba98bbfdc0c9ca61b4d1))
+
### [4.8.3](https://github.com/dequelabs/axe-core/compare/v4.8.2...v4.8.3) (2023-12-18)
### Bug Fixes
diff --git a/LICENSE-3RD-PARTY.txt b/LICENSE-3RD-PARTY.txt
new file mode 100644
index 0000000000..368c293bef
--- /dev/null
+++ b/LICENSE-3RD-PARTY.txt
@@ -0,0 +1,66 @@
+-----------------------------------------------------------------------------
+ MIT License
+ Applies to:
+ - colorjs.io; Copyright (c) 2021 Lea Verou, Chris Lilley
+ - core-js-pure; Copyright (c) 2014-2023 Denis Pushkarev
+ - css-selector-parser; Copyright (c) 2013 Dulin Marat
+ - doT.js; Copyright (c) 2011 Laura Doktorova
+ Software includes portions from jQote2 Copyright (c) 2010 aefxx,
+ http://aefxx.com/ licensed under the MIT license.
+ - emoji-regex; Copyright (c) Mathias Bynens
+ - es6-iterator; Copyright (c) 2013-2017 Mariusz Nowak (www.medikoo.com)
+ - es6-promise;
+ Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
+ - event-emitter; Copyright (C) 2012-2015 Mariusz Nowak (www.medikoo.com)
+ - is-promise; Copyright (c) 2014 Forbes Lindesay
+ - lru-queue; Copyright (C) 2014 Mariusz Nowak (www.medikoo.com)
+ - typedarray;
+ Copyright (c) 2010, Linden Research, Inc.
+ Copyright (c) 2012, Joshua Bell
+ - weakmap-polyfill; Copyright (c) 2015-2021 polygonplanet
+-----------------------------------------------------------------------------
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+-----------------------------------------------------------------------------
+ ISC License
+ Applies to:
+ - d; Copyright (c) 2013-2019, Mariusz Nowak, @medikoo, medikoo.com
+ - es5-ext; Copyright (c) 2011-2022, Mariusz Nowak, @medikoo, medikoo.com
+ - es6-symbol; Copyright (c) 2013-2019, Mariusz Nowak, @medikoo, medikoo.com
+ - es6-weak-map; Copyright (c) 2013-2018, Mariusz Nowak, @medikoo, medikoo.com
+ - ext; Copyright (c) 2011-2022, Mariusz Nowak, @medikoo, medikoo.com
+ - memoizee; Copyright (c) 2012-2018, Mariusz Nowak, @medikoo, medikoo.com
+ - next-tick; Copyright (c) 2012-2020, Mariusz Nowak, @medikoo, medikoo.com
+ - timers-ext; Copyright (c) 2013-2018, Mariusz Nowak, @medikoo, medikoo.com
+ - type; Copyright (c) 2019, Mariusz Nowak, @medikoo, medikoo.com
+-----------------------------------------------------------------------------
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
index 1812ee0b1b..5697270b10 100644
--- a/README.md
+++ b/README.md
@@ -179,6 +179,8 @@ Read the [documentation on contributing](CONTRIBUTING.md)
## Acknowledgements
-Thanks to Marat Dulin for his [css-selector-parser](https://www.npmjs.com/package/css-selector-parser) implementation which is included for shadow DOM support.
+Thanks to Marat Dulin for his [css-selector-parser](https://www.npmjs.com/package/css-selector-parser) implementation which is included for shadow DOM support. Another thank you to the [Slick Parser](https://github.com/mootools/slick/blob/master/Source/Slick.Parser.js) implementers for their contribution, we have used some of their algorithms in our shadow DOM support code. Thanks to Lea Verou and Chris Lilley for their [colorjs.io](https://colorjs.io/) library which we have used for converting between color formats.
-Thanks to the [Slick Parser](https://github.com/mootools/slick/blob/master/Source/Slick.Parser.js) implementers for their contribution, we have used some of their algorithms in our shadow DOM support code.
+## Licenses
+
+Axe-core is distributed under the [Mozilla Public License, version 2.0](LICENSE). It comes bundled with several dependencies which are distributed under their own terms. (See [LICENSE-3RD-PARTY.txt](LICENSE-3RD-PARTY.txt))
diff --git a/axe.d.ts b/axe.d.ts
index 403e504873..8ecd9de75a 100644
--- a/axe.d.ts
+++ b/axe.d.ts
@@ -1,13 +1,12 @@
// Type definitions for axe-core
// Project: https://github.com/dequelabs/axe-core
-// Definitions by: Marcy Sutton
declare namespace axe {
type ImpactValue = 'minor' | 'moderate' | 'serious' | 'critical' | null;
type TagValue = string;
- type ReporterVersion = 'v1' | 'v2' | 'raw' | 'raw-env' | 'no-passes';
+ type ReporterVersion = 'v1' | 'v2' | 'raw' | 'rawEnv' | 'no-passes';
type RunOnlyType = 'rule' | 'rules' | 'tag' | 'tags';
@@ -132,7 +131,7 @@ declare namespace axe {
interface RunOptions {
runOnly?: RunOnly | TagValue[] | string[] | string;
rules?: RuleObject;
- reporter?: ReporterVersion;
+ reporter?: ReporterVersion | string;
resultTypes?: resultGroups[];
selectors?: boolean;
ancestry?: boolean;
@@ -333,6 +332,14 @@ declare namespace axe {
xpath: string[];
ancestry: UnlabelledFrameSelector;
}
+ interface DqElement extends SerialDqElement {
+ element: Element;
+ toJSON(): SerialDqElement;
+ mergeSpecs(
+ childSpec: SerialDqElement,
+ parentSpec: SerialDqElement
+ ): SerialDqElement;
+ }
interface PartialRuleResult {
id: string;
result: 'inapplicable';
@@ -351,16 +358,21 @@ declare namespace axe {
frameContext: FrameContextObject;
}
+ interface RawCheckResult extends Omit {
+ relatedNodes?: Array;
+ }
+
interface RawNodeResult {
- any: CheckResult[];
- all: CheckResult[];
- none: CheckResult[];
+ node: SerialDqElement | DqElement;
+ any: RawCheckResult[];
+ all: RawCheckResult[];
+ none: RawCheckResult[];
impact: ImpactValue | null;
result: T;
}
interface RawResult extends Omit {
- inapplicable: [];
+ inapplicable: Array;
passes: RawNodeResult<'passed'>[];
incomplete: RawNodeResult<'incomplete'>[];
violations: RawNodeResult<'failed'>[];
@@ -383,6 +395,7 @@ declare namespace axe {
attr(attr: string): string | null;
hasAttr(attr: string): boolean;
props: { [key: string]: unknown };
+ boundingClientRect: DOMRect;
}
interface Utils {
@@ -396,7 +409,7 @@ declare namespace axe {
DqElement: new (
elm: Element,
options?: { absolutePaths?: boolean }
- ) => SerialDqElement;
+ ) => DqElement;
uuid: (
options?: { random?: Uint8Array | Array },
buf?: Uint8Array | Array,
diff --git a/bower.json b/bower.json
index fac1bab71a..27a80bd8c1 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "axe-core",
- "version": "4.8.3",
+ "version": "4.8.4",
"deprecated": true,
"contributors": [
{
diff --git a/doc/examples/mocha/package.json b/doc/examples/mocha/package.json
index 002eb36f09..870909591d 100644
--- a/doc/examples/mocha/package.json
+++ b/doc/examples/mocha/package.json
@@ -13,6 +13,7 @@
},
"devDependencies": {
"axe-core": "^4.6.2",
+ "chai": "^4.3.7",
"karma": "^6.4.1",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.1.1",
diff --git a/lib/core/base/virtual-node/virtual-node.js b/lib/core/base/virtual-node/virtual-node.js
index 589b61237f..4a19c8b021 100644
--- a/lib/core/base/virtual-node/virtual-node.js
+++ b/lib/core/base/virtual-node/virtual-node.js
@@ -51,30 +51,25 @@ class VirtualNode extends AbstractVirtualNode {
// add to the prototype so memory is shared across all virtual nodes
get props() {
if (!this._cache.hasOwnProperty('props')) {
- const {
- nodeType,
- nodeName,
- id,
- multiple,
- nodeValue,
- value,
- selected,
- checked,
- indeterminate
- } = this.actualNode;
+ const { nodeType, nodeName, id, nodeValue } = this.actualNode;
this._cache.props = {
nodeType,
nodeName: this._isXHTML ? nodeName : nodeName.toLowerCase(),
id,
type: this._type,
- multiple,
- nodeValue,
- value,
- selected,
- checked,
- indeterminate
+ nodeValue
};
+
+ // We avoid reading these on node types where they won't be relevant
+ // to work around issues like #4316.
+ if (nodeType === 1) {
+ this._cache.props.multiple = this.actualNode.multiple;
+ this._cache.props.value = this.actualNode.value;
+ this._cache.props.selected = this.actualNode.selected;
+ this._cache.props.checked = this.actualNode.checked;
+ this._cache.props.indeterminate = this.actualNode.indeterminate;
+ }
}
return this._cache.props;
diff --git a/lib/core/utils/get-selector.js b/lib/core/utils/get-selector.js
index 28af5bf6af..a90d3c1528 100644
--- a/lib/core/utils/get-selector.js
+++ b/lib/core/utils/get-selector.js
@@ -22,7 +22,8 @@ const ignoredAttributes = [
'aria-expanded',
'aria-grabbed',
'aria-pressed',
- 'aria-valuenow'
+ 'aria-valuenow',
+ 'xmlns'
];
const MAXATTRIBUTELENGTH = 31;
const attrCharsRegex = /([\\"])/g;
diff --git a/package-lock.json b/package-lock.json
index 820325f185..1f52d91f50 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "axe-core",
- "version": "4.8.3",
+ "version": "4.8.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "axe-core",
- "version": "4.8.3",
+ "version": "4.8.4",
"license": "MPL-2.0",
"devDependencies": {
"@axe-core/webdriverjs": "^4.5.2",
diff --git a/package.json b/package.json
index a6c34d59c3..74c6186edd 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "axe-core",
"description": "Accessibility engine for automated Web UI testing",
- "version": "4.8.3",
+ "version": "4.8.4",
"license": "MPL-2.0",
"engines": {
"node": ">=4"
@@ -55,7 +55,8 @@
"axe.min.js",
"axe.d.ts",
"sri-history.json",
- "locales/"
+ "locales/",
+ "LICENSE-3RD-PARTY.txt"
],
"standard-version": {
"scripts": {
diff --git a/sri-history.json b/sri-history.json
index a842d92fa6..48678b1c35 100644
--- a/sri-history.json
+++ b/sri-history.json
@@ -366,5 +366,9 @@
"4.8.3": {
"axe.js": "sha256-YWpAAdIo7fwKmLq8nJx1f6pwt7HAXwWm15RSGJKbxhw=",
"axe.min.js": "sha256-/mct+I/4SJnZ30Ce+j9T7ll9zPwzbJVrjdKpbKIP+NA="
+ },
+ "4.8.4": {
+ "axe.js": "sha256-RRn+EjX3fX893zHeLzMQebvK4/HR3yZpVFNxsV3Pbm0=",
+ "axe.min.js": "sha256-HXl1GEx0+LwVB27fLmwgdXCmeTM2beVwwFosWvFzLmo="
}
}
diff --git a/test/core/base/virtual-node/virtual-node.js b/test/core/base/virtual-node/virtual-node.js
index 771d3693b1..338442d75e 100644
--- a/test/core/base/virtual-node/virtual-node.js
+++ b/test/core/base/virtual-node/virtual-node.js
@@ -37,15 +37,45 @@ describe('VirtualNode', () => {
assert.equal(vNode.props.type, 'text');
});
- it('should reflect selected property', () => {
- node = document.createElement('option');
- let vNode = new VirtualNode(node);
- assert.equal(vNode.props.selected, false);
-
- node.selected = true;
- vNode = new VirtualNode(node);
- assert.equal(vNode.props.selected, true);
- });
+ for (const [prop, tagName, examplePropValue] of [
+ ['value', 'input', 'test value'],
+ ['selected', 'option', true],
+ ['checked', 'input', true],
+ ['indeterminate', 'input', true],
+ ['multiple', 'select', true]
+ ]) {
+ describe(`props.${prop}`, () => {
+ it(`should reflect a ${tagName} element's ${prop} property`, () => {
+ node = document.createElement(tagName);
+ let vNode = new VirtualNode(node);
+ assert.equal(vNode.props[prop], '');
+
+ node[prop] = examplePropValue;
+ vNode = new VirtualNode(node);
+ assert.equal(vNode.props[prop], examplePropValue);
+ });
+
+ it('should be undefined for a text node', () => {
+ node = document.createTextNode('text content');
+ let vNode = new VirtualNode(node);
+ assert.equal(vNode.props[prop], undefined);
+ });
+
+ // Regression test for #4316
+ it(`should be resilient to text node with un-gettable ${prop} property`, () => {
+ node = document.createTextNode('text content');
+ Object.defineProperty(node, prop, {
+ get() {
+ throw new Error('Unqueryable value');
+ }
+ });
+ let vNode = new VirtualNode(node);
+ assert.throws(() => node[prop]);
+ assert.doesNotThrow(() => vNode.props[prop]);
+ assert.equal(vNode.props[prop], undefined);
+ });
+ });
+ }
it('should lowercase type', () => {
node = document.createElement('input');
diff --git a/test/core/utils/get-selector.js b/test/core/utils/get-selector.js
index 520bfbea56..0a2cab5b78 100644
--- a/test/core/utils/get-selector.js
+++ b/test/core/utils/get-selector.js
@@ -471,7 +471,8 @@ describe('axe.utils.getSelector', function () {
'aria-expanded',
'aria-grabbed',
'aria-pressed',
- 'aria-valuenow'
+ 'aria-valuenow',
+ 'xmlns'
];
ignoredAttributes.forEach(function (att) {
node.setAttribute(att, 'true');
diff --git a/typings/axe-core/axe-core-tests.ts b/typings/axe-core/axe-core-tests.ts
index bff4ec46da..5d421307a8 100644
--- a/typings/axe-core/axe-core-tests.ts
+++ b/typings/axe-core/axe-core-tests.ts
@@ -2,7 +2,13 @@ import * as axe from '../../axe';
var context: any = document;
var $fixture = [document];
-var options = { iframes: false, selectors: false, elementRef: false };
+var options: axe.RunOptions = {
+ iframes: false,
+ selectors: false,
+ elementRef: false
+};
+options.reporter = 'rawEnv';
+options.reporter = 'custom';
axe.run(context, {}, (error: Error, results: axe.AxeResults) => {
if (error) {
@@ -344,6 +350,44 @@ axe.configure({
}
});
+const results: axe.RawResult[] = [
+ {
+ id: 'the-best-rule',
+ result: 'passed',
+ pageLevel: false,
+ impact: null,
+ tags: ['best-practice'],
+ description: 'Be cool',
+ help: 'No, cooler',
+ helpUrl:
+ 'https://dequeuniversity.com/rules/axe/4.8/the-best-rule?application=axeAPI',
+ inapplicable: [],
+ passes: [
+ {
+ any: [
+ {
+ id: 'the-best-check',
+ data: null,
+ impact: 'serious',
+ message: 'Element has sufficient color contrast of 21',
+ relatedNodes: [
+ new axe.utils.DqElement(document.body),
+ new axe.utils.DqElement(document.body).toJSON()
+ ]
+ }
+ ],
+ all: [],
+ none: [],
+ impact: null,
+ result: 'passed',
+ node: new axe.utils.DqElement(document.body)
+ }
+ ],
+ incomplete: [],
+ violations: []
+ }
+];
+
// Reporters
let fooReporter = (
results: axe.RawResult[],