axe-core 4.2.0 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ {
2
+ "printWidth": 80,
3
+ "useTabs": false,
4
+ "tabWidth": 2,
5
+ "semi": true,
6
+ "singleQuote": true,
7
+ "trailingComma": "none",
8
+ "bracketSpacing": true,
9
+ "arrowParens": "avoid"
10
+ }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  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
4
 
5
+ ### [4.2.1](https://github.com/dequelabs/axe-core/compare/v4.2.0...v4.2.1) (2021-05-18)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **aria-allowed-attr:** pass aria-label on some HTML elements ([#2935](https://github.com/dequelabs/axe-core/issues/2935)) ([695aa77](https://github.com/dequelabs/axe-core/commit/695aa7751246c0e5e786a66df7808faa7a244576))
10
+ - treat input with no role as textbox ([#2929](https://github.com/dequelabs/axe-core/issues/2929)) ([de18030](https://github.com/dequelabs/axe-core/commit/de180307fd876cfc6a1a0bdb828818a323976c81))
11
+ - **autocomplete-appropriate:** pass for autocomplete=username and type=email ([#2896](https://github.com/dequelabs/axe-core/issues/2896)) ([8b478c8](https://github.com/dequelabs/axe-core/commit/8b478c82b3362fc27df8a0087c779327e6a9d6d0))
12
+ - **getStandards:** Read standards from utils ([#2903](https://github.com/dequelabs/axe-core/issues/2903)) ([52ad4c6](https://github.com/dequelabs/axe-core/commit/52ad4c69991e433d413846c4c9778fdd863aebeb))
13
+ - **required-parent:** Allow *item > group > *item nesting ([#2898](https://github.com/dequelabs/axe-core/issues/2898)) ([3acd229](https://github.com/dequelabs/axe-core/commit/3acd229b08b806ea359e7e08e37e8721cddc5290))
14
+ - **types:** make `evaluate` check optional ([#2902](https://github.com/dequelabs/axe-core/issues/2902)) ([75fabfe](https://github.com/dequelabs/axe-core/commit/75fabfef3adeade350902f2dd18928e44fbb7cf4))
15
+
5
16
  ## [4.2.0](https://github.com/dequelabs/axe-core/compare/v4.1.2...v4.2.0) (2021-04-23)
6
17
 
7
18
  ### Features
package/README.md CHANGED
@@ -16,7 +16,7 @@ Axe is an accessibility testing engine for websites and other HTML-based user in
16
16
 
17
17
  Axe-core has different types of rules, for WCAG 2.0 and 2.1 on level A and AA, as well as a number of best practices that help you identify common accessibility practices like ensuring every page has an `h1` heading, and to help you avoid "gotchas" in ARIA like where an ARIA attribute you used will get ignored.
18
18
 
19
- With axe-core, you can find **up to 50% of WCAG issues automatically**. Additionally, axe-core will return elements as "incomplete" where axe-core could not be certain, and manual review is needed. To further improve test coverage we recommend the [intelligent guided tests](https://www.youtube.com/watch?v=AtsX0dPCG_4&feature=youtu.be&ab_channel=DequeSystems) in the [axe Extension](https://www.deque.com/axe/browser-extensions/).
19
+ With axe-core, you can find **on average 57% of WCAG issues automatically**. Additionally, axe-core will return elements as "incomplete" where axe-core could not be certain, and manual review is needed. To further improve test coverage we recommend the [intelligent guided tests](https://www.youtube.com/watch?v=AtsX0dPCG_4&feature=youtu.be&ab_channel=DequeSystems) in the [axe Extension](https://www.deque.com/axe/browser-extensions/).
20
20
 
21
21
  The complete list of rules, grouped WCAG level and best practice, can found in [doc/rule-descriptions.md](./doc/rule-descriptions.md).
22
22
 
package/axe.d.ts CHANGED
@@ -206,7 +206,7 @@ declare namespace axe {
206
206
  }
207
207
  interface Check {
208
208
  id: string;
209
- evaluate: Function | string;
209
+ evaluate?: Function | string;
210
210
  after?: Function | string;
211
211
  options?: any;
212
212
  matches?: string;
package/axe.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! axe v4.2.0
1
+ /*! axe v4.2.1
2
2
  * Copyright (c) 2021 Deque Systems, Inc.
3
3
  *
4
4
  * Your use of this Source Code Form is subject to the terms of the Mozilla Public
@@ -27,7 +27,7 @@
27
27
  return _typeof(obj);
28
28
  }
29
29
  var axe = axe || {};
30
- axe.version = '4.2.0';
30
+ axe.version = '4.2.1';
31
31
  if (typeof define === 'function' && define.amd) {
32
32
  define('axe-core', [], function() {
33
33
  return axe;
@@ -5067,6 +5067,9 @@
5067
5067
  getShadowSelector: function getShadowSelector() {
5068
5068
  return get_shadow_selector_default;
5069
5069
  },
5070
+ getStandards: function getStandards() {
5071
+ return _getStandards;
5072
+ },
5070
5073
  getStyleSheetFactory: function getStyleSheetFactory() {
5071
5074
  return get_stylesheet_factory_default;
5072
5075
  },
@@ -8483,7 +8486,7 @@
8483
8486
  },
8484
8487
  listitem: {
8485
8488
  type: 'structure',
8486
- requiredContext: [ 'list' ],
8489
+ requiredContext: [ 'list', 'group' ],
8487
8490
  allowedAttrs: [ 'aria-level', 'aria-posinset', 'aria-setsize', 'aria-expanded' ],
8488
8491
  superclassRole: [ 'section' ],
8489
8492
  nameFromContent: true
@@ -10751,6 +10754,9 @@
10751
10754
  return windowScroll.concat(getElmScrollRecursive(document.body));
10752
10755
  }
10753
10756
  var get_scroll_state_default = getScrollState;
10757
+ function _getStandards() {
10758
+ return clone_default(standards_default);
10759
+ }
10754
10760
  function getStyleSheetFactory(dynamicDoc) {
10755
10761
  if (!dynamicDoc) {
10756
10762
  throw new Error('axe.utils.getStyleSheetFactory should be invoked with an argument');
@@ -12155,22 +12161,9 @@
12155
12161
  suggestionsSourceElement = listElement && listElement.nodeName.toLowerCase() === 'datalist';
12156
12162
  }
12157
12163
  switch (vNode.props.type) {
12158
- case 'button':
12159
- case 'image':
12160
- case 'reset':
12161
- case 'submit':
12162
- return 'button';
12163
-
12164
12164
  case 'checkbox':
12165
12165
  return 'checkbox';
12166
12166
 
12167
- case 'email':
12168
- case 'tel':
12169
- case 'text':
12170
- case 'url':
12171
- case '':
12172
- return !suggestionsSourceElement ? 'textbox' : 'combobox';
12173
-
12174
12167
  case 'number':
12175
12168
  return 'spinbutton';
12176
12169
 
@@ -12182,6 +12175,22 @@
12182
12175
 
12183
12176
  case 'search':
12184
12177
  return !suggestionsSourceElement ? 'searchbox' : 'combobox';
12178
+
12179
+ case 'button':
12180
+ case 'image':
12181
+ case 'reset':
12182
+ case 'submit':
12183
+ return 'button';
12184
+
12185
+ case 'text':
12186
+ case 'tel':
12187
+ case 'url':
12188
+ case 'email':
12189
+ case '':
12190
+ return !suggestionsSourceElement ? 'textbox' : 'combobox';
12191
+
12192
+ default:
12193
+ return 'textbox';
12185
12194
  }
12186
12195
  },
12187
12196
  li: 'listitem',
@@ -15425,29 +15434,35 @@
15425
15434
  return virtualNode.attr('aria-hidden') !== 'true';
15426
15435
  }
15427
15436
  var aria_hidden_body_evaluate_default = ariaHiddenBodyEvaluate;
15428
- function ariaProhibitedAttrEvaluate(node, options, virtualNode) {
15429
- var prohibited = [];
15430
- var role = get_role_default(virtualNode);
15431
- var attrs = virtualNode.attrNames;
15432
- var prohibitedAttrs = role ? standards_default.ariaRoles[role].prohibitedAttrs : [ 'aria-label', 'aria-labelledby' ];
15433
- if (!prohibitedAttrs) {
15437
+ function ariaProhibitedAttrEvaluate(node) {
15438
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
15439
+ var virtualNode = arguments.length > 2 ? arguments[2] : undefined;
15440
+ var _options$elementsAllo = options.elementsAllowedAriaLabel, elementsAllowedAriaLabel = _options$elementsAllo === void 0 ? [] : _options$elementsAllo;
15441
+ var prohibitedList = listProhibitedAttrs(virtualNode, elementsAllowedAriaLabel);
15442
+ var prohibited = prohibitedList.filter(function(attrName) {
15443
+ if (!virtualNode.attrNames.includes(attrName)) {
15444
+ return false;
15445
+ }
15446
+ return sanitize_default(virtualNode.attr(attrName)) !== '';
15447
+ });
15448
+ if (prohibited.length === 0) {
15434
15449
  return false;
15435
15450
  }
15436
- for (var _i14 = 0; _i14 < attrs.length; _i14++) {
15437
- var attrName = attrs[_i14];
15438
- var attrValue = sanitize_default(virtualNode.attr(attrName));
15439
- if (prohibitedAttrs.includes(attrName) && attrValue !== '') {
15440
- prohibited.push(attrName);
15441
- }
15451
+ this.data(prohibited);
15452
+ var hasTextContent = sanitize_default(subtree_text_default(virtualNode)) !== '';
15453
+ return hasTextContent ? void 0 : true;
15454
+ }
15455
+ function listProhibitedAttrs(virtualNode, elementsAllowedAriaLabel) {
15456
+ var role = get_role_default(virtualNode);
15457
+ var roleSpec = standards_default.ariaRoles[role];
15458
+ if (roleSpec) {
15459
+ return roleSpec.prohibitedAttrs || [];
15442
15460
  }
15443
- if (prohibited.length) {
15444
- this.data(prohibited);
15445
- if (!role && sanitize_default(subtree_text_default(virtualNode)) !== '') {
15446
- return void 0;
15447
- }
15448
- return true;
15461
+ var nodeName2 = virtualNode.props.nodeName;
15462
+ if (elementsAllowedAriaLabel.includes(nodeName2)) {
15463
+ return [];
15449
15464
  }
15450
- return false;
15465
+ return [ 'aria-label', 'aria-labelledby' ];
15451
15466
  }
15452
15467
  var aria_prohibited_attr_evaluate_default = ariaProhibitedAttrEvaluate;
15453
15468
  var standards_exports = {};
@@ -15484,8 +15499,8 @@
15484
15499
  required = unique_array_default(options[role], required);
15485
15500
  }
15486
15501
  if (role && required) {
15487
- for (var _i15 = 0, l = required.length; _i15 < l; _i15++) {
15488
- var attr = required[_i15];
15502
+ for (var _i14 = 0, l = required.length; _i14 < l; _i14++) {
15503
+ var attr = required[_i14];
15489
15504
  if (!virtualNode.attr(attr) && !(elmSpec.implicitAttrs && typeof elmSpec.implicitAttrs[attr] !== 'undefined')) {
15490
15505
  missing.push(attr);
15491
15506
  }
@@ -15502,8 +15517,8 @@
15502
15517
  function getOwnedRoles(virtualNode, required) {
15503
15518
  var ownedRoles = [];
15504
15519
  var ownedElements = get_owned_virtual_default(virtualNode);
15505
- var _loop4 = function _loop4(_i16) {
15506
- var ownedElement = ownedElements[_i16];
15520
+ var _loop4 = function _loop4(_i15) {
15521
+ var ownedElement = ownedElements[_i15];
15507
15522
  var role = get_role_default(ownedElement, {
15508
15523
  noPresentational: true
15509
15524
  });
@@ -15515,8 +15530,8 @@
15515
15530
  ownedRoles.push(role);
15516
15531
  }
15517
15532
  };
15518
- for (var _i16 = 0; _i16 < ownedElements.length; _i16++) {
15519
- _loop4(_i16);
15533
+ for (var _i15 = 0; _i15 < ownedElements.length; _i15++) {
15534
+ _loop4(_i15);
15520
15535
  }
15521
15536
  return ownedRoles;
15522
15537
  }
@@ -15537,8 +15552,8 @@
15537
15552
  return !expandedChildRoles.includes(requiredRole) || expanded && requiredRole === popupRole;
15538
15553
  });
15539
15554
  }
15540
- for (var _i17 = 0; _i17 < ownedRoles.length; _i17++) {
15541
- var ownedRole = ownedRoles[_i17];
15555
+ for (var _i16 = 0; _i16 < ownedRoles.length; _i16++) {
15556
+ var ownedRole = ownedRoles[_i16];
15542
15557
  if (required.includes(ownedRole)) {
15543
15558
  required = required.filter(function(requiredRole) {
15544
15559
  return requiredRole !== ownedRole;
@@ -15574,7 +15589,7 @@
15574
15589
  return false;
15575
15590
  }
15576
15591
  var aria_required_children_evaluate_default = ariaRequiredChildrenEvaluate;
15577
- function getMissingContext(virtualNode, reqContext, includeElement) {
15592
+ function getMissingContext(virtualNode, ownGroupRoles, reqContext, includeElement) {
15578
15593
  var explicitRole2 = get_explicit_role_default(virtualNode);
15579
15594
  if (!reqContext) {
15580
15595
  reqContext = required_context_default(explicitRole2);
@@ -15586,6 +15601,9 @@
15586
15601
  while (vNode) {
15587
15602
  var parentRole = get_role_default(vNode);
15588
15603
  if (reqContext.includes('group') && parentRole === 'group') {
15604
+ if (ownGroupRoles.includes(explicitRole2)) {
15605
+ reqContext.push(explicitRole2);
15606
+ }
15589
15607
  vNode = vNode.parent;
15590
15608
  continue;
15591
15609
  }
@@ -15614,14 +15632,15 @@
15614
15632
  return owners.length ? owners : null;
15615
15633
  }
15616
15634
  function ariaRequiredParentEvaluate(node, options, virtualNode) {
15617
- var missingParents = getMissingContext(virtualNode);
15635
+ var ownGroupRoles = options && Array.isArray(options.ownGroupRoles) ? options.ownGroupRoles : [];
15636
+ var missingParents = getMissingContext(virtualNode, ownGroupRoles);
15618
15637
  if (!missingParents) {
15619
15638
  return true;
15620
15639
  }
15621
15640
  var owners = getAriaOwners(node);
15622
15641
  if (owners) {
15623
- for (var i = 0, l = owners.length; i < l; i++) {
15624
- missingParents = getMissingContext(get_node_from_tree_default(owners[i]), missingParents, true);
15642
+ for (var _i17 = 0, l = owners.length; _i17 < l; _i17++) {
15643
+ missingParents = getMissingContext(get_node_from_tree_default(owners[_i17]), ownGroupRoles, missingParents, true);
15625
15644
  if (!missingParents) {
15626
15645
  return true;
15627
15646
  }
@@ -16823,6 +16842,7 @@
16823
16842
  var allowedTypesMap = {
16824
16843
  bday: [ 'text', 'search', 'date' ],
16825
16844
  email: [ 'text', 'search', 'email' ],
16845
+ username: [ 'text', 'search', 'email' ],
16826
16846
  'street-address': [ 'text' ],
16827
16847
  tel: [ 'text', 'search', 'tel' ],
16828
16848
  'tel-country-code': [ 'text', 'search', 'tel' ],
@@ -21059,8 +21079,8 @@
21059
21079
  help: 'Form field must not have multiple label elements'
21060
21080
  },
21061
21081
  'frame-focusable-content': {
21062
- description: 'Ensures <frame> and <iframe> elements with tabindex=-1 do not have focusable content',
21063
- help: 'Frames with tabindex=-1 must not have focusable content'
21082
+ description: 'Ensures <frame> and <iframe> elements with focusable content do not have tabindex=-1',
21083
+ help: 'Frames with focusable content must not have tabindex=-1'
21064
21084
  },
21065
21085
  'frame-tested': {
21066
21086
  description: 'Ensures <iframe> and <frame> elements contain the axe-core script',
@@ -21340,10 +21360,10 @@
21340
21360
  }
21341
21361
  },
21342
21362
  'aria-prohibited-attr': {
21343
- impact: 'critical',
21363
+ impact: 'serious',
21344
21364
  messages: {
21345
21365
  pass: 'ARIA attribute is allowed',
21346
- fail: 'ARIA attribute cannot be used: ${data.values}',
21366
+ fail: 'ARIA attribute cannot be used, add a role attribute or use a different element: ${data.values}',
21347
21367
  incomplete: 'ARIA attribute is not well supported on the element and the text content will be used instead: ${data.values}'
21348
21368
  }
21349
21369
  },
@@ -22203,7 +22223,12 @@
22203
22223
  tags: [ 'cat.aria', 'wcag2a', 'wcag412' ],
22204
22224
  all: [],
22205
22225
  any: [ 'aria-allowed-attr' ],
22206
- none: [ 'aria-unsupported-attr', 'aria-prohibited-attr' ]
22226
+ none: [ 'aria-unsupported-attr', {
22227
+ options: {
22228
+ elementsAllowedAriaLabel: [ 'audio', 'applet', 'canvas', 'dl', 'embed', 'iframe', 'input', 'label', 'meter', 'object', 'svg', 'video' ]
22229
+ },
22230
+ id: 'aria-prohibited-attr'
22231
+ } ]
22207
22232
  }, {
22208
22233
  id: 'aria-allowed-role',
22209
22234
  excludeHidden: false,
@@ -22328,7 +22353,12 @@
22328
22353
  matches: 'aria-required-parent-matches',
22329
22354
  tags: [ 'cat.aria', 'wcag2a', 'wcag131' ],
22330
22355
  all: [],
22331
- any: [ 'aria-required-parent' ],
22356
+ any: [ {
22357
+ options: {
22358
+ ownGroupRoles: [ 'listitem', 'treeitem' ]
22359
+ },
22360
+ id: 'aria-required-parent'
22361
+ } ],
22332
22362
  none: []
22333
22363
  }, {
22334
22364
  id: 'aria-roledescription',
@@ -23237,7 +23267,10 @@
23237
23267
  evaluate: 'aria-hidden-body-evaluate'
23238
23268
  }, {
23239
23269
  id: 'aria-prohibited-attr',
23240
- evaluate: 'aria-prohibited-attr-evaluate'
23270
+ evaluate: 'aria-prohibited-attr-evaluate',
23271
+ options: {
23272
+ elementsAllowedAriaLabel: [ 'audio', 'applet', 'canvas', 'dl', 'embed', 'iframe', 'input', 'label', 'meter', 'object', 'svg', 'video' ]
23273
+ }
23241
23274
  }, {
23242
23275
  id: 'aria-required-attr',
23243
23276
  evaluate: 'aria-required-attr-evaluate'
@@ -23249,7 +23282,10 @@
23249
23282
  }
23250
23283
  }, {
23251
23284
  id: 'aria-required-parent',
23252
- evaluate: 'aria-required-parent-evaluate'
23285
+ evaluate: 'aria-required-parent-evaluate',
23286
+ options: {
23287
+ ownGroupRoles: [ 'listitem', 'treeitem' ]
23288
+ }
23253
23289
  }, {
23254
23290
  id: 'aria-roledescription',
23255
23291
  evaluate: 'aria-roledescription-evaluate',