Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/node-4+.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
matrix:
node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
eslint:
- 10
- 9
- 8
- 7
Expand All @@ -33,6 +34,38 @@ jobs:
- 4
- 3
exclude:
- node-version: 19
eslint: 10
- node-version: 18
eslint: 10
- node-version: 17
eslint: 10
- node-version: 16
eslint: 10
- node-version: 15
eslint: 10
- node-version: 14
eslint: 10
- node-version: 13
eslint: 10
- node-version: 12
eslint: 10
- node-version: 11
eslint: 10
- node-version: 10
eslint: 10
- node-version: 9
eslint: 10
- node-version: 8
eslint: 10
- node-version: 7
eslint: 10
- node-version: 6
eslint: 10
- node-version: 5
eslint: 10
- node-version: 4
eslint: 10
- node-version: 16
eslint: 9
- node-version: 15
Expand Down
20 changes: 4 additions & 16 deletions __tests__/__util__/RuleTester.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import test from 'tape';
import mockProperty from 'mock-property';
import { RuleTester } from 'eslint';

const orig = RuleTester.prototype.run;
RuleTester.prototype.run = function (name, rule, tests) {
test(`RuleTester: ${name}`, (t) => {
t.teardown(mockProperty(RuleTester.describe, 't', { value: t }));
orig.call(this, name, rule, tests);

t.end();
});
};

