Bump packages to fix linter

This commit is contained in:
Henry Mercer 2023-01-18 20:50:03 +00:00
parent ed9506bbaf
commit 0a11e3fdd9
6063 changed files with 378752 additions and 306784 deletions

View file

@ -0,0 +1,115 @@
import expect from 'expect';
import attributesComparator from '../../../src/util/attributesComparator';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
describe('attributesComparator', () => {
describe('base attributes', () => {
let baseAttributes;
let attributes;
describe('are undefined', () => {
describe('and attributes are undefined', () => {
it('should return true', () => {
expect(attributesComparator()).toBe(true);
});
});
});
describe('are empty', () => {
beforeEach(() => {
baseAttributes = [];
});
describe('and attributes', () => {
describe('are empty', () => {
attributes = [];
it('should return true', () => {
expect(attributesComparator(baseAttributes, attributes))
.toBe(true);
});
});
describe('have values', () => {
attributes = [
JSXAttributeMock('foo', 0),
JSXAttributeMock('bar', 'baz'),
];
it('should return true', () => {
expect(attributesComparator(baseAttributes, attributes))
.toBe(true);
});
});
});
});
describe('have values', () => {
beforeEach(() => {
baseAttributes = [
{
name: 'biz',
value: 1,
}, {
name: 'fizz',
value: 'pop',
}, {
name: 'fuzz',
value: 'lolz',
},
];
});
describe('and attributes', () => {
describe('are empty', () => {
attributes = [];
it('should return false', () => {
expect(attributesComparator(baseAttributes, attributes))
.toBe(false);
});
});
describe('have values', () => {
describe('and the values are the different', () => {
it('should return false', () => {
attributes = [
JSXElementMock(),
JSXAttributeMock('biz', 2),
JSXAttributeMock('ziff', 'opo'),
JSXAttributeMock('far', 'lolz'),
];
expect(attributesComparator(baseAttributes, attributes))
.toBe(false);
});
});
describe('and the values are a subset', () => {
it('should return true', () => {
attributes = [
JSXAttributeMock('biz', 1),
JSXAttributeMock('fizz', 'pop'),
JSXAttributeMock('goo', 'gazz'),
];
expect(attributesComparator(baseAttributes, attributes))
.toBe(false);
});
});
describe('and the values are the same', () => {
it('should return true', () => {
attributes = [
JSXAttributeMock('biz', 1),
JSXAttributeMock('fizz', 'pop'),
JSXAttributeMock('fuzz', 'lolz'),
];
expect(attributesComparator(baseAttributes, attributes))
.toBe(true);
});
});
describe('and the values are a superset', () => {
it('should return true', () => {
attributes = [
JSXAttributeMock('biz', 1),
JSXAttributeMock('fizz', 'pop'),
JSXAttributeMock('fuzz', 'lolz'),
JSXAttributeMock('dar', 'tee'),
];
expect(attributesComparator(baseAttributes, attributes))
.toBe(true);
});
});
});
});
});
});
});

View file

@ -0,0 +1,141 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import getAccessibleChildText from '../../../src/util/getAccessibleChildText';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
describe('getAccessibleChildText', () => {
it('returns the aria-label when present', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[JSXAttributeMock('aria-label', 'foo')],
), elementType)).toBe('foo');
});
it('returns the aria-label instead of children', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[JSXAttributeMock('aria-label', 'foo')],
[{ type: 'JSXText', value: 'bar' }],
), elementType)).toBe('foo');
});
it('skips elements with aria-hidden=true', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[JSXAttributeMock('aria-hidden', 'true')],
), elementType)).toBe('');
});
it('returns literal value for JSXText child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'JSXText', value: 'bar' }],
), elementType)).toBe('bar');
});
it('returns alt text for img child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
JSXAttributeMock('alt', 'a sensible label'),
])],
), elementType)).toBe('a sensible label');
});
it('returns blank when alt tag is used on arbitrary element', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[JSXElementMock('span', [
JSXAttributeMock('alt', 'a sensible label'),
])],
), elementType)).toBe('');
});
it('returns literal value for JSXText child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: 'bar' }],
), elementType)).toBe('bar');
});
it('returns trimmed literal value for JSXText child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: ' bar ' }],
), elementType)).toBe('bar');
});
it('returns space-collapsed literal value for JSXText child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: 'foo bar' }],
), elementType)).toBe('foo bar');
});
it('returns punctuation-stripped literal value for JSXText child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: 'foo, bar. baz? foo; bar:' }],
), elementType)).toBe('foo bar baz foo bar');
});
it('returns recursive value for JSXElement child', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[JSXElementMock(
'span',
[],
[{ type: 'Literal', value: 'bar' }],
)],
), elementType)).toBe('bar');
});
it('skips children with aria-hidden-true', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[JSXElementMock(
'span',
[],
[JSXElementMock(
'span',
[JSXAttributeMock('aria-hidden', 'true')],
)],
)],
), elementType)).toBe('');
});
it('joins multiple children properly - no spacing', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: 'foo' }, { type: 'Literal', value: 'bar' }],
), elementType)).toBe('foo bar');
});
it('joins multiple children properly - with spacing', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: ' foo ' }, { type: 'Literal', value: ' bar ' }],
), elementType)).toBe('foo bar');
});
it('skips unknown elements', () => {
expect(getAccessibleChildText(JSXElementMock(
'a',
[],
[{ type: 'Literal', value: 'foo' }, { type: 'Unknown' }, { type: 'Literal', value: 'bar' }],
), elementType)).toBe('foo bar');
});
});

