diff --git a/lib/commons/matches/attributes.js b/lib/commons/matches/attributes.js index c5a3a1f0eb..0445265473 100644 --- a/lib/commons/matches/attributes.js +++ b/lib/commons/matches/attributes.js @@ -1,4 +1,6 @@ import fromFunction from './from-function'; +import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node'; +import { getNodeFromTree } from '../../core/utils'; /** * Check if a virtual node matches some attribute(s) @@ -21,12 +23,8 @@ import fromFunction from './from-function'; * @returns {Boolean} */ function attributes(vNode, matcher) { - // TODO: this is a ridiculous hack since webpack is making these two - // separate functions - // TODO: es-module-AbstractVirtualNode - if (!axe._isAbstractNode(vNode)) { - // TODO: es-module-utils.getNodeFromTree - vNode = axe.utils.getNodeFromTree(vNode); + if (!(vNode instanceof AbstractVirtualNode)) { + vNode = getNodeFromTree(vNode); } return fromFunction(attrName => vNode.attr(attrName), matcher); } diff --git a/lib/commons/matches/explicit-role.js b/lib/commons/matches/explicit-role.js new file mode 100644 index 0000000000..48d32aad7a --- /dev/null +++ b/lib/commons/matches/explicit-role.js @@ -0,0 +1,24 @@ +import fromPrimative from './from-primative'; +import getRole from '../aria/get-role'; + +/** + * Check if a virtual node matches an explicit role(s) + *`` + * Note: matches.explicitRole(vNode, matcher) can be indirectly used through + * matches(vNode, { explicitRole: matcher }) + * + * Example: + * ```js + * matches.explicitRole(vNode, ['combobox', 'textbox']); + * matches.explicitRole(vNode, 'combobox'); + * ``` + * + * @param {VirtualNode} vNode + * @param {Object} matcher + * @returns {Boolean} + */ +function explicitRole(vNode, matcher) { + return fromPrimative(getRole(vNode, { noImplicit: true }), matcher); +} + +export default explicitRole; diff --git a/lib/commons/matches/from-definition.js b/lib/commons/matches/from-definition.js index 3c6b41a686..11c6ded690 100644 --- a/lib/commons/matches/from-definition.js +++ b/lib/commons/matches/from-definition.js @@ -1,13 +1,21 @@ import attributes from './attributes'; import condition from './condition'; +import explicitRole from './explicit-role'; +import implicitRole from './implicit-role'; import nodeName from './node-name'; import properties from './properties'; +import semanticRole from './semantic-role'; +import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node'; +import { getNodeFromTree } from '../../core/utils'; const matchers = { attributes, condition, + explicitRole, + implicitRole, nodeName, - properties + properties, + semanticRole }; /** @@ -34,12 +42,8 @@ const matchers = { * @returns {Boolean} */ function fromDefinition(vNode, definition) { - // TODO: this is a ridiculous hack since webpack is making these two - // separate functions - // TODO: es-module-AbstractVirtualNode - if (!axe._isAbstractNode(vNode)) { - // TODO: es-module-utils.getNodeFromTree - vNode = axe.utils.getNodeFromTree(vNode); + if (!(vNode instanceof AbstractVirtualNode)) { + vNode = getNodeFromTree(vNode); } if (Array.isArray(definition)) { diff --git a/lib/commons/matches/implicit-role.js b/lib/commons/matches/implicit-role.js new file mode 100644 index 0000000000..2ff949ceae --- /dev/null +++ b/lib/commons/matches/implicit-role.js @@ -0,0 +1,24 @@ +import fromPrimative from './from-primative'; +import getImplicitRole from '../aria/implicit-role'; + +/** + * Check if a virtual node matches an implicit role(s) + *`` + * Note: matches.implicitRole(vNode, matcher) can be indirectly used through + * matches(vNode, { implicitRole: matcher }) + * + * Example: + * ```js + * matches.implicitRole(vNode, ['combobox', 'textbox']); + * matches.implicitRole(vNode, 'combobox'); + * ``` + * + * @param {VirtualNode} vNode + * @param {Object} matcher + * @returns {Boolean} + */ +function implicitRole(vNode, matcher) { + return fromPrimative(getImplicitRole(vNode.actualNode), matcher); +} + +export default implicitRole; diff --git a/lib/commons/matches/index.js b/lib/commons/matches/index.js index ad0d39a9b3..f0434676fc 100644 --- a/lib/commons/matches/index.js +++ b/lib/commons/matches/index.js @@ -5,19 +5,25 @@ */ import attributes from './attributes'; import condition from './condition'; +import explicitRole from './explicit-role'; import fromDefinition from './from-definition'; import fromFunction from './from-function'; import fromPrimative from './from-primative'; +import implicitRole from './implicit-role'; import matches from './matches'; import nodeName from './node-name'; import properties from './properties'; +import semanticRole from './semantic-role'; matches.attributes = attributes; matches.condition = condition; +matches.explicitRole = explicitRole; matches.fromDefinition = fromDefinition; matches.fromFunction = fromFunction; matches.fromPrimative = fromPrimative; +matches.implicitRole = implicitRole; matches.nodeName = nodeName; matches.properties = properties; +matches.semanticRole = semanticRole; export default matches; diff --git a/lib/commons/matches/node-name.js b/lib/commons/matches/node-name.js index ba76eb248c..f4ac42c721 100644 --- a/lib/commons/matches/node-name.js +++ b/lib/commons/matches/node-name.js @@ -1,4 +1,6 @@ import fromPrimative from './from-primative'; +import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node'; +import { getNodeFromTree } from '../../core/utils'; /** * Check if the nodeName of a virtual node matches some value. @@ -18,12 +20,8 @@ import fromPrimative from './from-primative'; * @returns {Boolean} */ function nodeName(vNode, matcher) { - // TODO: this is a ridiculous hack since webpack is making these two - // separate functions - // TODO: es-module-AbstractVirtualNode - if (!axe._isAbstractNode(vNode)) { - // TODO: es-module-utils.getNodeFromTree - vNode = axe.utils.getNodeFromTree(vNode); + if (!(vNode instanceof AbstractVirtualNode)) { + vNode = getNodeFromTree(vNode); } return fromPrimative(vNode.props.nodeName, matcher); } diff --git a/lib/commons/matches/properties.js b/lib/commons/matches/properties.js index 7d394f3303..2220a16f38 100644 --- a/lib/commons/matches/properties.js +++ b/lib/commons/matches/properties.js @@ -1,4 +1,6 @@ import fromFunction from './from-function'; +import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node'; +import { getNodeFromTree } from '../../core/utils'; /** * Check if a virtual node matches some attribute(s) @@ -21,12 +23,8 @@ import fromFunction from './from-function'; * @returns {Boolean} */ function properties(vNode, matcher) { - // TODO: this is a ridiculous hack since webpack is making these two - // separate functions - // TODO: es-module-AbstractVirtualNode - if (!axe._isAbstractNode(vNode)) { - // TODO: es-module-utils.getNodeFromTree - vNode = axe.utils.getNodeFromTree(vNode); + if (!(vNode instanceof AbstractVirtualNode)) { + vNode = getNodeFromTree(vNode); } return fromFunction(propName => vNode.props[propName], matcher); } diff --git a/lib/commons/matches/semantic-role.js b/lib/commons/matches/semantic-role.js new file mode 100644 index 0000000000..2ffe6c8f0b --- /dev/null +++ b/lib/commons/matches/semantic-role.js @@ -0,0 +1,24 @@ +import fromPrimative from './from-primative'; +import getRole from '../aria/get-role'; + +/** + * Check if a virtual node matches an semantic role(s) + *`` + * Note: matches.semanticRole(vNode, matcher) can be indirectly used through + * matches(vNode, { semanticRole: matcher }) + * + * Example: + * ```js + * matches.semanticRole(vNode, ['combobox', 'textbox']); + * matches.semanticRole(vNode, 'combobox'); + * ``` + * + * @param {VirtualNode} vNode + * @param {Object} matcher + * @returns {Boolean} + */ +function semanticRole(vNode, matcher) { + return fromPrimative(getRole(vNode), matcher); +} + +export default semanticRole; diff --git a/test/commons/matches/explicit-role.js b/test/commons/matches/explicit-role.js new file mode 100644 index 0000000000..09446b54e4 --- /dev/null +++ b/test/commons/matches/explicit-role.js @@ -0,0 +1,41 @@ +describe('matches.explicitRole', function() { + var explicitRole = axe.commons.matches.explicitRole; + var fixture = document.querySelector('#fixture'); + var queryFixture = axe.testUtils.queryFixture; + + beforeEach(function() { + fixture.innerHTML = ''; + }); + + it('should return true if explicit role matches', function() { + var virtualNode = queryFixture(''); + assert.isTrue(explicitRole(virtualNode, 'textbox')); + }); + + it('should return true if explicit role matches array', function() { + var virtualNode = queryFixture(''); + assert.isTrue(explicitRole(virtualNode, ['combobox', 'textbox'])); + }); + + it('should return false if explicit role does not match', function() { + var virtualNode = queryFixture(''); + assert.isFalse(explicitRole(virtualNode, 'textbox')); + }); + + it('should return false if matching implicit role', function() { + var virtualNode = queryFixture('