RuleTester.describe = function (text, method) {
RuleTester.it.title = text;
const self = this;
RuleTester.describe.t.test(text, (t) => {
t.teardown(mockProperty(RuleTester.it, 't', { value: t }));
method.call(self);
test(`RuleTester: ${text}`, (t) => {
RuleTester.it.t = t;
RuleTester.it.title = text;
method.call(this);
t.end();
});
};
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/accessible-emoji-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'Emojis should be wrapped in <span>, have role="img", and have an accessible description with aria-label or aria-labelledby.',
type: 'JSXOpeningElement',
};

ruleTester.run('accessible-emoji', rule, {
Expand Down
3 changes: 0 additions & 3 deletions __tests__/src/rules/alt-text-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ const ruleTester = new RuleTester();

const missingPropError = (type) => ({
message: `${type} elements must have an alt prop, either with meaningful text, or an empty string for decorative images.`,
type: 'JSXOpeningElement',
});

const altValueError = (type) => ({
message: `Invalid alt value for ${type}. \
Use alt="" for presentational images.`,
type: 'JSXOpeningElement',
});

const ariaLabelValueError = {
Expand All @@ -38,7 +36,6 @@ const ariaLabelledbyValueError = {

const preferAltError = () => ({
message: 'Prefer alt="" over a presentational role. First rule of aria is to not use aria if it can be achieved via native HTML.',
type: 'JSXOpeningElement',
});

const objectError = {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/anchor-ambiguous-text-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ const DEFAULT_AMBIGUOUS_WORDS = [

const expectedErrorGenerator = (words) => ({
message: `Ambiguous text within anchor. Screen reader users rely on link text for context; the words "${words.join('", "')}" are ambiguous and do not provide enough context.`,
type: 'JSXOpeningElement',
});

const expectedError = expectedErrorGenerator(DEFAULT_AMBIGUOUS_WORDS);
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/anchor-has-content-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'Anchors must have content and the content must be accessible by a screen reader.',
type: 'JSXOpeningElement',
};

ruleTester.run('anchor-has-content', rule, {
Expand Down
3 changes: 0 additions & 3 deletions __tests__/src/rules/anchor-is-valid-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,12 @@ const invalidHrefErrorMessage = 'The href attribute requires a valid value to be

const preferButtonexpectedError = {
message: preferButtonErrorMessage,
type: 'JSXOpeningElement',
};
const noHrefexpectedError = {
message: noHrefErrorMessage,
type: 'JSXOpeningElement',
};
const invalidHrefexpectedError = {
message: invalidHrefErrorMessage,
type: 'JSXOpeningElement',
};

const components = [{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'An element that manages focus with `aria-activedescendant` must have a tabindex',
type: 'JSXOpeningElement',
};

ruleTester.run('aria-activedescendant-has-tabindex', rule, {
Expand Down
2 changes: 0 additions & 2 deletions __tests__/src/rules/aria-props-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ const errorMessage = (name) => {

if (suggestions.length > 0) {
return {
type: 'JSXAttribute',
message: `${message} Did you mean to use ${suggestions}?`,
};
}

return {
type: 'JSXAttribute',
message,
};
};
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/aria-role-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const ruleTester = new RuleTester();

const errorMessage = {
message: 'Elements with ARIA roles must use a valid, non-abstract ARIA role.',
type: 'JSXAttribute',
};

const roleKeys = roles.keys();
Expand Down
2 changes: 0 additions & 2 deletions __tests__/src/rules/aria-unsupported-elements-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const ruleTester = new RuleTester();
const errorMessage = (invalidProp) => ({
message: `This element does not support ARIA roles, states and properties. \
Try removing the prop '${invalidProp}'.`,
type: 'JSXOpeningElement',
});

const domElements = dom.keys();
Expand All @@ -46,7 +45,6 @@ const ariaValidityTests = domElements.map((element) => {
};
}).concat({
code: '<fake aria-hidden />',
errors: [errorMessage('aria-hidden')],
});

// Generate invalid test cases.
Expand Down
14 changes: 4 additions & 10 deletions __tests__/src/rules/autocomplete-valid-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ const ruleTester = new RuleTester();

const invalidAutocomplete = [{
message: axeFailMessage('autocomplete-valid'),
type: 'JSXOpeningElement',
}];

const inappropriateAutocomplete = [{
message: axeFailMessage('autocomplete-appropriate'),
type: 'JSXOpeningElement',
}];

const componentsSettings = {
Expand Down Expand Up @@ -60,10 +54,10 @@ ruleTester.run('autocomplete-valid', rule, {

// PASSED "autocomplete-appropriate"
// see also: https://github.com/dequelabs/axe-core/issues/2912
{ code: '<input type="date" autocomplete="email" />;', errors: inappropriateAutocomplete },
{ code: '<input type="number" autocomplete="url" />;', errors: inappropriateAutocomplete },
{ code: '<input type="month" autocomplete="tel" />;', errors: inappropriateAutocomplete },
{ code: '<Foo type="month" autocomplete="tel"></Foo>;', errors: inappropriateAutocomplete, options: [{ inputComponents: ['Foo'] }] },
{ code: '<input type="date" autocomplete="email" />;' },
{ code: '<input type="number" autocomplete="url" />;' },
{ code: '<input type="month" autocomplete="tel" />;' },
{ code: '<Foo type="month" autocomplete="tel"></Foo>;', options: [{ inputComponents: ['Foo'] }] },
)).map(parserOptionsMapper),
invalid: parsers.all([].concat(
// FAILED "autocomplete-valid"
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/click-events-have-key-events-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const errorMessage = 'Visible, non-interactive elements with click handlers must

const expectedError = {
message: errorMessage,
type: 'JSXOpeningElement',
};

ruleTester.run('click-events-have-key-events', rule, {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/control-has-associated-label-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const ruleName = 'jsx-a11y/control-has-associated-label';

const expectedError = {
message: 'A control must be associated with a text label.',
type: 'JSXOpeningElement',
};

const alwaysValid = [
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/heading-has-content-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'Headings must have content and the content must be accessible by a screen reader.',
type: 'JSXOpeningElement',
};

const components = [{
Expand Down
3 changes: 1 addition & 2 deletions __tests__/src/rules/html-has-lang-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: '<html> elements must have the lang prop.',
type: 'JSXOpeningElement',
};

ruleTester.run('html-has-lang', rule, {
Expand All @@ -31,7 +30,7 @@ ruleTester.run('html-has-lang', rule, {
{ code: '<html lang={foo} />' },
{ code: '<html lang />' },
{ code: '<HTML />' },
{ code: '<HTMLTop lang="en" />', errors: [expectedError], settings: { 'jsx-a11y': { components: { HTMLTop: 'html' } } } },
{ code: '<HTMLTop lang="en" />', settings: { 'jsx-a11y': { components: { HTMLTop: 'html' } } } },
)).map(parserOptionsMapper),
invalid: parsers.all([].concat(
{ code: '<html />', errors: [expectedError] },
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/iframe-has-title-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: '<iframe> elements must have a unique title property.',
type: 'JSXOpeningElement',
};

const componentsSettings = {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/img-redundant-alt-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'Redundant alt attribute. Screen-readers already announce `img` tags as an image. You don’t need to use the words `image`, `photo,` or `picture` (or any specified custom words) in the alt prop.',
type: 'JSXOpeningElement',
};

ruleTester.run('img-redundant-alt', rule, {
Expand Down
3 changes: 0 additions & 3 deletions __tests__/src/rules/interactive-supports-focus-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ function template(strings, ...keys) {
}

const ruleName = 'interactive-supports-focus';
const type = 'JSXOpeningElement';
const codeTemplate = template`<${0} role="${1}" ${2}={() => void 0} />`;
const fixedTemplate = template`<${0} tabIndex={${1}} role="${2}" ${3}={() => void 0} />`;
const tabindexTemplate = template`<${0} role="${1}" ${2}={() => void 0} tabIndex="0" />`;
Expand All @@ -54,7 +53,6 @@ const buttonError = {
desc: 'Add `tabIndex={0}` to make the element focusable in sequential keyboard navigation.',
output: '<Div tabIndex={0} onClick={() => void 0} role="button" />',
}],
type,
};

const recommendedOptions = configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {};
Expand Down Expand Up @@ -208,7 +206,6 @@ const failReducer = (roles, handlers, messageTemplate) => (
roleAcc.concat(handlers.map((handler) => ({
code: codeTemplate(element, role, handler),
errors: [{
type,
message: messageTemplate(role),
suggestions: [{
desc: 'Add `tabIndex={0}` to make the element focusable in sequential keyboard navigation.',
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/label-has-associated-control-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const expectedErrors = {};
Object.keys(errorMessages).forEach((key) => {
expectedErrors[key] = {
message: errorMessages[key],
type: 'JSXOpeningElement',
};
});

Expand Down
3 changes: 0 additions & 3 deletions __tests__/src/rules/label-has-for-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,14 @@ const ruleTester = new RuleTester();

const expectedNestingError = {
message: 'Form label must have the following type of associated control: nesting',
type: 'JSXOpeningElement',
};

const expectedSomeError = {
message: 'Form label must have ANY of the following types of associated control: nesting, id',
type: 'JSXOpeningElement',
};

const expectedEveryError = {
message: 'Form label must have ALL of the following types of associated control: nesting, id',
type: 'JSXOpeningElement',
};

const optionsComponents = [{
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/lang-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'lang attribute must have a valid value.',
type: 'JSXAttribute',
};

const componentsSettings = {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/media-has-caption-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'Media elements such as <audio> and <video> must have a <track> for captions.',
type: 'JSXOpeningElement',
};

const customSchema = [
Expand Down
4 changes: 0 additions & 4 deletions __tests__/src/rules/mouse-events-have-key-events-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,15 @@ const ruleTester = new RuleTester();

const mouseOverError = {
message: 'onMouseOver must be accompanied by onFocus for accessibility.',
type: 'JSXAttribute',
};
const pointerEnterError = {
message: 'onPointerEnter must be accompanied by onFocus for accessibility.',
type: 'JSXAttribute',
};
const mouseOutError = {
message: 'onMouseOut must be accompanied by onBlur for accessibility.',
type: 'JSXAttribute',
};
const pointerLeaveError = {
message: 'onPointerLeave must be accompanied by onBlur for accessibility.',
type: 'JSXAttribute',
};

ruleTester.run('mouse-events-have-key-events', rule, {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/no-access-key-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'No access key attribute allowed. Inconsistencies between keyboard shortcuts and keyboard commands used by screen readers and keyboard-only users create a11y complications.',
type: 'JSXOpeningElement',
};

ruleTester.run('no-access-key', rule, {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/no-aria-hidden-on-focusable-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'aria-hidden="true" must not be set on focusable elements.',
type: 'JSXOpeningElement',
};

ruleTester.run('no-aria-hidden-on-focusable', rule, {
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/no-autofocus-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = {
message: 'The autoFocus prop should not be enabled, as it can reduce usability and accessibility for users.',
type: 'JSXAttribute',
};

const ignoreNonDOMSchema = [
Expand Down
1 change: 0 additions & 1 deletion __tests__/src/rules/no-distracting-elements-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const ruleTester = new RuleTester();

const expectedError = (element) => ({
message: `Do not use <${element}> elements as they can create visual accessibility issues and are deprecated.`,
type: 'JSXOpeningElement',
});

const componentsSettings = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const errorMessage = 'Interactive elements should not be assigned non-interactiv

const expectedError = {
message: errorMessage,
type: 'JSXAttribute',
};

const ruleName = 'jsx-a11y/no-interactive-element-to-noninteractive-role';
Expand Down
Loading