View file

@ -0,0 +1,71 @@
import expect from 'expect';
import getComputedRole from '../../../src/util/getComputedRole';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
describe('getComputedRole', () => {
describe('explicit role', () => {
describe('valid role', () => {
it('should return the role', () => {
expect(getComputedRole(
'div',
[JSXAttributeMock('role', 'button')],
)).toBe('button');
});
});
describe('invalid role', () => {
describe('has implicit', () => {
it('should return the implicit role', () => {
expect(getComputedRole(
'li',
[JSXAttributeMock('role', 'beeswax')],
)).toBe('listitem');
});
});
describe('lacks implicit', () => {
it('should return null', () => {
expect(getComputedRole(
'div',
[JSXAttributeMock('role', 'beeswax')],
)).toBeNull();
});
});
});
describe('no role', () => {
describe('has implicit', () => {
it('should return the implicit role', () => {
expect(getComputedRole(
'li',
[],
)).toBe('listitem');
});
});
describe('lacks implicit', () => {
it('should return null', () => {
expect(getComputedRole(
'div',
[],
)).toBeNull();
});
});
});
});
describe('implicit role', () => {
describe('has implicit', () => {
it('should return the implicit role', () => {
expect(getComputedRole(
'li',
[JSXAttributeMock('role', 'beeswax')],
)).toBe('listitem');
});
});
describe('lacks implicit', () => {
it('should return null', () => {
expect(getComputedRole(
'div',
[],
)).toBeNull();
});
});
});
});

View file

@ -0,0 +1,45 @@
import expect from 'expect';
import getElementType from '../../../src/util/getElementType';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
describe('getElementType', () => {
describe('no settings in context', () => {
const elementType = getElementType({ settings: {} });
it('should return the exact tag name for a DOM element', () => {
expect(elementType(JSXElementMock('input').openingElement)).toBe('input');
});
it('should return the exact tag name for a custom element', () => {
expect(elementType(JSXElementMock('CustomInput').openingElement)).toBe('CustomInput');
});
it('should return the exact tag name for names that are in Object.prototype', () => {
expect(elementType(JSXElementMock('toString').openingElement)).toBe('toString');
});
});
describe('components settings in context', () => {
const elementType = getElementType({
settings: {
'jsx-a11y': {
components: {
CustomInput: 'input',
},
},
},
});
it('should return the exact tag name for a DOM element', () => {
expect(elementType(JSXElementMock('input').openingElement)).toBe('input');
});
it('should return the mapped tag name for a custom element', () => {
expect(elementType(JSXElementMock('CustomInput').openingElement)).toBe('input');
});
it('should return the exact tag name for a custom element not in the components map', () => {
expect(elementType(JSXElementMock('CityInput').openingElement)).toBe('CityInput');
});
});
});

View file

@ -0,0 +1,30 @@
import expect from 'expect';
import getExplicitRole from '../../../src/util/getExplicitRole';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
describe('getExplicitRole', () => {
describe('valid role', () => {
it('should return the role', () => {
expect(getExplicitRole(
'div',
[JSXAttributeMock('role', 'button')],
)).toBe('button');
});
});
describe('invalid role', () => {
it('should return null', () => {
expect(getExplicitRole(
'div',
[JSXAttributeMock('role', 'beeswax')],
)).toBeNull();
});
});
describe('no role', () => {
it('should return null', () => {
expect(getExplicitRole(
'div',
[],
)).toBeNull();
});
});
});

View file

@ -0,0 +1,21 @@
import expect from 'expect';
import getImplicitRole from '../../../src/util/getImplicitRole';
describe('getImplicitRole', () => {
describe('has implicit', () => {
it('should return the implicit role', () => {
expect(getImplicitRole(
'li',
[],
)).toBe('listitem');
});
});
describe('lacks implicit', () => {
it('should return null', () => {
expect(getImplicitRole(
'div',
[],
)).toBeNull();
});
});
});

View file

@ -0,0 +1,48 @@
import expect from 'expect';
import getSuggestion from '../../../src/util/getSuggestion';
describe('spell check suggestion API', () => {
it('should return no suggestions given empty word and no dictionary', () => {
const word = '';
const expected = [];
const actual = getSuggestion(word);
expect(expected).toEqual(actual);
});
it('should return no suggestions given real word and no dictionary', () => {
const word = 'foo';
const expected = [];
const actual = getSuggestion(word);
expect(expected).toEqual(actual);
});
it('should return correct suggestion given real word and a dictionary', () => {
const word = 'fo';
const dictionary = ['foo', 'bar', 'baz'];
const expected = ['foo'];
const actual = getSuggestion(word, dictionary);
expect(expected).toEqual(actual);
});
it('should return multiple correct suggestions given real word and a dictionary', () => {
const word = 'theer';
const dictionary = ['there', 'their', 'foo', 'bar'];
const expected = ['there', 'their'];
const actual = getSuggestion(word, dictionary);
expect(expected).toEqual(actual);
});
it('should return correct # of suggestions given the limit argument', () => {
const word = 'theer';
const dictionary = ['there', 'their', 'foo', 'bar'];
const limit = 1;
const expected = 1;
const actual = getSuggestion(word, dictionary, limit).length;
expect(expected).toEqual(actual);
});
});

