testaro 60.10.3 → 60.12.0

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,146 @@
1
+ /*
2
+ © 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2025 Jonathan Robert Pool. All rights reserved.
4
+
5
+ MIT License
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+ */
25
+
26
+ /*
27
+ focAndOp
28
+ Related to Tenon rule 190.
29
+
30
+ This test reports discrepancies between Tab-focusability and operability. The standard practice
31
+ is to make focusable elements operable and operable elements focusable. If focusable elements are
32
+ not operable, users are likely to be surprised that nothing happens when they try to operate such
33
+ elements. Conversely, if operable elements are not focusable, users who navigate with a
34
+ keyboard are prevented from operating those elements. The test considers an element
35
+ Tab-focusable if its tabIndex property has the value 0. The test considers an element operable if
36
+ it has a non-inherited pointer cursor and is not a 'LABEL' element, has an operable tag name, has
37
+ an interactive explicit role, or has an 'onclick' attribute.
38
+ */
39
+
40
+ // IMPORTS
41
+
42
+ const {doTest} = require('../procs/testaro');
43
+
44
+ // FUNCTIONS
45
+
46
+ // Runs the test and returns the result.
47
+ exports.reporter = async (page, withItems) => {
48
+ // Define a violation function for execution in the browser.
49
+ const getBadWhat = element => {
50
+ // Get whether the element is visible.
51
+ const isVisible = element.checkVisibility({
52
+ contentVisibilityAuto: true,
53
+ opacityProperty: true,
54
+ visibilityProperty: true
55
+ });
56
+ // If so:
57
+ if (isVisible) {
58
+ // Get whether it is focusable.
59
+ const isFocusable = element.tabIndex === 0;
60
+ // Get the operable tagnames.
61
+ const opTags = new Set(['A', 'BUTTON', 'IFRAME', 'INPUT','OPTION', 'SELECT', 'TEXTAREA']);
62
+ // Get the operable roles.
63
+ const opRoles = new Set([
64
+ 'button',
65
+ 'checkbox',
66
+ 'combobox',
67
+ 'composite',
68
+ 'grid',
69
+ 'gridcell',
70
+ 'input',
71
+ 'link',
72
+ 'listbox',
73
+ 'menu',
74
+ 'menubar',
75
+ 'menuitem',
76
+ 'menuitemcheckbox',
77
+ 'option',
78
+ 'radio',
79
+ 'radiogroup',
80
+ 'scrollbar',
81
+ 'searchbox',
82
+ 'select',
83
+ 'slider',
84
+ 'spinbutton',
85
+ 'switch',
86
+ 'tab',
87
+ 'tablist',
88
+ 'textbox',
89
+ 'tree',
90
+ 'treegrid',
91
+ 'treeitem',
92
+ 'widget',
93
+ ]);
94
+ // Initialize the operabilities of the element.
95
+ const opHow = [];
96
+ let hasPointer = false;
97
+ // If the element is not a label:
98
+ if (element.tagName !== 'LABEL') {
99
+ const styleDec = window.getComputedStyle(element);
100
+ hasPointer = styleDec.cursor === 'pointer';
101
+ // If it has a pointer cursor:
102
+ if (hasPointer) {
103
+ // Neutralize the cursor style of the parent element of the element.
104
+ element.parentElement.style.cursor = 'default';
105
+ // Get whether, after this, the element still has a pointer cursor.
106
+ hasPointer = styleDec.cursor === 'pointer';
107
+ // Add this to the operabilities of the element.
108
+ opHow.push('pointer cursor');
109
+ }
110
+ }
111
+ // If the element has a click event listener:
112
+ if (element.onclick) {
113
+ // Add this to the operabilities.
114
+ opHow.push('click listener');
115
+ }
116
+ // If the element has an operable explicit role:
117
+ const role = element.getAttribute('role');
118
+ if (opRoles.has(role)) {
119
+ // Add this to the operabilities.
120
+ opHow.push(`role ${role}`);
121
+ }
122
+ // If the element has an operable tagname:
123
+ const tagName = element.tagName;
124
+ if (opTags.has(tagName)) {
125
+ // Add this to the operabilities.
126
+ opHow.push(`tagname ${tagName}`);
127
+ }
128
+ const isOperable = opHow.length > 0;
129
+ // If the element is focusable but not operable:
130
+ if (isFocusable && ! isOperable) {
131
+ // Return a severity and violation description.
132
+ return '2:Element is Tab-focusable but not operable';
133
+ }
134
+ // Otherwise, if it is operable but not focusable:
135
+ else if (isOperable && ! isFocusable) {
136
+ // Return a severity and violation description.
137
+ return `3:Element is operable (${opHow.join(', ')}) but not Tab-focusable`;
138
+ }
139
+ }
140
+ };
141
+ const whats = 'Elements are Tab-focusable but not operable or vice versa';
142
+ // Perform the test and return the result.
143
+ return doTest(
144
+ page, withItems, 'focAndOp', 'body *', whats, 2, null, getBadWhat.toString()
145
+ );
146
+ };
package/testaro/focInd.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /*
2
2
  © 2021–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2025 Jonathan Robert Pool. All rights reserved.
3
4
 
4
5
  MIT License
5
6
 
@@ -41,90 +42,74 @@
41
42
  WARNING: This test fails to recognize outlines when run with firefox.
42
43
  */
