Skip to content

Commit

Permalink
TreeView: fix axe accessibility issues (#25860)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zedwag authored Oct 24, 2023
1 parent 64ed08d commit 12ce7fc
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,17 @@ const HierarchicalCollectionWidget = CollectionWidget.inherit({
},

_getIconContainer: function(itemData) {
return itemData.icon ? getImageContainer(itemData.icon) : undefined;
if(!itemData.icon) {
return undefined;
}

const $imageContainer = getImageContainer(itemData.icon);

if($imageContainer.is('img')) {
$imageContainer.attr('alt', itemData.text ?? `${this.NAME} item icon`);
}

return $imageContainer;
},

_getTextContainer: function(itemData) {
Expand Down
2 changes: 2 additions & 0 deletions packages/devextreme/js/ui/tree_view/ui.tree_view.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,8 @@ const TreeViewBase = HierarchicalCollectionWidget.inherit({
direction: this.option('scrollDirection'),
useKeyboard: false
});

this.setAria('role', 'treeitem', this._scrollable.$element());
},

_renderNodeContainer: function($parent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ QUnit.testStart(() => {

const DX_CONTEXT_MENU_CLASS = 'dx-context-menu';
const DX_MENU_ITEM_CLASS = 'dx-menu-item';
const DX_ICON_CLASS = 'dx-icon';
const DX_MENU_ITEM_CONTENT_CLASS = 'dx-menu-item-content';
const DX_MENU_PHONE_CLASS = 'dx-menu-phone-overlay';
const DX_MENU_ITEM_SELECTED_CLASS = 'dx-menu-item-selected';
Expand Down Expand Up @@ -255,6 +256,26 @@ QUnit.module('Rendering', moduleConfig, () => {

assert.notOk(instance._keyboardListenerId);
});

QUnit.test('ContextMenu icon image should have alt attribute with item text if it specified', function(assert) {
const instance = new ContextMenu(this.$element, {
items: [{ text: 'Item text', icon: 'some_icon.jpg' }],
visible: true,
});
const $icon = $(instance.itemsContainer()).find(`.${DX_MENU_ITEM_CLASS} .${DX_ICON_CLASS}`);

assert.strictEqual($icon.attr('alt'), 'Item text');
});

QUnit.test('ContextMenu icon image should have alt attribute with "dxContextMenu item icon" if item text is not specified', function(assert) {
const instance = new ContextMenu(this.$element, {
items: [{ icon: 'some_icon.jpg' }],
visible: true,
});
const $icon = instance.itemsContainer().find(`.${DX_MENU_ITEM_CLASS} .${DX_ICON_CLASS}`);

assert.strictEqual($icon.attr('alt'), 'dxContextMenu item icon');
});
});

QUnit.module('Showing and hiding context menu', moduleConfig, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ QUnit.testStart(() => {
});

const DX_MENU_CLASS = 'dx-menu';
const MENU_ITEM_CLASS = 'dx-menu-item';
const ICON_CLASS = 'dx-icon';
const DX_MENU_ITEM_CLASS = DX_MENU_CLASS + '-item';
const DX_MENU_ITEM_SELECTED_CLASS = 'dx-menu-item-selected';
const DX_MENU_HORIZONTAL = 'dx-menu-horizontal';
Expand Down Expand Up @@ -72,6 +74,26 @@ QUnit.module('Menu rendering', {
assert.ok(menu);
assert.equal(root.length, 0, 'no root');
});

QUnit.test('Menu icon image should have alt attribute with item text if it specified', function(assert) {
const menu = createMenu({
items: [{ text: 'Item text', icon: 'some_icon.jpg' }]
});

const $icon = menu.element.find(`.${MENU_ITEM_CLASS} .${ICON_CLASS}`);

assert.strictEqual($icon.attr('alt'), 'Item text');
});

QUnit.test('Menu icon image should have alt attribute with "dxMenu item icon" if item text is not specified', function(assert) {
const menu = createMenu({
items: [{ icon: 'some_icon.jpg' }]
});

const $icon = menu.element.find(`.${MENU_ITEM_CLASS} .${ICON_CLASS}`);

assert.strictEqual($icon.attr('alt'), 'dxMenu item icon');
});
});

QUnit.module('Menu - selection', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ QUnit.testStart(function() {
import 'ui/tree_view';

const WIDGET_CLASS = 'dx-treeview';
const SCROLLABLE_CLASS = 'dx-scrollable';
const NODE_CONTAINER_CLASS = 'dx-treeview-node-container';
const OPENED_NODE_CONTAINER_CLASS = 'dx-treeview-node-container-opened';
const NODE_CLASS = 'dx-treeview-node';
const ITEM_CLASS = 'dx-treeview-item';
const ICON_CLASS = 'dx-icon';
const SELECTED_STATE_CLASS = 'dx-state-selected';
const ITEM_WITH_CHECKBOX_CLASS = 'dx-treeview-item-with-checkbox';
const ITEM_WITHOUT_CHECKBOX_CLASS = 'dx-treeview-item-without-checkbox';
Expand Down Expand Up @@ -56,6 +58,12 @@ QUnit.module('aria accessibility', {
assert.equal(this.$element.attr('role'), 'tree', 'role is correct');
});

QUnit.test('scrollable should have role treeitem attribute', function(assert) {
const $scrollable = this.$element.find('.' + SCROLLABLE_CLASS);

assert.equal($scrollable.attr('role'), 'treeitem', 'role is correct');
});

QUnit.test('aria role for items', function(assert) {
const $node = this.$element.find('.' + NODE_CLASS);
assert.equal($node.attr('role'), 'treeitem', 'role is correct');
Expand Down Expand Up @@ -604,5 +612,23 @@ QUnit.module('markup', {

assert.ok($selectAll.hasClass('dx-checkbox-indeterminate'));
});

QUnit.test('TreeView icon image should have alt attribute with item text if it specified', function(assert) {
const $treeView = initTree({
items: [{ text: 'Item text', icon: 'some_icon.jpg' }]
});
const $icon = $treeView.find(`.${ITEM_CLASS} .${ICON_CLASS}`);

assert.strictEqual($icon.attr('alt'), 'Item text');
});

QUnit.test('TreeView icon image should have alt attribute with "dxTreeView item icon" if item text is not specified', function(assert) {
const $treeView = initTree({
items: [{ icon: 'some_icon.jpg' }]
});
const $icon = $treeView.find(`.${ITEM_CLASS} .${ICON_CLASS}`);

assert.strictEqual($icon.attr('alt'), 'dxTreeView item icon');
});
});

0 comments on commit 12ce7fc

Please sign in to comment.