View file

@ -0,0 +1,83 @@
import expect from 'expect';
import getTabIndex from '../../../src/util/getTabIndex';
import IdentifierMock from '../../../__mocks__/IdentifierMock';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
describe('getTabIndex', () => {
describe('tabIndex is defined', () => {
describe('as a number ', () => {
describe('zero', () => {
it('should return zero', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', 0))).toBe(0);
});
});
describe('positive integer', () => {
it('should return the integer', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', 1))).toBe(1);
});
});
describe('negative integer', () => {
it('should return the integer', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', -1))).toBe(-1);
});
});
describe('float', () => {
it('should return undefined', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', 9.1))).toBeUndefined();
});
});
});
describe('as a string', () => {
describe('empty', () => {
it('should return undefined', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', ''))).toBeUndefined();
});
});
describe('which converts to a number', () => {
it('should return an integer', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', '0'))).toBe(0);
});
});
describe('which is NaN', () => {
it('should return undefined', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', '0a'))).toBeUndefined();
});
});
});
describe('as a boolean', () => {
describe('true', () => {
it('should return undefined', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', true))).toBeUndefined();
});
});
describe('false', () => {
it('should return undefined', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', false))).toBeUndefined();
});
});
});
describe('as an expression', () => {
describe('function expression', () => {
it('should return the correct type', () => {
const attr = function mockFn() { return 0; };
expect(typeof getTabIndex(JSXAttributeMock('tabIndex', attr))).toEqual('function');
});
});
describe('variable expression', () => {
it('should return the Identifier name', () => {
const name = 'identName';
expect(getTabIndex(JSXAttributeMock(
'tabIndex',
IdentifierMock(name),
true,
))).toEqual(name);
});
});
});
});
describe('tabIndex is not defined', () => {
it('should return undefined', () => {
expect(getTabIndex(JSXAttributeMock('tabIndex', undefined))).toBeUndefined();
});
});
});

View file

@ -0,0 +1,107 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import hasAccessibleChild from '../../../src/util/hasAccessibleChild';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
describe('hasAccessibleChild', () => {
describe('has no children and does not set dangerouslySetInnerHTML', () => {
it('returns false', () => {
expect(hasAccessibleChild(JSXElementMock('div', []), elementType)).toBe(false);
});
});
describe('has no children and sets dangerouslySetInnerHTML', () => {
it('Returns true', () => {
const prop = JSXAttributeMock('dangerouslySetInnerHTML', true);
const element = JSXElementMock('div', [prop], []);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
});
describe('has children', () => {
it('Returns true for a Literal child', () => {
const child = {
type: 'Literal',
value: 'foo',
};
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
it('Returns true for visible child JSXElement', () => {
const child = JSXElementMock('div', []);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
it('Returns true for JSXText Element', () => {
const child = {
type: 'JSXText',
value: 'foo',
};
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
it('Returns false for hidden child JSXElement', () => {
const ariaHiddenAttr = JSXAttributeMock('aria-hidden', true);
const child = JSXElementMock('div', [ariaHiddenAttr]);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(false);
});
it('Returns true for defined JSXExpressionContainer', () => {
const expression = {
type: 'Identifier',
name: 'foo',
};
const child = JSXExpressionContainerMock(expression);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
it('Returns false for undefined JSXExpressionContainer', () => {
const expression = {
type: 'Identifier',
name: 'undefined',
};
const child = JSXExpressionContainerMock(expression);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(false);
});
it('Returns false for unknown child type', () => {
const child = {
type: 'Unknown',
};
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(false);
});
it('Returns true with children passed as a prop', () => {
const children = JSXAttributeMock('children', true);
const element = JSXElementMock('div', [children], []);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
it('Returns false for hidden child input JSXElement', () => {
const child = JSXElementMock('input', [JSXAttributeMock('type', 'hidden')]);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(false);
});
it('Returns true for a custom JSXElement even if type hidden', () => {
const child = JSXElementMock('CustomInput', [JSXAttributeMock('type', 'hidden')]);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, elementType)).toBe(true);
});
it('Returns false for a custom JSXElement mapped to input if type is hidden', () => {
const child = JSXElementMock('CustomInput', [JSXAttributeMock('type', 'hidden')]);
const element = JSXElementMock('div', [], [child]);
expect(hasAccessibleChild(element, () => 'input')).toBe(false);
});
});
});

View file

@ -0,0 +1,34 @@
import expect from 'expect';
import JSXAttributeMock from '../../../../__mocks__/JSXAttributeMock';
import getImplicitRoleForInput from '../../../../src/util/implicitRoles/input';
describe('isAbstractRole', () => {
it('works for buttons', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'button')])).toBe('button');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'image')])).toBe('button');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'reset')])).toBe('button');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'submit')])).toBe('button');
});
it('works for checkboxes', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'checkbox')])).toBe('checkbox');
});
it('works for radios', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'radio')])).toBe('radio');
});
it('works for ranges', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'range')])).toBe('slider');
});
it('works for textboxes', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'email')])).toBe('textbox');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'password')])).toBe('textbox');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'search')])).toBe('textbox');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'tel')])).toBe('textbox');
expect(getImplicitRoleForInput([JSXAttributeMock('type', 'url')])).toBe('textbox');
});
it('works for the default case', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', '')])).toBe('textbox');
});
it('works for the true case', () => {
expect(getImplicitRoleForInput([JSXAttributeMock('type', true)])).toBe('textbox');
});
});

