From 31795d9ef15b8e66d67405bf80e5afe6e2807f5b Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 7 Nov 2019 09:45:24 -0600 Subject: [PATCH 1/3] added combobox grid using ARIA 1.2 pattern --- examples/combobox/css/combobox.css | 93 +++ examples/combobox/grid-combo.html | 421 ++++++++++++ examples/combobox/js/grid-combo-example.js | 98 +++ examples/combobox/js/grid-combobox.js | 312 +++++++++ test/tests/combobox_grid-combo-12.js | 762 +++++++++++++++++++++ 5 files changed, 1686 insertions(+) create mode 100644 examples/combobox/css/combobox.css create mode 100644 examples/combobox/grid-combo.html create mode 100644 examples/combobox/js/grid-combo-example.js create mode 100644 examples/combobox/js/grid-combobox.js create mode 100644 test/tests/combobox_grid-combo-12.js diff --git a/examples/combobox/css/combobox.css b/examples/combobox/css/combobox.css new file mode 100644 index 0000000000..25e9671a3d --- /dev/null +++ b/examples/combobox/css/combobox.css @@ -0,0 +1,93 @@ +.annotate { + font-style: italic; + color: #366ed4; +} + +.hidden { + display: none; +} + +.combobox-wrapper { + display: inline-block; + position: relative; + font-size: 16px; +} + +.combobox-label { + font-size: 14px; + font-weight: bold; + margin-right: 5px; +} + +.listbox, +.grid { + min-width: 230px; + background: white; + border: 1px solid #ccc; + list-style: none; + margin: 0; + padding: 0; + position: absolute; + top: 1.7em; + z-index: 1; +} + +.listbox .result { + cursor: default; + margin: 0; +} + +.grid .result-row { + padding: 2px; + cursor: default; + margin: 0; +} + +.listbox .result:hover, +.grid .result-row:hover { + background: rgb(139, 189, 225); +} + +.listbox .focused, +.grid .focused { + background: rgb(139, 189, 225); +} + +.grid .focused-cell { + outline-style: dotted; + outline-color: green; +} + +.combobox-wrapper input { + font-size: inherit; + border: 1px solid #aaa; + border-radius: 2px; + line-height: 1.5em; + padding-right: 30px; + width: 200px; +} + +.combobox-dropdown { + position: absolute; + right: 0; + top: 0; + padding: 0 0 2px; + height: 1.5em; + border-radius: 0 2px 2px 0; + border: 1px solid #aaa; +} + +.grid .result-cell { + display: inline-block; + cursor: default; + margin: 0; + padding: 0 5px; +} + +.grid .result-cell:last-child { + float: right; + font-size: 12px; + font-weight: 200; + color: #333; + line-height: 24px; +} diff --git a/examples/combobox/grid-combo.html b/examples/combobox/grid-combo.html new file mode 100644 index 0000000000..eec8b2e0b2 --- /dev/null +++ b/examples/combobox/grid-combo.html @@ -0,0 +1,421 @@ + + + + +ARIA 1.2 Combobox with Grid Popup Example | WAI-ARIA Authoring Practices 1.1 + + + + + + + + + + + + + + + + +
+

ARIA 1.2 Combobox with Grid Popup Example

+

+ The following example combobox implements the + combobox design pattern + using a grid for the suggested values popup. +

+

+ In this example, users can specify the name of a fruit or vegetable by either typing a value in the box or choosing from the set of values presented in a grid popup. + The popup becomes available after the textbox contains a character that matches the beginning of the name of one of the items in the set of value suggestions. + Users may type any value in the textbox; this implementation does not limit input to values that are in the set of value suggestions. +

+

+ The grid that presents suggested values has two columns. + Each row of the grid represents one suggestion; column one contains the name of the fruit or vegetable and column two identifies whether it is a fruit or vegetable. +

+

Similar examples include:

+ +
+

Example

+ +
+ +
+
+ +
+ +
+
+ +
+ +
+

Keyboard Support

+

+ The example combobox on this page implements the following keyboard interface. + Other variations and options for the keyboard interface are described in the + Keyboard Interaction section of the combobox design pattern. +

+

Textbox

+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
Down ArrowIf the grid is displayed, moves focus to the first suggested value.
Up ArrowIf the grid is displayed, moves focus to the last suggested value.
Escape +
    +
  • Clears the textbox
  • +
  • If the grid is displayed, closes it.
  • +
+
Standard single line text editing keys +
    +
  • Keys used for cursor movement and text manipulation, such as Delete and Shift + Right Arrow.
  • +
  • An HTML input with type=text is used for the textbox so the browser will provide platform-specific editing keys.
  • +
+
+

Grid Popup

+

+ NOTE: When visual focus is in the grid, DOM focus remains on the textbox and the value of aria-activedescendant on the textbox is set to a value that refers to an element in the grid that is visually indicated as focused. + Where the following descriptions of keyboard commands mention focus, they are referring to the visual focus indicator. + For more information about this focus management technique, see + Using aria-activedescendant to Manage Focus. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
Enter +
    +
  • Sets the textbox value to the content of the first cell in the row containing focus.
  • +
  • Closes the grid popup.
  • +
  • Sets focus on the textbox.
  • +
+
Escape +
    +
  • Closes the grid popup.
  • +
  • Sets focus on the textbox.
  • +
  • Clears the textbox.
  • +
+
Down Arrow +
    +
  • Moves focus to the next row.
  • +
  • If focus is in the last row, moves focus to the first row.
  • +
  • Note: This wrapping behavior is useful when Home and End move the editing cursor as described below.
  • +
+
Up Arrow +
    +
  • Moves focus to the previous row.
  • +
  • If focus is in the first row, moves focus to the last row.
  • +
  • Note: This wrapping behavior is useful when Home and End move the editing cursor as described below.
  • +
+
Right Arrow +
    +
  • Moves focus to the next cell.
  • +
  • If focus is in the last cell in a row, moves focus to the first cell in the next row.
  • +
  • If focus is in the last cell in the last row, moves focus to the first cell in the first row.
  • +
+
Left Arrow +
    +
  • Moves focus to the previous cell.
  • +
  • If focus is in the first cell in a row, moves focus to the last cell in the previous row.
  • +
  • If focus is in the first cell in the first row, moves focus to the last cell in the last row.
  • +
+
HomeMoves focus to the textbox and places the editing cursor at the beginning of the field.
EndMoves focus to the textbox and places the editing cursor at the end of the field.
Printable Characters +
    +
  • Moves focus to the textbox.
  • +
  • Types the character in the textbox.
  • +
+
+
+ +
+

Role, Property, State, and Tabindex Attributes

+

+ The example comboboxes on this page implement the following ARIA roles, states, and properties. + Information about other ways of applying ARIA roles, states, and properties is available in the + Roles, States, and Properties section of the combobox design pattern. +

+

Textbox

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleAttributeElementUsage
+ combobox + input[type="text"] +
    +
  • Identifies the element as a combobox.
  • +
  • Note: Unlike this ARIA 1.2 combobox, an ARIA 1.1 pattern would have the combobox role on a container element of the textbox input instead of the textbox itself.
+ + +
+ aria-haspopup=grid + input[type="text"]Indicates that the combobox can popup a grid to suggest values.
+ aria-expanded=false + input[type="text"]Indicates that the popup element is not displayed.
+ aria-expanded=true + input[type="text"]Indicates that the popup element is displayed.
+ id="string" + input[type="text"] +
    +
  • Referenced by for attribute of label element to provide an accessible label.
  • +
  • Recommended labeling method for HTML input elements so clicking label focuses input.
  • +
+
+ aria-autocomplete=list + input[type="text"]Indicates that the autocomplete behavior of the text input is to suggest a list of possible values in a popup.
+ aria-controls=IDREF + input[type="text"] +
    +
  • Identifies the popup element that lists suggested values.
  • +
  • Note: +
      +
    • In the ARIA 1.0 combobox pattern, the textbox has aria-owns instead of aria-controls.
    • +
    • In this ARIA 1.1 pattern, aria-owns is instead on the parent container so the popup element is a sibling of the textbox instead of a child of the textbox, making it perceivable by screen reader users as an element adjacent to the textbox when using a reading cursor or touch interface.
    • +
    +
  • +
+
+ aria-activedescendant=IDREF + input[type="text"] +
    +
  • When a cell in the grid is visually indicated as having keyboard focus, refers to that cell.
  • +
  • When navigation keys, such as Down Arrow, are pressed, the JavaScript changes the value.
  • +
  • Enables assistive technologies to know which element the application regards as focused while DOM focus remains on the input element.
  • +
  • + For more information about this focus management technique, see + Using aria-activedescendant to Manage Focus. +
  • +
+
+

Grid Popup

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleAttributeElementUsage
+ grid + + div + Identifies the element as a grid.
+ aria-labelledby=IDREF + divProvides a label for the grid element of the combobox.
+ row + divIdentifies the element containing all the cells for a row.
+ aria-selected=true + div +
    +
  • Specified on a row in the grid when it is visually indicated as selected.
  • +
  • Occurs only when a cell in the grid is referenced by aria-activedescendant.
  • +
+
gridcelldivIdentifies the element containing the content for a single cell.
+
+ +
+

Javascript and CSS Source Code

+ +
+ +
+

HTML Source Code

+ +
+ + + +
+
+ + + diff --git a/examples/combobox/js/grid-combo-example.js b/examples/combobox/js/grid-combo-example.js new file mode 100644 index 0000000000..0f641a2977 --- /dev/null +++ b/examples/combobox/js/grid-combo-example.js @@ -0,0 +1,98 @@ +/* +* This content is licensed according to the W3C Software License at +* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document +* +* ARIA Combobox Examples +*/ + +var FRUITS_AND_VEGGIES = [ + ['Apple', 'Fruit'], + ['Artichoke', 'Vegetable'], + ['Asparagus', 'Vegetable'], + ['Banana', 'Fruit'], + ['Beets', 'Vegetable'], + ['Bell pepper', 'Vegetable'], + ['Broccoli', 'Vegetable'], + ['Brussels sprout', 'Vegetable'], + ['Cabbage', 'Vegetable'], + ['Carrot', 'Vegetable'], + ['Cauliflower', 'Vegetable'], + ['Celery', 'Vegetable'], + ['Chard', 'Vegetable'], + ['Chicory', 'Vegetable'], + ['Corn', 'Vegetable'], + ['Cucumber', 'Vegetable'], + ['Daikon', 'Vegetable'], + ['Date', 'Fruit'], + ['Edamame', 'Vegetable'], + ['Eggplant', 'Vegetable'], + ['Elderberry', 'Fruit'], + ['Fennel', 'Vegetable'], + ['Fig', 'Fruit'], + ['Garlic', 'Vegetable'], + ['Grape', 'Fruit'], + ['Honeydew melon', 'Fruit'], + ['Iceberg lettuce', 'Vegetable'], + ['Jerusalem artichoke', 'Vegetable'], + ['Kale', 'Vegetable'], + ['Kiwi', 'Fruit'], + ['Leek', 'Vegetable'], + ['Lemon', 'Fruit'], + ['Mango', 'Fruit'], + ['Mangosteen', 'Fruit'], + ['Melon', 'Fruit'], + ['Mushroom', 'Fungus'], + ['Nectarine', 'Fruit'], + ['Okra', 'Vegetable'], + ['Olive', 'Vegetable'], + ['Onion', 'Vegetable'], + ['Orange', 'Fruit'], + ['Parship', 'Vegetable'], + ['Pea', 'Vegetable'], + ['Pear', 'Fruit'], + ['Pineapple', 'Fruit'], + ['Potato', 'Vegetable'], + ['Pumpkin', 'Fruit'], + ['Quince', 'Fruit'], + ['Radish', 'Vegetable'], + ['Rhubarb', 'Vegetable'], + ['Shallot', 'Vegetable'], + ['Spinach', 'Vegetable'], + ['Squash', 'Vegetable'], + ['Strawberry', 'Fruit'], + ['Sweet potato', 'Vegetable'], + ['Tomato', 'Fruit'], + ['Turnip', 'Vegetable'], + ['Ugli fruit', 'Fruit'], + ['Victoria plum', 'Fruit'], + ['Watercress', 'Vegetable'], + ['Watermelon', 'Fruit'], + ['Yam', 'Vegetable'], + ['Zucchini', 'Vegetable'] +]; + +function searchVeggies (searchString) { + var results = []; + + for (var i = 0; i < FRUITS_AND_VEGGIES.length; i++) { + var veggie = FRUITS_AND_VEGGIES[i][0].toLowerCase(); + if (veggie.indexOf(searchString.toLowerCase()) === 0) { + results.push(FRUITS_AND_VEGGIES[i]); + } + } + + return results; +} + +/** + * @function onload + * @desc Initialize the combobox examples once the page has loaded + */ +window.addEventListener('load', function () { + var ex1Combobox = new aria.GridCombobox( + document.getElementById('ex1-input'), + document.getElementById('ex1-grid'), + searchVeggies + ); + +}); diff --git a/examples/combobox/js/grid-combobox.js b/examples/combobox/js/grid-combobox.js new file mode 100644 index 0000000000..7df5aaa7f2 --- /dev/null +++ b/examples/combobox/js/grid-combobox.js @@ -0,0 +1,312 @@ +/* +* This content is licensed according to the W3C Software License at +* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document +*/ + +/** + * @constructor + * + * @desc + * Combobox object representing the state and interactions for a combobox + * widget + * + * @param comboboxNode + * The DOM node pointing to the combobox + * @param input + * The input node + * @param grid + * The grid node to load results in + * @param searchFn + * The search function. The function accepts a search string and returns an + * array of results. + */ +aria.GridCombobox = function ( + input, + grid, + searchFn +) { + this.input = input; + this.grid = grid; + this.searchFn = searchFn; + this.activeRowIndex = -1; + this.activeColIndex = 0; + this.rowsCount = 0; + this.colsCount = 0; + this.gridFocused = false; + this.shown = false; + this.selectionCol = 0; + + this.setupEvents(); +}; + +aria.GridCombobox.prototype.setupEvents = function () { + document.body.addEventListener('click', this.handleBodyClick.bind(this)); + this.input.addEventListener('keyup', this.handleInputKeyUp.bind(this)); + this.input.addEventListener('keydown', this.handleInputKeyDown.bind(this)); + this.input.addEventListener('focus', this.handleInputFocus.bind(this)); + this.grid.addEventListener('click', this.handleGridClick.bind(this)); +}; + +aria.GridCombobox.prototype.handleBodyClick = function (evt) { + if (evt.target === this.input || this.grid.contains(evt.target)) { + return; + } + this.hideResults(); +}; + +aria.GridCombobox.prototype.handleInputKeyUp = function (evt) { + var key = evt.which || evt.keyCode; + + switch (key) { + case aria.KeyCode.UP: + case aria.KeyCode.DOWN: + case aria.KeyCode.ESC: + case aria.KeyCode.RETURN: + evt.preventDefault(); + return; + case aria.KeyCode.LEFT: + case aria.KeyCode.RIGHT: + if (this.gridFocused) { + console.log('grid focused'); + evt.preventDefault(); + return; + } + default: + this.updateResults(); + } +}; + + +aria.GridCombobox.prototype.handleInputKeyDown = function (evt) { + var key = evt.which || evt.keyCode; + var activeRowIndex = this.activeRowIndex; + var activeColIndex = this.activeColIndex; + + if (key === aria.KeyCode.ESC) { + if (this.gridFocused) { + this.gridFocused = false; + this.removeFocusCell(this.activeRowIndex, this.activeColIndex); + this.activeRowIndex = -1; + this.activeColIndex = 0; + this.input.setAttribute( + 'aria-activedescendant', + '' + ); + } + else { + this.hideResults(); + setTimeout((function () { + // On Firefox, input does not get cleared here unless wrapped in + // a setTimeout + this.input.value = ''; + }).bind(this), 1); + } + return; + } + + if (this.rowsCount < 1) { + return; + } + + var prevActive = this.getItemAt(activeRowIndex, this.selectionCol); + var activeItem; + + switch (key) { + case aria.KeyCode.UP: + this.gridFocused = true; + activeRowIndex = this.getRowIndex(key); + evt.preventDefault(); + break; + case aria.KeyCode.DOWN: + this.gridFocused = true; + activeRowIndex = this.getRowIndex(key); + evt.preventDefault(); + break; + case aria.KeyCode.LEFT: + if (activeColIndex <= 0) { + activeColIndex = this.colsCount - 1; + activeRowIndex = this.getRowIndex(key); + } + else { + activeColIndex--; + } + if (this.gridFocused) { + evt.preventDefault(); + } + break; + case aria.KeyCode.RIGHT: + if (activeColIndex === -1 || activeColIndex >= this.colsCount - 1) { + activeColIndex = 0; + activeRowIndex = this.getRowIndex(key); + } + else { + activeColIndex++; + } + if (this.gridFocused) { + evt.preventDefault(); + } + break; + case aria.KeyCode.RETURN: + activeItem = this.getItemAt(activeRowIndex, this.selectionCol); + this.selectItem(activeItem); + this.gridFocused = false; + return; + case aria.KeyCode.TAB: + this.hideResults(); + return; + default: + return; + } + + if (prevActive) { + this.removeFocusCell(this.activeRowIndex, this.activeColIndex); + prevActive.setAttribute('aria-selected', 'false'); + } + + activeItem = this.getItemAt(activeRowIndex, activeColIndex); + this.activeRowIndex = activeRowIndex; + this.activeColIndex = activeColIndex; + + if (activeItem) { + this.input.setAttribute( + 'aria-activedescendant', + 'result-item-' + activeRowIndex + 'x' + activeColIndex + ); + this.focusCell(activeRowIndex, activeColIndex); + var selectedItem = this.getItemAt(activeRowIndex, this.selectionCol); + selectedItem.setAttribute('aria-selected', 'true'); + } + else { + this.input.setAttribute( + 'aria-activedescendant', + '' + ); + } +}; + +aria.GridCombobox.prototype.handleInputFocus = function (evt) { + this.updateResults(); +}; + +aria.GridCombobox.prototype.handleGridClick = function (evt) { + if (!evt.target) { + return; + } + + var row; + if (evt.target.getAttribute('role') === 'row') { + row = evt.target; + } + else if (evt.target.getAttribute('role') === 'gridcell') { + row = evt.target.parentNode; + } + else { + return; + } + + var selectItem = row.querySelector('.result-cell'); + this.selectItem(selectItem); +}; + +aria.GridCombobox.prototype.updateResults = function () { + var searchString = this.input.value; + var results = this.searchFn(searchString); + + this.hideResults(); + + if (!searchString) { + results = []; + } + + if (results.length) { + for (var row = 0; row < results.length; row++) { + var resultRow = document.createElement('div'); + resultRow.className = 'result-row'; + resultRow.setAttribute('role', 'row'); + resultRow.setAttribute('id', 'result-row-' + row); + for (var col = 0; col < results[row].length; col++) { + var resultCell = document.createElement('div'); + resultCell.className = 'result-cell'; + resultCell.setAttribute('role', 'gridcell'); + resultCell.setAttribute('id', 'result-item-' + row + 'x' + col); + resultCell.innerText = results[row][col]; + resultRow.appendChild(resultCell); + } + this.grid.appendChild(resultRow); + } + aria.Utils.removeClass(this.grid, 'hidden'); + this.input.setAttribute('aria-expanded', 'true'); + this.rowsCount = results.length; + this.colsCount = results.length ? results[0].length : 0; + this.shown = true; + } +}; + +aria.GridCombobox.prototype.getRowIndex = function (key) { + var activeRowIndex = this.activeRowIndex; + + switch (key) { + case aria.KeyCode.UP: + case aria.KeyCode.LEFT: + if (activeRowIndex <= 0) { + activeRowIndex = this.rowsCount - 1; + } + else { + activeRowIndex--; + } + break; + case aria.KeyCode.DOWN: + case aria.KeyCode.RIGHT: + if (activeRowIndex === -1 || activeRowIndex >= this.rowsCount - 1) { + activeRowIndex = 0; + } + else { + activeRowIndex++; + } + } + + return activeRowIndex; +}; + + +aria.GridCombobox.prototype.getItemAt = function (rowIndex, colIndex) { + return document.getElementById('result-item-' + rowIndex + 'x' + colIndex); +}; + + +aria.GridCombobox.prototype.selectItem = function (item) { + if (item) { + this.input.value = item.innerText; + this.hideResults(); + } +}; + +aria.GridCombobox.prototype.hideResults = function () { + this.gridFocused = false; + this.shown = false; + this.activeRowIndex = -1; + this.activeColIndex = 0; + this.grid.innerHTML = ''; + aria.Utils.addClass(this.grid, 'hidden'); + this.input.setAttribute('aria-expanded', 'false'); + this.rowsCount = 0; + this.colsCount = 0; + this.input.setAttribute( + 'aria-activedescendant', + '' + ); +}; + +aria.GridCombobox.prototype.removeFocusCell = function (rowIndex, colIndex) { + var row = document.getElementById('result-row-' + rowIndex); + aria.Utils.removeClass(row, 'focused'); + var cell = this.getItemAt(rowIndex, colIndex); + aria.Utils.removeClass(cell, 'focused-cell'); +}; + +aria.GridCombobox.prototype.focusCell = function (rowIndex, colIndex) { + var row = document.getElementById('result-row-' + rowIndex); + aria.Utils.addClass(row, 'focused'); + var cell = this.getItemAt(rowIndex, colIndex); + aria.Utils.addClass(cell, 'focused-cell'); +}; diff --git a/test/tests/combobox_grid-combo-12.js b/test/tests/combobox_grid-combo-12.js new file mode 100644 index 0000000000..9bd85e6730 --- /dev/null +++ b/test/tests/combobox_grid-combo-12.js @@ -0,0 +1,762 @@ +'use strict'; + +const { ariaTest } = require('..'); +const { By, Key } = require('selenium-webdriver'); +const assertAriaLabelledby = require('../util/assertAriaLabelledby'); +const assertAttributeValues = require('../util/assertAttributeValues'); +const assertAttributeDNE = require('../util/assertAttributeDNE'); +const assertAriaRoles = require('../util/assertAriaRoles'); + +const exampleFile = 'combobox/grid-combo.html'; + +const ex = { + labelSelector: '#ex1 label', + textboxSelector: '#ex1 input[type="text"]', + gridSelector: '#ex1 [role="grid"]', + rowSelector: '#ex1 [role="row"]', + gridcellSelector: '#ex1 [role="gridcell"]', + gridcellFocusedClass: 'focused-cell', + numAOptions: 3 +}; + +const waitForFocusChange = async (t, textboxSelector, originalFocus) => { + await t.context.session.wait( + async function () { + let newfocus = await t.context.session + .findElement(By.css(textboxSelector)) + .getAttribute('aria-activedescendant'); + return newfocus != originalFocus; + }, + t.context.waitTime, + 'Timeout waiting for "aria-activedescendant" value to change from "' + originalFocus + '". ' + ); +}; + +const confirmCursorIndex = async (t, selector, cursorIndex) => { + return t.context.session.executeScript(function () { + const [selector, cursorIndex] = arguments; + let item = document.querySelector(selector); + return item.selectionStart === cursorIndex; + }, selector, cursorIndex); +}; + +const gridcellId = (row, column) => { + return 'result-item-' + row + 'x' + column; +}; + +// Attributes +ariaTest('Test for role="combobox"', exampleFile, 'textbox-role', async (t) => { + t.plan(1); + await assertAriaRoles(t, 'ex1', 'combobox', '1', 'input[type=text]'); +}); + +ariaTest('"aria-haspopup"=grid on textbox element', exampleFile, 'textbox-aria-haspopup', async (t) => { + t.plan(1); + await assertAttributeValues(t, ex.textboxSelector, 'aria-haspopup', 'grid'); +}); + +ariaTest('"aria-expanded" on textbox element', exampleFile, 'textbox-aria-expanded', async (t) => { + t.plan(4); + + const textbox = await t.context.session.findElement(By.css(ex.textboxSelector)); + + // Check that aria-expanded is false and the grid is not visible before interacting + + t.is( + await textbox.getAttribute('aria-expanded'), + 'false', + 'textbox element should have attribute "aria-expanded" set to false by default.' + ); + + const popupId = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-controls'); + + const popupElement = await t.context.session + .findElement(By.id('ex1')) + .findElement(By.id(popupId)); + + t.false( + await popupElement.isDisplayed(), + 'Popup element should not be displayed when \'aria-expanded\' is false\'' + ); + + // Send key "a" to textbox + + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a'); + + // Check that aria-expanded is true and the grid is visible + + t.is( + await textbox.getAttribute('aria-expanded'), + 'true', + 'textbox element should have attribute "aria-expand" set to true after typing.' + ); + + t.true( + await popupElement.isDisplayed(), + 'Popup element should be displayed when \'aria-expanded\' is true\'' + ); +}); + +ariaTest('"id" attribute on texbox used to discover accessible name', exampleFile, 'textbox-id', async (t) => { + t.plan(2); + + const labelForTextboxId = await t.context.session + .findElement(By.css(ex.labelSelector)) + .getAttribute('for'); + + t.truthy( + labelForTextboxId, + '"for" attribute with id value should exist on label: ' + ex.labelSelector + ); + + const textboxElementId = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('id'); + + t.true( + labelForTextboxId === textboxElementId, + 'Id on textbox element (' + ex.textboxSelector + ') should match the "for" attribute of the label (' + labelForTextboxId + ')' + ); +}); + +ariaTest('"aria-autocomplete" on grid element', exampleFile, 'textbox-aria-autocomplete', async (t) => { + t.plan(1); + await assertAttributeValues(t, ex.textboxSelector, 'aria-autocomplete', 'list'); +}); + +ariaTest('"aria-controls" attribute on grid element', exampleFile, 'textbox-aria-controls', async (t) => { + t.plan(2); + + const popupId = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-controls'); + + t.truthy( + popupId, + '"aria-controls" attribute should exist on: ' + ex.textboxSelector + ); + + const popupElements = await t.context.session + .findElement(By.id('ex1')) + .findElements(By.id(popupId)); + + t.is( + popupElements.length, + 1, + 'There should be a element with id "' + popupId + '" as referenced by the aria-controls attribute' + ); +}); + +ariaTest('"aria-activedescendant" on textbox element', exampleFile, 'textbox-aria-activedescendant', async (t) => { + t.plan(1); + await assertAttributeValues(t, ex.textboxSelector, 'aria-activedescendant', null); +}); + +ariaTest('role "grid" on div element', exampleFile, 'grid-role', async (t) => { + t.plan(1); + await assertAriaRoles(t, 'ex1', 'grid', '1', 'div'); +}); + +ariaTest('"aria-labelledby" attribute on grid element', exampleFile, 'grid-aria-labelledby', async (t) => { + t.plan(1); + await assertAriaLabelledby(t, ex.gridSelector); +}); + +ariaTest('role "row" exists within grid element', exampleFile, 'row-role', async (t) => { + t.plan(1); + + // Send key "a" then arrow down to reveal all options + await t.context.session.findElement(By.css(ex.textboxSelector)).sendKeys('a', Key.ARROW_DOWN); + + let rowElements = await t.context.session.findElement(By.css(ex.gridSelector)) + .findElements(By.css('[role="row"]')); + + t.truthy( + await rowElements.length, + 'role="row" elements should be found within a gridcell element after opening popup' + ); +}); + +// This test fails due to bug: https://github.com/w3c/aria-practices/issues/859 +ariaTest.failing('"aria-selected" attribute on row element', exampleFile, 'row-aria-selected', async (t) => { + t.plan(2); + + // Send key "a" + await t.context.session.findElement(By.css(ex.textboxSelector)).sendKeys('a'); + await assertAttributeDNE(t, ex.rowSelector + ':nth-of-type(1)', 'aria-selected'); + + // Send key ARROW_DOWN to selected first option + await t.context.session.findElement(By.css(ex.textboxSelector)).sendKeys(Key.ARROW_DOWN); + await assertAttributeValues(t, ex.rowSelector + ':nth-of-type(1)', 'aria-selected', 'true'); +}); + +ariaTest('role "gridcell" exists within row element', exampleFile, 'gridcell-role', async (t) => { + t.plan(1); + + // Send key "a" then arrow down to reveal all options + await t.context.session.findElement(By.css(ex.textboxSelector)).sendKeys('a', Key.ARROW_DOWN); + + let rowElements = await t.context.session.findElement(By.css(ex.rowSelector)) + .findElements(By.css('[role="gridcell"]')); + + t.truthy( + await rowElements.length, + 'role="gridcell" elements should be found within a row element after opening popup' + ); +}); + + +// Keys + +ariaTest('Test down key press with focus on textbox', + exampleFile, 'textbox-key-down-arrow', async (t) => { + + t.plan(4); + + // Send ARROW_DOWN to the textbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ARROW_DOWN); + + // Check that the grid is displayed + t.false( + await t.context.session.findElement(By.css(ex.gridSelector)).isDisplayed(), + 'In example ex3 grid should not be display after ARROW_DOWN keypress while textbox is empty' + ); + + // Send "a" then ARROW_DOWN to the textbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_DOWN); + + // Account for race condition + await waitForFocusChange(t, ex.textboxSelector, ''); + + // Check that the grid is displayed + t.true( + await t.context.session.findElement(By.css(ex.gridSelector)).isDisplayed(), + 'In example ex3 grid should display after ARROW_DOWN keypress when textbox has character values' + ); + + // Check that the active descendent focus is correct + let focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + + t.is( + focusedId, + gridcellId(0,0), + 'After down arrow sent to textbox, aria-activedescendant should be set to the first gridcell element: ' + gridcellId(0,0) + ); + + let focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(0,0))) + .getAttribute('class'); + + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(0,0) + '" should have visual focus' + ); + + }); + +ariaTest('Test down key press with focus on list', + exampleFile, 'popup-key-down-arrow', async (t) => { + + t.plan(6); + + // Send 'a' to text box, then send ARROW_DOWN to textbox to set focus on grid + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_DOWN); + + // Test that ARROW_DOWN moves active descendant focus on item in grid + for (let i = 1; i < ex.numAOptions; i++) { + let oldfocus = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ARROW_DOWN); + + // Account for race condition + await waitForFocusChange(t, ex.textboxSelector, oldfocus); + + // Check that the active descendent focus is correct + + let focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(i,0), + 'After down up sent to textbox, aria-activedescendant should be set to this gridcell element: ' + gridcellId(i,0) + ); + + let focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(i,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(i,0) + '" should have visual focus' + ); + } + + // Sending ARROW_DOWN to the last item should put focus on the first + let oldfocus = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ARROW_DOWN); + + // Account for race condition + await waitForFocusChange(t, ex.textboxSelector, oldfocus); + + // Focus should be on the first item + + let focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(0,0), + 'After down arrow sent to last grid row, aria-activedescendant should be set to the first gridcell element: ' + gridcellId(0,0) + ); + + let focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(0,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(0,0) + '" should have visual focus' + ); + + }); + + +ariaTest('Test up key press with focus on textbox', + exampleFile, 'textbox-key-up-arrow', async (t) => { + + t.plan(4); + + // Send ARROW_UP to the textbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ARROW_UP); + + // Check that the grid is displayed + t.false( + await t.context.session.findElement(By.css(ex.gridSelector)).isDisplayed(), + 'In example ex3 grid should not be display after ARROW_UP keypress while textbox is empty' + ); + + // Send "a" then ARROW_UP to the textbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_UP); + + // Account for race condition + await waitForFocusChange(t, ex.textboxSelector, ''); + + // Check that the grid is displayed + t.true( + await t.context.session.findElement(By.css(ex.gridSelector)).isDisplayed(), + 'In example ex3 grid should display after ARROW_UP keypress when textbox has character values' + ); + + // Check that the active descendent focus is correct + let focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + + t.is( + focusedId, + gridcellId(ex.numAOptions - 1,0), + 'After up arrow sent to textbox, aria-activedescendant should be set to the last row first gridcell element: ' + gridcellId(ex.numAOptions - 1,0) + ); + + let focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(ex.numAOptions - 1,0))) + .getAttribute('class'); + + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(ex.numAOptions - 1,0) + '" should have visual focus' + ); + + }); + +ariaTest('Test up key press with focus on grid', + exampleFile, 'popup-key-up-arrow', async (t) => { + + t.plan(6); + + // Send 'a' to text box, then send ARROW_UP to textbox to textbox to put focus in textbox + // Up arrow should move selection to the last item in the list + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_UP); + + // Test that ARROW_UP moves active descendant focus up one item in the grid + for (let index = ex.numAOptions - 2; index >= 0 ; index--) { + let oldfocus = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + + // Send Key + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ARROW_UP); + + await waitForFocusChange(t, ex.textboxSelector, oldfocus); + + // Check that the active descendent focus is correct + + let focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(index,0), + 'After up arrow sent to textbox, aria-activedescendant should be set to gridcell element: ' + gridcellId(index,0) + ); + + let focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(index,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(index,0) + '" should have visual focus' + ); + } + + // Test that ARROW_UP, when on the first item, returns focus to the last item in the list + let oldfocus = await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + + // Send Key + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ARROW_UP); + + await waitForFocusChange(t, ex.textboxSelector, oldfocus); + + // Check that the active descendent focus is correct + + let focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(ex.numAOptions - 1,0), + 'After up arrow sent to first element in popup, aria-activedescendant should be set to the last row first gridcell element: ' + gridcellId(ex.numAOptions - 1,0) + ); + + let focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(ex.numAOptions - 1,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(ex.numAOptions - 1,0) + '" should have visual focus' + ); + + }); + +ariaTest('Test enter key press with focus on grid', + exampleFile, 'popup-key-enter', async (t) => { + + t.plan(2); + + // Send key "a" to the textbox, then key ARROW_DOWN to select the first item + + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_DOWN); + + // Get the value of the first option in the grid + + const firstOption = await t.context.session.findElement(By.css(ex.gridcellSelector)).getText(); + + // Send key ENTER + + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ENTER); + + // Confirm that the grid is closed + + await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false'); + + // Confirm that the value of the textbox is now set to the first option + + t.is( + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('value'), + firstOption, + 'key press "ENTER" should result in first option in textbox' + ); + + }); + +ariaTest('Test escape key press with focus on textbox', + exampleFile, 'textbox-key-escape', async (t) => { + t.plan(2); + + // Send key "a", then key ESCAPE to the textbox + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ESCAPE); + + // Wait for gridbox to close + await t.context.session.wait( + async function () { + return !(await t.context.session.findElement(By.css(ex.gridSelector)).isDisplayed()); + }, + t.context.waitTime, + 'Timeout waiting for gridbox to close afer escape' + ); + + // Confirm the grid is closed and the textboxed is cleared + await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false'); + t.is( + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('value'), + '', + 'In key press "ESCAPE" should result in clearing of the textbox' + ); + + }); + +// This test fails due to bug: https://github.com/w3c/aria-practices/issues/860 +ariaTest.failing('Test escape key press with focus on popup', + exampleFile, 'popup-key-escape', async (t) => { + t.plan(2); + + // Send key "a" then key "ARROW_DOWN to put the focus on the grid, + // then key ESCAPE to the textbox + + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys('a', Key.ARROW_DOWN); + + await waitForFocusChange(t, ex.textboxSelector, ''); + + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .sendKeys(Key.ESCAPE); + + // Wait for gridbox to close + await t.context.session.wait( + async function () { + return !(await t.context.session.findElement(By.css(ex.gridSelector)).isDisplayed()); + }, + t.context.waitTime, + 'Timeout waiting for gridbox to close afer escape' + ); + + // Confirm the grid is closed and the textboxed is cleared + await assertAttributeValues(t, ex.textboxSelector, 'aria-expanded', 'false'); + + t.is( + await t.context.session + .findElement(By.css(ex.textboxSelector)) + .getAttribute('value'), + '', + 'In grid key press "ESCAPE" should result in clearing of the textbox' + ); + + }); + +ariaTest('left arrow from focus on list puts focus on grid and moves cursor right', + exampleFile, 'popup-key-left-arrow', async (t) => { + t.plan(4); + + // Send key "a" then key "ARROW_DOWN" to put the focus on the grid + const textbox = t.context.session.findElement(By.css(ex.textboxSelector)); + await textbox.sendKeys('a', Key.ARROW_DOWN); + + // Send key "ARROW_LEFT" + await textbox.sendKeys(Key.ARROW_LEFT); + + // Check that the active descendent focus is correct + let lastrow = ex.numAOptions - 1; + + var focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(lastrow,1), + 'After left arrow sent to pop-up, aria-activedescendant should be set to the last row, last gricell: ' + gridcellId(lastrow, 1) + ); + + var focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(lastrow,1))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(lastrow,1) + '" should have visual focus' + ); + + // Send key "ARROW_LEFT" a second time + await textbox.sendKeys(Key.ARROW_LEFT); + + // Check that the active descendent focus is correct + focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(lastrow,0), + 'After left arrow sent twice to popup, aria-activedescendant should be set to the last row first gridcell: ' + gridcellId(lastrow, 0) + ); + + focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(lastrow,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(lastrow,0) + '" should have visual focus' + ); + + }); + + +ariaTest('Right arrow from focus on list puts focus on grid', + exampleFile, 'popup-key-right-arrow', async (t) => { + t.plan(6); + + // Send key "a" then key "ARROW_DOWN" to put the focus on the grid + const textbox = t.context.session.findElement(By.css(ex.textboxSelector)); + await textbox.sendKeys('a', Key.ARROW_DOWN); + + // Send key "RIGHT_ARROW" + await textbox.sendKeys(Key.ARROW_RIGHT); + + // Check that the active descendent focus is correct + var focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(0,1), + 'After right arrow sent to pop-up, aria-activedescendant should be set to the first row second gridcell element: ' + gridcellId(0, 1) + ); + + var focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(0,1))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(0,1) + '" should have visual focus' + ); + + // Send key "ARROW_RIGHT" a second time + await textbox.sendKeys(Key.ARROW_RIGHT); + + // Check that the active descendent focus is correct + focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(1,0), + 'After right arrow send twice to popup, aria-activedescendant should be set to the second row first gridcell element: ' + gridcellId(1, 0) + ); + + focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(1,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(1,0) + '" should have visual focus' + ); + + // Send key "ARROW_RIGHT" four more times + await textbox.sendKeys(Key.ARROW_RIGHT, Key.ARROW_RIGHT, Key.ARROW_RIGHT, Key.ARROW_RIGHT); + + // Check that the active descendent focus is correct + focusedId = await t.context.session.findElement(By.css(ex.textboxSelector)) + .getAttribute('aria-activedescendant'); + t.is( + focusedId, + gridcellId(0,0), + 'After right arrow to the popup 6 times in total, aria-activedescendant should be back on the first row, first gridcell: ' + gridcellId(0, 0) + ); + + focusedElementClasses = await t.context.session.findElement(By.id(gridcellId(0,0))) + .getAttribute('class'); + t.true( + focusedElementClasses.includes(ex.gridcellFocusedClass), + 'Gridcell with id "' + gridcellId(0,0) + '" should have visual focus' + ); + + }); + +ariaTest('Home from focus on list puts focus on grid and moves cursor', + exampleFile, 'popup-key-home', async (t) => { + t.plan(2); + + // Send key "a" then key "ARROW_DOWN" to put the focus on the grid + const textbox = t.context.session.findElement(By.css(ex.textboxSelector)); + await textbox.sendKeys('a', Key.ARROW_DOWN); + + // Send key "ARROW_HOME" + await textbox.sendKeys(Key.HOME); + + t.true( + await confirmCursorIndex(t, ex.textboxSelector, 0), + 'Cursor should be at index 0 after one ARROW_HOME key' + ); + + t.is( + await textbox.getAttribute('aria-activedescendant'), + '', + 'Focus should be on the textbox after one ARROW_HOME key', + ); + }); + +ariaTest('End from focus on list puts focus on grid', + exampleFile, 'popup-key-end', async (t) => { + t.plan(2); + + // Send key "a" then key "ARROW_DOWN" to put the focus on the grid + const textbox = t.context.session.findElement(By.css(ex.textboxSelector)); + await textbox.sendKeys('a', Key.ARROW_DOWN); + + // Send key "END_ARROW" + await textbox.sendKeys(Key.END); + + t.true( + await confirmCursorIndex(t, ex.textboxSelector, 1), + 'Cursor should be at index 1 after one ARROW_END key' + ); + + t.is( + await textbox.getAttribute('aria-activedescendant'), + '', + 'Focus should be on the textbox after on ARROW_END key', + ); + }); + +ariaTest('Sending character keys while focus is on grid moves focus', + exampleFile, 'popup-key-char', async (t) => { + t.plan(2); + + // Send key "ARROW_DOWN" to put the focus on the grid + const textbox = t.context.session.findElement(By.css(ex.textboxSelector)); + await textbox.sendKeys(Key.ARROW_DOWN); + + // Send key "a" + await textbox.sendKeys('a'); + + t.is( + await textbox.getAttribute('value'), + 'a', + 'Value of the textbox should be "a" after sending key "a" to the textbox while the focus ' + + 'is on the grid' + ); + + t.is( + await textbox.getAttribute('aria-activedescendant'), + '', + 'Focus should be on the textbox after sending a character key while the focus is on the grid', + ); + + }); + +ariaTest.failing('Expected behavior for all other standard single line editing keys', + exampleFile, 'standard-single-line-editing-keys', async (t) => { + t.plan(1); + t.fail(); + }); + From 105650ba766beca07ec1175711ff06714555a69c Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 7 Nov 2019 10:20:54 -0600 Subject: [PATCH 2/3] updated file name to make testing easier --- examples/combobox/{grid-combo.html => grid-combobox.html} | 2 +- test/tests/checkbox_checkbox-2.js | 2 ++ test/tests/combobox_grid-combo-12.js | 7 ++++--- 3 files changed, 7 insertions(+), 4 deletions(-) rename examples/combobox/{grid-combo.html => grid-combobox.html} (99%) diff --git a/examples/combobox/grid-combo.html b/examples/combobox/grid-combobox.html similarity index 99% rename from examples/combobox/grid-combo.html rename to examples/combobox/grid-combobox.html index eec8b2e0b2..d16b682b36 100644 --- a/examples/combobox/grid-combo.html +++ b/examples/combobox/grid-combobox.html @@ -56,7 +56,7 @@

Example

{ t.plan(5); @@ -227,3 +228,4 @@ ariaTest('key SPACE selects or unselects checkbox', exampleFile, 'key-space', as 'After sending SPACE to the checkbox in a uncheck state, 1 condiments should be selected via: ' + ex.checkedCondsSelector ); }); +*/ diff --git a/test/tests/combobox_grid-combo-12.js b/test/tests/combobox_grid-combo-12.js index 9bd85e6730..4063a8e0e6 100644 --- a/test/tests/combobox_grid-combo-12.js +++ b/test/tests/combobox_grid-combo-12.js @@ -7,7 +7,7 @@ const assertAttributeValues = require('../util/assertAttributeValues'); const assertAttributeDNE = require('../util/assertAttributeDNE'); const assertAriaRoles = require('../util/assertAriaRoles'); -const exampleFile = 'combobox/grid-combo.html'; +const exampleFile = 'combobox/grid-combobox.html'; const ex = { labelSelector: '#ex1 label', @@ -47,9 +47,9 @@ const gridcellId = (row, column) => { // Attributes ariaTest('Test for role="combobox"', exampleFile, 'textbox-role', async (t) => { t.plan(1); - await assertAriaRoles(t, 'ex1', 'combobox', '1', 'input[type=text]'); + await assertAriaRoles(t, 'ex1', 'combobox', '1', 'input'); }); - +/* ariaTest('"aria-haspopup"=grid on textbox element', exampleFile, 'textbox-aria-haspopup', async (t) => { t.plan(1); await assertAttributeValues(t, ex.textboxSelector, 'aria-haspopup', 'grid'); @@ -760,3 +760,4 @@ ariaTest.failing('Expected behavior for all other standard single line editing k t.fail(); }); +*/ From e2602e66147616b9d488cd0c3aa328c3835c0c8f Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 7 Nov 2019 10:26:20 -0600 Subject: [PATCH 3/3] updated regression test file --- test/tests/combobox_grid-combo-12.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/tests/combobox_grid-combo-12.js b/test/tests/combobox_grid-combo-12.js index 4063a8e0e6..061ade5b39 100644 --- a/test/tests/combobox_grid-combo-12.js +++ b/test/tests/combobox_grid-combo-12.js @@ -49,7 +49,7 @@ ariaTest('Test for role="combobox"', exampleFile, 'textbox-role', async (t) => { t.plan(1); await assertAriaRoles(t, 'ex1', 'combobox', '1', 'input'); }); -/* + ariaTest('"aria-haspopup"=grid on textbox element', exampleFile, 'textbox-aria-haspopup', async (t) => { t.plan(1); await assertAttributeValues(t, ex.textboxSelector, 'aria-haspopup', 'grid'); @@ -760,4 +760,3 @@ ariaTest.failing('Expected behavior for all other standard single line editing k t.fail(); }); -*/