43
44
 
44
- // ########## IMPORTS
45
+ // IMPORTS
45
46
 
46
- // Module to perform common operations.
47
- const {init, getRuleResult} = require('../procs/testaro');
47
+ const {doTest} = require('../procs/testaro');
48
48
 
49
- // ########## FUNCTIONS
49
+ // FUNCTIONS
50
50
 
51
51
  // Runs the test and returns the result.
52
52
  exports.reporter = async (page, withItems) => {
53
- // Initialize the locators and result.
54
- const all = await init(100, page, 'body *:visible');
55
- all.result.data.focusableCount = 0;
56
- // For each locator:
57
- for (const loc of all.allLocs) {
58
- // Get whether its element is focusable.
59
- const isFocusable = await loc.evaluate(el => el.tabIndex === 0);
60
- // If it is:
61
- if (isFocusable) {
62
- // Add this to the report.
63
- all.result.data.focusableCount++;
64
- // Get whether it has a nonstandard focus indicator.
65
- const hasBadIndicator = await loc.evaluate(el => {
66
- // Get the live style declaration of the element.
67
- const styleDec = window.getComputedStyle(el);
68
- // If the element has an outline:
53
+ // Define a violation function for execution in the browser.
54
+ const getBadWhat = element => {
55
+ // Get whether the element is visible.
56
+ const isVisible = element.checkVisibility({
57
+ contentVisibilityAuto: true,
58
+ opacityProperty: true,
59
+ visibilityProperty: true
60
+ });
61
+ // If so:
62
+ if (isVisible) {
63
+ // Get whether it is focusable.
64
+ const isFocusable = element.tabIndex === 0;
65
+ // If so:
66
+ if (isFocusable) {
67
+ // Get its live style declaration.
68
+ const styleDec = window.getComputedStyle(element);
69
+ // If the element has an outline before being focused:
69
70
  if (styleDec.outlineWidth !== '0px') {
70
- // Return a violation.
71
- return 'an outline when blurred';
71
+ // Return a violation description.
72
+ return 'Element is focusable but has an outline when blurred';
72
73
  }
73
- // Otherwise, i.e. if the element has no outline:
74
- else {
75
- // Focus the element.
76
- el.focus({preventScroll: true});
77
- // If it now has no outline:
78
- if (styleDec.outlineWidth === '0px') {
79
- // Return this violation.
80
- return 'no focus outline';
81
- }
82
- // Otherwise, if it now has an outline thinner than 2 pixels:
83
- else if (Number.parseFloat(styleDec.outlineWidth) < 2) {
84
- // Return this violation.
85
- return 'a focus outline thinner than 2 pixels';
86
- }
87
- // Otherwise, if it now has a transparent outline:
88
- else if (styleDec.outlineColor === 'rgba(0, 0, 0, 0)') {
89
- // Return this violation.
90
- return 'a transparent focus outline';
91
- }
92
- // Otherwise, if it now has a non-solid outline:
93
- else if (styleDec.outlineStyle !== 'solid') {
94
- // If the outline style exists:
95
- if (styleDec.outlineStyle) {
96
- // If the style is delegated to the user agent:
97
- if (styleDec.outlineStyle === 'auto') {
98
- // Return conformance.
99
- return false;
100
- }
101
- // Otherwise, i.e. if the style is not delegated to the user agent:
102
- else {
103
- // Return this violation.
104
- return `a focus outline with the ${styleDec.outlineStyle} instead of solid style`;
105
- }
106
- }
107
- // Otherwise, i.e. if no outline style exists:
108
- else {
109
- // Return this violation.
110
- return 'a focus outline with no style instead of solid style';
74
+ // Otherwise, i.e. if the element has no outline, focus the element.
75
+ element.focus({preventScroll: true});
76
+ // If it now has no outline:
77
+ if (styleDec.outlineWidth === '0px') {
78
+ // Return a violation description.
79
+ return 'Element when focused has no outline';
80
+ }
81
+ // Otherwise, if it now has an outline thinner than 2 pixels:
82
+ if (Number.parseFloat(styleDec.outlineWidth) < 2) {
83
+ // Return a violation description.
84
+ return 'Element when focused has an outline thinner than 2 pixels';
85
+ }
86
+ // Otherwise, if it now has a transparent outline:
87
+ if (styleDec.outlineColor === 'rgba(0, 0, 0, 0)') {
88
+ // Return a violation description.
89
+ return 'Element when focused has a transparent outline';
90
+ }
91
+ // Otherwise, if it now has a non-solid outline:
92
+ if (styleDec.outlineStyle !== 'solid') {
93
+ // If the outline style exists:
94
+ if (styleDec.outlineStyle) {
95
+ // If the style is not delegated to the user agent:
96
+ if (styleDec.outlineStyle !== 'auto') {
97
+ // Return a violation description
98
+ return `Element when focused has an outline with the ${styleDec.outlineStyle} instead of solid style`;
111
99
  }
112
100
  }
113
- // Otherwise, i.e. if the element now has a standard outline:
101
+ // Otherwise, i.e. if no outline style exists:
114
102
  else {
115
- // Return conformance.
116
- return false;
103
+ // Return a violation description.
104
+ return 'Element when focused has an outline with no instead of solid style';
117
105
  }
118
106
  }
119
- });
120
- // If it does:
121
- if (hasBadIndicator) {
122
- // Add the locator to the array of violators.
123
- all.locs.push([loc, hasBadIndicator]);
124
107
  }
125
108
  }
126
- }
127
- // Populate and return the result.
128
- const whats = ['Element has __param__', 'Elements fail to have standard focus indicators'];
129
- return await getRuleResult(withItems, all, 'focInd', whats, 1);
109
+ };
110
+ const whats = 'Elements fail to have standard focus indicators';
111
+ // Perform the test and return the result.
112
+ return doTest(
113
+ page, withItems, 'focInd', 'body *', whats, 1, null, getBadWhat.toString()
114
+ );
130
115
  };
@@ -32,54 +32,41 @@
32
32
  their subtrees are excluded.
33
33
  */
34
34
 
35
+ // IMPORTS
36
+
37
+ const {doTest} = require('../procs/testaro');
38
+
35
39
  // FUNCTIONS
36
40
 
37
41
  // Runs the test and returns the result.
38
42
  exports.reporter = async (page, withItems) => {
39
- // Return totals and standard instances for the rule.
40
- return await page.evaluate(withItems => {
41
- // Get all elements.
42
- const allElements = document.body.querySelectorAll('*');
43
- // Get all violation candidates, i.e. elements that have non-empty child text nodes.
44
- const candidates = Array.from(allElements).filter(el =>
45
- Array.from(el.childNodes).some(child =>
46
- child.nodeType === Node.TEXT_NODE &&
47
- child.textContent.trim().length
48
- )
43
+ // Define a violation function for execution in the browser.
44
+ const getBadWhat = element => {
45
+ // Get whether the element has a non-spacing child text node.
46
+ const hasText = Array.from(element.childNodes).some(child =>
47
+ child.nodeType === Node.TEXT_NODE && child.textContent.trim()
49
48
  );
50
- let violationCount = 0;
51
- const instances = [];
52
- // For each candidate:
53
- candidates.forEach(element => {
49
+ // If so:
50
+ if (hasText) {
54
51
  // Get its relevant style properties.
55
52
  const styleDec = window.getComputedStyle(element);
56
53
  const {fontSize, lineHeight} = styleDec;
57
54
  const fontSizeNum = Number.parseFloat(fontSize);
58
55
  const lineHeightNum = Number.parseFloat(lineHeight);
59
- // If it violates the rule:
60
- if (lineHeightNum < 1.495 * fontSizeNum) {
61
- // Increment the violation count.
62
- violationCount++;
63
- // If itemization is required:
64
- if (withItems) {
65
- const fontSizeRounded = fontSizeNum.toFixed(1);
66
- const lineHeightRounded = lineHeightNum.toFixed(1);
67
- const what = `Element line height (${lineHeightRounded}px) is less than 1.5 times its font size (${fontSizeRounded}px)`;
68
- // Add an instance to the instances.
69
- instances.push(window.getInstance(element, 'lineHeight', what, 1, 1));
70
- }
56
+ // Get whether it violates the rule.
57
+ const isBad = lineHeightNum < 1.495 * fontSizeNum;
58
+ // If it does:
59
+ if (isBad) {
60
+ const whatFontSize = `font size (${fontSizeNum.toFixed(1)}px)`;
61
+ const whatLineHeight = `line height (${lineHeightNum.toFixed(1)}px)`;
62
+ // Return a violation description.
63
+ return `Element ${whatLineHeight} is less than 1.5 times its ${whatFontSize}`;
71
64
  }
72
- });
73
- // If there were any violations and itemization is not required:
74
- if (violationCount && ! withItems) {
75
- const what = 'Element line heights are less than 1.5 times their font sizes';
76
- // Add a summary instance to the instances.
77
- instances.push(window.getInstance(null, 'lineHeight', what, violationCount, 1));
78
65
  }
79
- return {
80
- data: {},
81
- totals: [0, violationCount, 0, 0],
82
- standardInstances: instances
83
- };
84
- }, withItems);
66
+ };
67
+ const whats = 'Element line heights are less than 1.5 times their font sizes';
68
+ // Perform the test and return the result.
69
+ return doTest(
70
+ page, withItems, 'lineHeight', '*', whats, 1, null, getBadWhat.toString()
71
+ );
85
72
  };
@@ -1,5 +1,6 @@
1
1
  /*
2
2
  © 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2025 Jonathan Robert Pool. All rights reserved.
3
4
 
4
5
  MIT License
5
6
 
@@ -29,34 +30,38 @@
29
30
  This test reports elements with font sizes smaller than 11 pixels.
30
31
  */
31
32
 
32
- // Module to perform common operations.
33
- const {init, getRuleResult} = require('../procs/testaro');
33
+ // IMPORTS
34
34
 
35
- // ########## FUNCTIONS
35
+ const {doTest} = require('../procs/testaro');
36
+
37
+ // FUNCTIONS
36
38
 
37
- // Runs the test and returns the result.
38
39
  exports.reporter = async (page, withItems) => {
39
- // Initialize the locators and result.
40
- const all = await init(100, page, 'body *:not(script, style):visible', {hasText: /[^\s]+/});
41
- // For each locator:
42
- for (const loc of all.allLocs) {
43
- // Get the font size of its element if less than 11 pixels.
44
- const fontSize = await loc.evaluate(el => {
45
- const styleDec = window.getComputedStyle(el);
46
- const fontSizeString = styleDec.fontSize;
47
- const fontSize = Number.parseFloat(fontSizeString);
48
- return fontSize < 11 ? fontSize : null;
49
- });
50
- // If it violates the rule:
51
- if (fontSize) {
52
- // Add the locator to the array of violators.
53
- all.locs.push([loc, fontSize]);
40
+ const getBadWhat = element => {
41
+ const rawText = element.textContent || '';
42
+ // If the element has text content with any non-whitespace:
43
+ if (/[^\s]/.test(rawText)) {
44
+ const isVisible = element.checkVisibility({
45
+ contentVisibilityAuto: true,
46
+ opacityProperty: true,
47
+ visibilityProperty: true
48
+ });
49
+ // If the element is visible:
50
+ if (isVisible) {
51
+ const styleDec = window.getComputedStyle(element);
52
+ // Get its font size.
53
+ const fontSizeString = styleDec.fontSize;
54
+ const fontSize = Number.parseFloat(fontSizeString);
55
+ // If its font size is smaller than 11 pixels:
56
+ if (fontSize < 11) {
57
+ // Return a violation description.
58
+ return `Element is visible but its font size is ${fontSize}px, smaller than 11px`;
59
+ }
60
+ }
54
61
  }
55
- }
56
- // Populate and return the result.
57
- const whats = [
58
- 'Element has a font size of __param__ pixels, smaller than 11 pixels',
59
- 'Elements have font sizes smaller than 11 pixels'
60
- ];
61
- return await getRuleResult(withItems, all, 'miniText', whats, 2);
62
+ };
63
+ const whats = 'Visible elements have font sizes smaller than 11 pixels';
64
+ return doTest(
65
+ page, withItems, 'miniText', 'body *:not(script, style)', whats, 2, '', getBadWhat.toString()
66
+ );
62
67
  };
package/tests/testaro.js CHANGED
@@ -385,17 +385,17 @@ const allRules = [
385
385
  defaultOn: true
386
386
  },
387
387
  {
388
- id: 'focInd',
389
- what: 'missing and nonstandard focus indicators',
388
+ id: 'focAndOp',
389
+ what: 'Tab-focusable elements that are not operable or vice versa',
390
390
  launchRole: 'waster',
391
- timeOut: 10,
391
+ timeOut: 5,
392
392
  defaultOn: true
393
393
  },
394
394
  {
395
- id: 'focOp',
396
- what: 'Tab-focusable elements that are not operable',
395
+ id: 'focInd',
396
+ what: 'missing and nonstandard focus indicators',
397
397
  launchRole: 'waster',
398
- timeOut: 5,
398
+ timeOut: 10,
399
399
  defaultOn: true
400
400
  },
401
401
  {
@@ -419,13 +419,6 @@ const allRules = [
419
419
  timeOut: 10,
420
420
  defaultOn: true
421
421
  },
422
- {
423
- id: 'opFoc',
424
- what: 'operable elements that are not Tab-focusable',
425
- launchRole: 'waster',
426
- timeOut: 10,
427
- defaultOn: true
428
- },
429
422
  {
430
423
  id: 'tabNav',
431
424
  what: 'nonstandard keyboard navigation between elements with the tab role',
@@ -31,23 +31,16 @@
31
31
  </head>
32
32
  <body>
33
33
  <main>
34
- <h1>Page with correct and erroneous datalist references</h1>
34
+ <h1 id="nonDatalist">Page with correct and erroneous datalist references</h1>
35
35
  <form onsubmit="alert('Thank you for your submission')">
36
36
  <datalist id="okDatalist">
37
37
  <option value="red">
38
38
  <option value="yellow">
39
39
  </datalist>
40
- <datalist id="badDatalist">
41
- <option value="paper">
42
- <option value="plastic">
43
- </datalist>
44
- <datalist id="badDatalist">
45
- <option value="metal">
46
- <option value="stone">
47
- </datalist>
48
40
  <p><label>Name a color: <input type="text" name="color" list="okDatalist"></label></p>
49
- <p><label>Name a material: <input type="text" name="material" list="badDatalist"></label></p>
41
+ <p><label>Name a material: <input type="text" name="material" list></label></p>
50
42
  <p><label>Name a city: <input type="text" name="city" list="noDatalist"></label></p>
43
+ <p><label>Name a thing: <input type="text" name="thing" list="nonDatalist"></label></p>
51
44
  <p><button>Submit</button></p>
52
45
  </form>
53
46
  <p>The material and city inputs are defective.</p>
package/procs/operable.js DELETED
@@ -1,108 +0,0 @@
1
- /*
2
- © 2023 CVS Health and/or one of its affiliates. All rights reserved.
3
-
4
- MIT License
5
-
6
- Permission is hereby granted, free of charge, to any person obtaining a copy
7
- of this software and associated documentation files (the "Software"), to deal
8
- in the Software without restriction, including without limitation the rights
9
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the Software is
11
- furnished to do so, subject to the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be included in all
14
- copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
23
- */
24
-
25
- /*
26
- operable
27
- Returns whether the element of a locator is operable., i.e. it has a non-inherited pointer cursor
28
- and is not a 'LABEL' element, has an operable tag name, has an interactive explicit role, or has
29
- an 'onclick' attribute. The isOperable function modifies the page.
30
- */
31
-
32
- // ########## FUNCTIONS
33
-
34
- // Gets whether an element is operable.
35
- exports.isOperable = async loc => {
36
- // Get whether and, if so, how the element is operable.
37
- const operabilities = await loc.evaluate(el => {
38
- // Operable tag names.
39
- const opTags = new Set(['A', 'BUTTON', 'IFRAME', 'INPUT', 'SELECT', 'TEXTAREA']);
40
- // Operable roles.
41
- const opRoles = new Set([
42
- 'button',
43
- 'checkbox',
44
- 'combobox',
45
- 'composite',
46
- 'grid',
47
- 'gridcell',
48
- 'input',
49
- 'link',
50
- 'listbox',
51
- 'menu',
52
- 'menubar',
53
- 'menuitem',
54
- 'menuitemcheckbox',
55
- 'option',
56
- 'radio',
57
- 'radiogroup',
58
- 'scrollbar',
59
- 'searchbox',
60
- 'select',
61
- 'slider',
62
- 'spinbutton',
63
- 'switch',
64
- 'tab',
65
- 'tablist',
66
- 'textbox',
67
- 'tree',
68
- 'treegrid',
69
- 'treeitem',
70
- 'widget',
71
- ]);
72
- // Initialize the operabilities.
73
- const opHow = [];
74
- // If the element is not a label and has a non-inherited pointer cursor:
75
- let hasPointer = false;
76
- if (el.tagName !== 'LABEL') {
77
- const styleDec = window.getComputedStyle(el);
78
- hasPointer = styleDec.cursor === 'pointer';
79
- if (hasPointer) {
80
- el.parentElement.style.cursor = 'default';
81
- hasPointer = styleDec.cursor === 'pointer';
82
- }
83
- }
84
- if (hasPointer) {
85
- // Add this to the operabilities.
86
- opHow.push('pointer cursor');
87
- }
88
- // If the element is clickable:
89
- if (el.onclick) {
90
- // Add this to the operabilities.
91
- opHow.push('click listener');
92
- }
93
- // If the element has an operable explicit role:
94
- const role = el.getAttribute('role');
95
- if (opRoles.has(role)) {
96
- // Add this to the operabilities.
97
- opHow.push(`role ${role}`);
98
- }
99
- // If the element has an operable type:
100
- const tagName = el.tagName;
101
- if (opTags.has(tagName)) {
102
- // Add this to the operabilities.
103
- opHow.push(`tag name ${tagName}`);
104
- }
105
- return opHow;
106
- });
107
- return operabilities;
108
- };