View file

@ -0,0 +1,12 @@
import expect from 'expect';
import JSXAttributeMock from '../../../../__mocks__/JSXAttributeMock';
import getImplicitRoleForMenu from '../../../../src/util/implicitRoles/menu';
describe('isAbstractRole', () => {
it('works for toolbars', () => {
expect(getImplicitRoleForMenu([JSXAttributeMock('type', 'toolbar')])).toBe('toolbar');
});
it('works for non-toolbars', () => {
expect(getImplicitRoleForMenu([JSXAttributeMock('type', '')])).toBe('');
});
});

View file

@ -0,0 +1,21 @@
import expect from 'expect';
import JSXAttributeMock from '../../../../__mocks__/JSXAttributeMock';
import getImplicitRoleForMenuitem from '../../../../src/util/implicitRoles/menuitem';
describe('isAbstractRole', () => {
it('works for menu items', () => {
expect(getImplicitRoleForMenuitem([JSXAttributeMock('type', 'command')])).toBe('menuitem');
});
it('works for menu item checkboxes', () => {
expect(getImplicitRoleForMenuitem([JSXAttributeMock('type', 'checkbox')])).toBe('menuitemcheckbox');
});
it('works for menu item radios', () => {
expect(getImplicitRoleForMenuitem([JSXAttributeMock('type', 'radio')])).toBe('menuitemradio');
});
it('works for non-toolbars', () => {
expect(getImplicitRoleForMenuitem([JSXAttributeMock('type', '')])).toBe('');
});
it('works for the true case', () => {
expect(getImplicitRoleForMenuitem([JSXAttributeMock('type', true)])).toBe('');
});
});

View file

