diff --git a/lib/utils/get-element-type.js b/lib/utils/get-element-type.js
index 2d2a531b..29bff36b 100644
--- a/lib/utils/get-element-type.js
+++ b/lib/utils/get-element-type.js
@@ -1,4 +1,4 @@
-const {elementType, getProp, getPropValue} = require('jsx-ast-utils')
+const {elementType, getProp, getLiteralPropValue} = require('jsx-ast-utils')
/*
Allows custom component to be mapped to an element type.
@@ -12,7 +12,7 @@ function getElementType(context, node, ignoreMap = false) {
// check if the node contains a polymorphic prop
const polymorphicPropName = settings?.github?.polymorphicPropName ?? 'as'
- const rawElement = getPropValue(getProp(node.attributes, polymorphicPropName)) ?? elementType(node)
+ const rawElement = getLiteralPropValue(getProp(node.attributes, polymorphicPropName)) ?? elementType(node)
// if a component configuration does not exists, return the raw element
if (ignoreMap || !settings?.github?.components?.[rawElement]) return rawElement
diff --git a/lib/utils/get-role.js b/lib/utils/get-role.js
index b69431d7..df98b39e 100644
--- a/lib/utils/get-role.js
+++ b/lib/utils/get-role.js
@@ -1,4 +1,4 @@
-const {getProp, getPropValue} = require('jsx-ast-utils')
+const {getProp, getLiteralPropValue} = require('jsx-ast-utils')
const {elementRoles} = require('aria-query')
const {getElementType} = require('./get-element-type')
const ObjectMap = require('./object-map')
@@ -43,7 +43,7 @@ function cleanElementRolesMap() {
*/
function getRole(context, node) {
// Early return if role is explicitly set
- const explicitRole = getPropValue(getProp(node.attributes, 'role'))
+ const explicitRole = getLiteralPropValue(getProp(node.attributes, 'role'))
if (explicitRole) {
return explicitRole
}
@@ -80,7 +80,7 @@ function getRole(context, node) {
continue
}
- const value = getPropValue(propOnNode)
+ const value = getLiteralPropValue(propOnNode)
if (value || (value === '' && prop === 'alt')) {
if (
prop === 'href' ||
diff --git a/tests/a11y-role-supports-aria-props.js b/tests/a11y-role-supports-aria-props.js
index b1b41fe5..c4bbbc5e 100644
--- a/tests/a11y-role-supports-aria-props.js
+++ b/tests/a11y-role-supports-aria-props.js
@@ -36,6 +36,9 @@ ruleTester.run('a11y-role-supports-aria-props', rule, {
{code: '
'},
{code: ''},
{code: ''},
+ // Don't try to evaluate expression
+ {code: ''},
+ {code: ''},
// IMPLICIT ROLE TESTS
// A TESTS - implicit role is `link`
@@ -479,12 +482,17 @@ ruleTester.run('a11y-role-supports-aria-props', rule, {
errors: [getErrorMessage('aria-labelledby', 'generic')],
},
{
- code: '',
- errors: [getErrorMessage('aria-label', 'generic')],
+ code: '',
+ errors: [getErrorMessage('aria-labelledby', 'generic')],
},
+ // Determines role from literal `as` prop.
{
- code: '',
+ code: '',
errors: [getErrorMessage('aria-labelledby', 'generic')],
},
+ {
+ code: '',
+ errors: [getErrorMessage('aria-label', 'generic')],
+ },
],
})
diff --git a/tests/utils/get-element-type.js b/tests/utils/get-element-type.js
index 004bef70..e49bb771 100644
--- a/tests/utils/get-element-type.js
+++ b/tests/utils/get-element-type.js
@@ -1,5 +1,5 @@
const {getElementType} = require('../../lib/utils/get-element-type')
-const {mockJSXAttribute, mockJSXOpeningElement} = require('./mocks')
+const {mockJSXAttribute, mockJSXConditionalAttribute, mockJSXOpeningElement} = require('./mocks')
const mocha = require('mocha')
const describe = mocha.describe
@@ -55,4 +55,12 @@ describe('getElementType', function () {
const node = mockJSXOpeningElement('Link', [mockJSXAttribute('as', 'Button')])
expect(getElementType(setting, node)).to.equal('button')
})
+
+ it('returns raw type when polymorphic prop is set to non-literal expression', function () {
+ //
+ const node = mockJSXOpeningElement('Box', [
+ mockJSXConditionalAttribute('as', 'isNavigationOpen', 'generic', 'navigation'),
+ ])
+ expect(getElementType({}, node)).to.equal('Box')
+ })
})
diff --git a/tests/utils/get-role.js b/tests/utils/get-role.js
index 6ee41ec4..9dff372a 100644
--- a/tests/utils/get-role.js
+++ b/tests/utils/get-role.js
@@ -1,11 +1,31 @@
const {getRole} = require('../../lib/utils/get-role')
-const {mockJSXAttribute, mockJSXOpeningElement} = require('./mocks')
+const {mockJSXAttribute, mockJSXConditionalAttribute, mockJSXOpeningElement} = require('./mocks')
const mocha = require('mocha')
const describe = mocha.describe
const it = mocha.it
const expect = require('chai').expect
describe('getRole', function () {
+ it('returns undefined when polymorphic prop is set with a non-literal expression', function () {
+ //
+ const node = mockJSXOpeningElement('Box', [mockJSXConditionalAttribute('as', 'isNavigationOpen', 'div', 'nav')])
+ expect(getRole({}, node)).to.equal(undefined)
+ })
+
+ it('returns undefined when role is set to non-literal expression', function () {
+ //
+ const node = mockJSXOpeningElement('Box', [
+ mockJSXConditionalAttribute('role', 'isNavigationOpen', 'generic', 'navigation'),
+ ])
+ expect(getRole({}, node)).to.equal(undefined)
+ })
+
+ it('returns `role` when set to a literal expression', function () {
+ //
+ const node = mockJSXOpeningElement('Box', [mockJSXAttribute('role', 'generic')])
+ expect(getRole({}, node)).to.equal('generic')
+ })
+
it('returns generic role for regardless of attribute', function () {
const node = mockJSXOpeningElement('span', [mockJSXAttribute('aria-label', 'something')])
expect(getRole({}, node)).to.equal('generic')
diff --git a/tests/utils/mocks.js b/tests/utils/mocks.js
index 4d0181b9..4c923890 100644
--- a/tests/utils/mocks.js
+++ b/tests/utils/mocks.js
@@ -12,6 +12,38 @@ function mockJSXAttribute(prop, propValue) {
}
}
+/* Mocks conditional expression
+ e.g. can be by calling
+ mockJSXConditionalAttribute('as', 'isNavigationOpen', 'generic', 'navigation')
+*/
+function mockJSXConditionalAttribute(prop, expression, consequentValue, alternateValue) {
+ return {
+ type: 'JSXAttribute',
+ name: {
+ type: 'JSXIdentifier',
+ name: prop,
+ },
+ value: {
+ type: 'JSXExpressionContainer',
+ value: prop,
+ expression: {
+ type: 'ConditionalExpression',
+ test: {
+ type: expression,
+ },
+ consequent: {
+ type: 'Literal',
+ value: consequentValue,
+ },
+ alternate: {
+ type: 'Literal',
+ value: alternateValue,
+ },
+ },
+ },
+ }
+}
+
function mockJSXOpeningElement(tagName, attributes = []) {
return {
type: 'JSXOpeningElement',
@@ -23,4 +55,4 @@ function mockJSXOpeningElement(tagName, attributes = []) {
}
}
-module.exports = {mockJSXAttribute, mockJSXOpeningElement}
+module.exports = {mockJSXAttribute, mockJSXOpeningElement, mockJSXConditionalAttribute}