@ -0,0 +1,39 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import isAbstractRole from '../../../src/util/isAbstractRole';
import {
genElementSymbol,
genAbstractRoleElements,
genNonAbstractRoleElements,
} from '../../../__mocks__/genInteractives';
describe('isAbstractRole', () => {
describe('JSX Components (no tagName)', () => {
it('should NOT identify them as abstract role elements', () => {
expect(isAbstractRole(undefined, []))
.toBe(false);
});
});
describe('elements with an abstract role', () => {
genAbstractRoleElements().forEach(({ openingElement }) => {
const { attributes } = openingElement;
it(`should identify \`${genElementSymbol(openingElement)}\` as an abstract role element`, () => {
expect(isAbstractRole(
elementType(openingElement),
attributes,
)).toBe(true);
});
});
});
describe('elements with a non-abstract role', () => {
genNonAbstractRoleElements().forEach(({ openingElement }) => {
const { attributes } = openingElement;
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an abstract role element`, () => {
expect(isAbstractRole(
elementType(openingElement),
attributes,
)).toBe(false);
});
});
});
});

View file

@ -0,0 +1,51 @@
import expect from 'expect';
import isContentEditable from '../../../src/util/isContentEditable';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
describe('isContentEditable', () => {
describe('HTML5', () => {
describe('content editable', () => {
it('should identify HTML5 contentEditable elements', () => {
const attributes = [
JSXAttributeMock('contentEditable', 'true'),
];
expect(isContentEditable('some tag', attributes))
.toBe(true);
});
});
describe('not content editable', () => {
it('should not identify HTML5 content editable elements with null as the value', () => {
const attributes = [
JSXAttributeMock('contentEditable', null),
];
expect(isContentEditable('some tag', attributes))
.toBe(false);
});
it('should not identify HTML5 content editable elements with undefined as the value', () => {
const attributes = [
JSXAttributeMock('contentEditable', undefined),
];
expect(isContentEditable('some tag', attributes))
.toBe(false);
});
it('should not identify HTML5 content editable elements with true as the value', () => {
const attributes = [
JSXAttributeMock('contentEditable', true),
];
expect(isContentEditable('some tag', attributes))
.toBe(false);
});
it('should not identify HTML5 content editable elements with "false" as the value', () => {
const attributes = [
JSXAttributeMock('contentEditable', 'false'),
];
expect(isContentEditable('some tag', attributes))
.toBe(false);
});
});
});
});

View file

@ -0,0 +1,26 @@
import expect from 'expect';
import { dom } from 'aria-query';
import { elementType } from 'jsx-ast-utils';
import isDOMElement from '../../../src/util/isDOMElement';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
const domElements = [...dom.keys()];
describe('isDOMElement', () => {
describe('DOM elements', () => {
domElements.forEach((el) => {
it(`should identify ${el} as a DOM element`, () => {
const element = JSXElementMock(el);
expect(isDOMElement(elementType(element.openingElement)))
.toBe(true);
});
});
});
describe('Custom Element', () => {
it('should not identify a custom element', () => {
const element = JSXElementMock('CustomElement');
expect(isDOMElement(element))
.toBe(false);
});
});
});

View file

@ -0,0 +1,81 @@
import expect from 'expect';
import isDisabledElement from '../../../src/util/isDisabledElement';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
describe('isDisabledElement', () => {
describe('HTML5', () => {
describe('disabled', () => {
it('should identify HTML5 disabled elements', () => {
const attributes = [
JSXAttributeMock('disabled', 'disabled'),
];
expect(isDisabledElement(attributes))
.toBe(true);
});
});
describe('not disabled', () => {
it('should identify HTML5 disabled elements with null as the value', () => {
const attributes = [
JSXAttributeMock('disabled', null),
];
expect(isDisabledElement(attributes))
.toBe(true);
});
it('should not identify HTML5 disabled elements with undefined as the value', () => {
const attributes = [
JSXAttributeMock('disabled', undefined),
];
expect(isDisabledElement(attributes))
.toBe(false);
});
});
});
describe('ARIA', () => {
describe('disabled', () => {
it('should not identify ARIA disabled elements', () => {
const attributes = [
JSXAttributeMock('aria-disabled', 'true'),
];
expect(isDisabledElement(attributes))
.toBe(true);
});
it('should not identify ARIA disabled elements', () => {
const attributes = [
JSXAttributeMock('aria-disabled', true),
];
expect(isDisabledElement(attributes))
.toBe(true);
});
});
describe('not disabled', () => {
it('should not identify ARIA disabled elements', () => {
const attributes = [
JSXAttributeMock('aria-disabled', 'false'),
];
expect(isDisabledElement(attributes))
.toBe(false);
});
it('should not identify ARIA disabled elements', () => {
const attributes = [
JSXAttributeMock('aria-disabled', false),
];
expect(isDisabledElement(attributes))
.toBe(false);
});
it('should not identify ARIA disabled elements with null as the value', () => {
const attributes = [
JSXAttributeMock('aria-disabled', null),
];
expect(isDisabledElement(attributes))
.toBe(false);
});
it('should not identify ARIA disabled elements with undefined as the value', () => {
const attributes = [
JSXAttributeMock('aria-disabled', undefined),
];
expect(isDisabledElement(attributes))
.toBe(false);
});
});
});
});

View file

@ -0,0 +1,86 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import isFocusable from '../../../src/util/isFocusable';
import {
genElementSymbol,
genInteractiveElements,
genNonInteractiveElements,
} from '../../../__mocks__/genInteractives';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
function mergeTabIndex(index, attributes) {
return [...attributes, JSXAttributeMock('tabIndex', index)];
}
describe('isFocusable', () => {
describe('interactive elements', () => {
genInteractiveElements().forEach(({ openingElement }) => {
it(`should identify \`${genElementSymbol(openingElement)}\` as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
openingElement.attributes,
)).toBe(true);
});
it(`should not identify \`${genElementSymbol(openingElement)}\` with tabIndex of -1 as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex(-1, openingElement.attributes),
)).toBe(false);
});
it(`should identify \`${genElementSymbol(openingElement)}\` with tabIndex of 0 as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex(0, openingElement.attributes),
)).toBe(true);
});
it(`should identify \`${genElementSymbol(openingElement)}\` with tabIndex of 1 as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex(1, openingElement.attributes),
)).toBe(true);
});
});
});
describe('non-interactive elements', () => {
genNonInteractiveElements().forEach(({ openingElement }) => {
it(`should not identify \`${genElementSymbol(openingElement)}\` as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
it(`should not identify \`${genElementSymbol(openingElement)}\` with tabIndex of -1 as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex(-1, openingElement.attributes),
)).toBe(false);
});
it(`should identify \`${genElementSymbol(openingElement)}\` with tabIndex of 0 as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex(0, openingElement.attributes),
)).toBe(true);
});
it(`should identify \`${genElementSymbol(openingElement)}\` with tabIndex of 1 as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex(1, openingElement.attributes),
)).toBe(true);
});
it(`should not identify \`${genElementSymbol(openingElement)}\` with tabIndex of 'bogus' as a focusable element`, () => {
expect(isFocusable(
elementType(openingElement),
mergeTabIndex('bogus', openingElement.attributes),
)).toBe(false);
});
});
});
});

View file

@ -0,0 +1,76 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import isInteractiveElement from '../../../src/util/isInteractiveElement';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
import {
genElementSymbol,
genIndeterminantInteractiveElements,
genInteractiveElements,
genInteractiveRoleElements,
genNonInteractiveElements,
genNonInteractiveRoleElements,
} from '../../../__mocks__/genInteractives';
describe('isInteractiveElement', () => {
describe('JSX Components (no tagName)', () => {
it('should identify them as interactive elements', () => {
expect(isInteractiveElement(undefined, []))
.toBe(false);
});
});
describe('interactive elements', () => {
genInteractiveElements().forEach(({ openingElement }) => {
it(`should identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => {
expect(isInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(true);
});
});
});
describe('interactive role elements', () => {
genInteractiveRoleElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => {
expect(isInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('non-interactive elements', () => {
genNonInteractiveElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => {
expect(isInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('non-interactive role elements', () => {
genNonInteractiveRoleElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => {
expect(isInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('indeterminate elements', () => {
genIndeterminantInteractiveElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${openingElement.name.name}\` as an interactive element`, () => {
expect(isInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('JSX elements', () => {
it('is not interactive', () => {
expect(isInteractiveElement('CustomComponent', JSXElementMock())).toBe(false);
});
});
});

View file

@ -0,0 +1,44 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import isInteractiveRole from '../../../src/util/isInteractiveRole';
import {
genElementSymbol,
genInteractiveRoleElements,
genNonInteractiveRoleElements,
} from '../../../__mocks__/genInteractives';
describe('isInteractiveRole', () => {
describe('JSX Components (no tagName)', () => {
it('should identify them as interactive role elements', () => {
expect(isInteractiveRole(undefined, []))
.toBe(false);
});
});
describe('elements with a non-interactive role', () => {
genNonInteractiveRoleElements().forEach(({ openingElement }) => {
const { attributes } = openingElement;
it(`should not identify \`${genElementSymbol(openingElement)}\` as an interactive role element`, () => {
expect(isInteractiveRole(
elementType(openingElement),
attributes,
)).toBe(false);
});
});
});
describe('elements without a role', () => {
it('should not identify them as interactive role elements', () => {
expect(isInteractiveRole('div', [])).toBe(false);
});
});
describe('elements with an interactive role', () => {
genInteractiveRoleElements().forEach(({ openingElement }) => {
const { attributes } = openingElement;
it(`should identify \`${genElementSymbol(openingElement)}\` as an interactive role element`, () => {
expect(isInteractiveRole(
elementType(openingElement),
attributes,
)).toBe(true);
});
});
});
});

View file

@ -0,0 +1,70 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import isNonInteractiveElement from '../../../src/util/isNonInteractiveElement';
import {
genElementSymbol,
genIndeterminantInteractiveElements,
genInteractiveElements,
genInteractiveRoleElements,
genNonInteractiveElements,
genNonInteractiveRoleElements,
} from '../../../__mocks__/genInteractives';
describe('isNonInteractiveElement', () => {
describe('JSX Components (no tagName)', () => {
it('should identify them as interactive elements', () => {
expect(isNonInteractiveElement(undefined, []))
.toBe(false);
});
});
describe('non-interactive elements', () => {
genNonInteractiveElements().forEach(({ openingElement }) => {
it(`should identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => {
expect(isNonInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(true);
});
});
});
describe('non-interactive role elements', () => {
genNonInteractiveRoleElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => {
expect(isNonInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('interactive elements', () => {
genInteractiveElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => {
expect(isNonInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('interactive role elements', () => {
genInteractiveRoleElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => {
expect(isNonInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
describe('indeterminate elements', () => {
genIndeterminantInteractiveElements().forEach(({ openingElement }) => {
it(`should NOT identify \`${openingElement.name.name}\` as a non-interactive element`, () => {
expect(isNonInteractiveElement(
elementType(openingElement),
openingElement.attributes,
)).toBe(false);
});
});
});
});

View file

@ -0,0 +1,44 @@
import expect from 'expect';
import { elementType } from 'jsx-ast-utils';
import isNonInteractiveRole from '../../../src/util/isNonInteractiveRole';
import {
genElementSymbol,
genInteractiveRoleElements,
genNonInteractiveRoleElements,
} from '../../../__mocks__/genInteractives';
describe('isNonInteractiveRole', () => {
describe('JSX Components (no tagName)', () => {
it('should identify them as interactive role elements', () => {
expect(isNonInteractiveRole(undefined, []))
.toBe(false);
});
});
describe('elements with a non-interactive role', () => {
genNonInteractiveRoleElements().forEach(({ openingElement }) => {
const { attributes } = openingElement;
it(`should identify \`${genElementSymbol(openingElement)}\` as non-interactive role element`, () => {
expect(isNonInteractiveRole(
elementType(openingElement),
attributes,
)).toBe(true);
});
});
});
describe('elements without a role', () => {
it('should not identify them as non-interactive role elements', () => {
expect(isNonInteractiveRole('div', [])).toBe(false);
});
});
describe('elements with an interactive role', () => {
genInteractiveRoleElements().forEach(({ openingElement }) => {
const { attributes } = openingElement;
it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive role element`, () => {
expect(isNonInteractiveRole(
elementType(openingElement),
attributes,
)).toBe(false);
});
});
});
});

View file

@ -0,0 +1,44 @@
import expect from 'expect';
import isNonLiteralProperty from '../../../src/util/isNonLiteralProperty';
import IdentifierMock from '../../../__mocks__/IdentifierMock';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
import JSXSpreadAttributeMock from '../../../__mocks__/JSXSpreadAttributeMock';
import JSXTextMock from '../../../__mocks__/JSXTextMock';
import LiteralMock from '../../../__mocks__/LiteralMock';
const theProp = 'theProp';
const spread = JSXSpreadAttributeMock('theSpread');
describe('isNonLiteralProperty', () => {
describe('elements without the property', () => {
it('should not identify them as non-literal role elements', () => {
expect(isNonLiteralProperty([], theProp)).toBe(false);
});
});
describe('elements with a literal property', () => {
it('should not identify them as non-literal role elements without spread operator', () => {
expect(isNonLiteralProperty([JSXAttributeMock(theProp, LiteralMock('theRole'))], theProp)).toBe(false);
});
it('should not identify them as non-literal role elements with spread operator', () => {
expect(isNonLiteralProperty([spread, JSXAttributeMock(theProp, LiteralMock('theRole'))], theProp)).toBe(false);
});
});
describe('elements with a JSXText property', () => {
it('should not identify them as non-literal role elements', () => {
expect(isNonLiteralProperty([JSXAttributeMock(theProp, JSXTextMock('theRole'))], theProp)).toBe(false);
});
});
describe('elements with a property of undefined', () => {
it('should not identify them as non-literal role elements', () => {
const undefinedExpression = IdentifierMock('undefined');
expect(isNonLiteralProperty([JSXAttributeMock(theProp, undefinedExpression)], theProp)).toBe(false);
});
});
describe('elements with a expression property', () => {
it('should identify them as non-literal role elements', () => {
const identifierExpression = IdentifierMock('theIdentifier');
expect(isNonLiteralProperty([JSXAttributeMock(theProp, identifierExpression)], theProp)).toBe(true);
});
});
});

View file

@ -0,0 +1,47 @@
import expect from 'expect';
import isSemanticRoleElement from '../../../src/util/isSemanticRoleElement';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
describe('isSemanticRoleElement', () => {
it('should identify semantic role elements', () => {
expect(isSemanticRoleElement('input', [
JSXAttributeMock('type', 'checkbox'),
JSXAttributeMock('role', 'switch'),
])).toBe(true);
});
it('should reject non-semantic role elements', () => {
expect(isSemanticRoleElement('input', [
JSXAttributeMock('type', 'radio'),
JSXAttributeMock('role', 'switch'),
])).toBe(false);
expect(isSemanticRoleElement('input', [
JSXAttributeMock('type', 'text'),
JSXAttributeMock('role', 'combobox'),
])).toBe(false);
expect(isSemanticRoleElement('button', [
JSXAttributeMock('role', 'switch'),
JSXAttributeMock('aria-pressed', 'true'),
])).toBe(false);
expect(isSemanticRoleElement('input', [
JSXAttributeMock('role', 'switch'),
])).toBe(false);
});
it('should not throw on JSXSpreadAttribute', () => {
expect(() => {
isSemanticRoleElement('input', [
JSXAttributeMock('type', 'checkbox'),
JSXAttributeMock('role', 'checkbox'),
JSXAttributeMock('aria-checked', 'false'),
JSXAttributeMock('aria-labelledby', 'foo'),
JSXAttributeMock('tabindex', '0'),
{
type: 'JSXSpreadAttribute',
argument: {
type: 'Identifier',
name: 'props',
},
},
]);
}).not.toThrow();
});
});

View file

@ -0,0 +1,178 @@
import expect from 'expect';
import mayContainChildComponent from '../../../src/util/mayContainChildComponent';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
describe('mayContainChildComponent', () => {
describe('no FancyComponent', () => {
it('should return false', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], []),
]),
]),
]),
JSXElementMock('span', [], []),
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
]),
]),
'FancyComponent',
5,
)).toBe(false);
});
});
describe('contains an indicated component', () => {
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('input'),
]),
'input',
)).toBe(true);
});
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
'FancyComponent',
)).toBe(true);
});
it('FancyComponent is outside of default depth, should return false', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
]),
'FancyComponent',
)).toBe(false);
});
it('FancyComponent is inside of custom depth, should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
]),
'FancyComponent',
2,
)).toBe(true);
});
it('deep nesting, should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], [
JSXElementMock('span', [], [
JSXElementMock('FancyComponent'),
]),
]),
]),
]),
]),
JSXElementMock('span', [], []),
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
]),
]),
'FancyComponent',
6,
)).toBe(true);
});
});
describe('Intederminate situations', () => {
describe('expression container children', () => {
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXExpressionContainerMock('mysteryBox'),
]),
'FancyComponent',
)).toBe(true);
});
});
});
describe('Glob name matching', () => {
describe('component name contains question mark ? - match any single character', () => {
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
'Fanc?Co??onent',
)).toBe(true);
});
it('should return false', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
'FancyComponent?',
)).toBe(false);
});
});
describe('component name contains asterisk * - match zero or more characters', () => {
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
'Fancy*',
)).toBe(true);
});
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
'*Component',
)).toBe(true);
});
it('should return true', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('FancyComponent'),
]),
'Fancy*C*t',
)).toBe(true);
});
});
});
describe('using a custom elementType function', () => {
it('should return true when the custom elementType returns the proper name', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('CustomInput'),
]),
'input',
2,
() => 'input',
)).toBe(true);
});
it('should return false when the custom elementType returns a wrong name', () => {
expect(mayContainChildComponent(
JSXElementMock('div', [], [
JSXElementMock('CustomInput'),
]),
'input',
2,
() => 'button',
)).toBe(false);
});
});
});

View file

@ -0,0 +1,170 @@
import expect from 'expect';
import mayHaveAccessibleLabel from '../../../src/util/mayHaveAccessibleLabel';
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
import JSXElementMock from '../../../__mocks__/JSXElementMock';
import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
import JSXSpreadAttributeMock from '../../../__mocks__/JSXSpreadAttributeMock';
import JSXTextMock from '../../../__mocks__/JSXTextMock';
import LiteralMock from '../../../__mocks__/LiteralMock';
describe('mayHaveAccessibleLabel', () => {
describe('no label', () => {
it('should return false', () => {
expect(mayHaveAccessibleLabel(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], []),
]),
]),
]),
JSXElementMock('span', [], []),
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
]),
]),
5,
)).toBe(false);
});
});
describe('label via attributes', () => {
it('aria-label, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [
JSXAttributeMock('aria-label', 'A delicate label'),
], []))).toBe(true);
});
it('aria-label without content, should return false', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [
JSXAttributeMock('aria-label', ''),
], []))).toBe(false);
});
it('aria-labelledby, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [
JSXAttributeMock('aria-labelledby', 'elementId'),
], []))).toBe(true);
});
it('aria-labelledby without content, should return false', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [
JSXAttributeMock('aria-labelledby', ''),
], []))).toBe(false);
});
it('aria-labelledby with an expression container, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [
JSXAttributeMock('aria-labelledby', 'elementId', true),
], []))).toBe(true);
});
});
describe('label via custom label attribute', () => {
let customLabelProp;
beforeEach(() => {
customLabelProp = 'cowbell';
});
it('aria-label, should return true', () => {
expect(mayHaveAccessibleLabel(
JSXElementMock('div', [
JSXAttributeMock(customLabelProp, 'A delicate label'),
], []),
1,
[customLabelProp],
)).toBe(true);
});
});
describe('text label', () => {
it('Literal text, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
LiteralMock('A fancy label'),
]))).toBe(true);
});
it('JSXText, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
JSXTextMock('A fancy label'),
]))).toBe(true);
});
it('label is outside of default depth, should return false', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXTextMock('A fancy label'),
]),
]))).toBe(false);
});
it('label is inside of custom depth, should return true', () => {
expect(mayHaveAccessibleLabel(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXTextMock('A fancy label'),
]),
]),
2,
)).toBe(true);
});
it('deep nesting, should return true', () => {
expect(mayHaveAccessibleLabel(
JSXElementMock('div', [], [
JSXElementMock('div', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], []),
JSXElementMock('span', [], [
JSXElementMock('span', [], [
JSXElementMock('span', [], [
JSXTextMock('A fancy label'),
]),
]),
]),
]),
]),
JSXElementMock('span', [], []),
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
]),
]),
6,
)).toBe(true);
});
});
describe('image content', () => {
it('without alt, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
]),
]))).toBe(false);
});
it('with alt, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
JSXAttributeMock('alt', 'A sensible label'),
]),
]))).toBe(true);
});
it('with aria-label, should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
JSXElementMock('img', [
JSXAttributeMock('src', 'some/path'),
JSXAttributeMock('aria-label', 'A sensible label'),
]),
]))).toBe(true);
});
});
describe('Intederminate situations', () => {
describe('expression container children', () => {
it('should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [], [
JSXExpressionContainerMock('mysteryBox'),
]))).toBe(true);
});
});
describe('spread operator in attributes', () => {
it('should return true', () => {
expect(mayHaveAccessibleLabel(JSXElementMock('div', [
JSXAttributeMock('style', 'some-junk'),
JSXSpreadAttributeMock('props'),
], []))).toBe(true);
});
});
});
});

View file

@ -0,0 +1,46 @@
import expect from 'expect';
import parserOptionsMapper from '../../__util__/parserOptionsMapper';
describe('parserOptionsMapper', () => {
it('should return an test case object', () => {
const testCase = {
code: '<div />',
errors: [],
options: {},
};
expect(parserOptionsMapper(testCase)).toEqual({
code: '<div />',
errors: [],
options: {},
parserOptions: {
ecmaVersion: 2018,
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true,
},
},
});
});
it('should allow for overriding parserOptions', () => {
const testCase = {
code: '<div />',
errors: [],
options: {},
parserOptions: {
ecmaVersion: 5,
},
};
expect(parserOptionsMapper(testCase)).toEqual({
code: '<div />',
errors: [],
options: {},
parserOptions: {
ecmaVersion: 5,
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true,
},
},
});
});
});

View file

@ -0,0 +1,29 @@
import expect from 'expect';
import { generateObjSchema, arraySchema, enumArraySchema } from '../../../src/util/schemas';
describe('schemas', () => {
it('should generate an object schema with correct properties', () => {
const schema = generateObjSchema({
foo: 'bar',
baz: arraySchema,
});
const properties = schema.properties || {};
expect(properties.foo).toEqual(properties.foo, 'bar');
expect(properties.baz.type).toEqual('array');
});
describe('enumArraySchema', () => {
it('works with no arguments', () => {
expect(enumArraySchema()).toEqual({
additionalItems: false,
items: {
enum: [],
type: 'string',
},
minItems: 0,
type: 'array',
uniqueItems: true,
});
});
});
});