From 656281a371f62268a95dba5f7f34b0d52387fa25 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 29 May 2026 10:07:53 -0300 Subject: [PATCH 1/6] PivotGrid A11y and KBN - The expand icons are not accessible via keyboard (KBN) --- .../grids/pivot_grid/area_item/m_area_item.ts | 2 + .../__internal/grids/pivot_grid/m_widget.ts | 11 +++ .../pivotGrid.markup.tests.js | 65 ++++++++++++++ .../pivotGrid.tests.js | 89 +++++++++++++++++++ 4 files changed, 167 insertions(+) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts b/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts index dbc68392969d..340579bfbfd9 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts @@ -198,6 +198,8 @@ abstract class AreaItem { span.classList.add(PIVOTGRID_EXPAND_CLASS); div.appendChild(span); td.appendChild(div); + td.setAttribute('aria-expanded', String(cell.expanded)); + td.setAttribute('tabindex', '0'); } cellText = this._getCellText(cell, encodeHtml); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index f4ab393f4a55..67b29cfeb96b 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -883,6 +883,16 @@ class PivotGrid extends Widget { }); } + _handleCellKeyDown(e) { + if (e.key === 'Enter' || e.key === ' ') { + const args = this._createEventArgs(e.currentTarget, e); + if (args.cell && isDefined(args.cell.expanded)) { + e.preventDefault(); + this._handleCellClick({ currentTarget: e.currentTarget, preventDefault: noop }); + } + } + } + _getNoDataText() { return this.option('texts.noData'); } @@ -1074,6 +1084,7 @@ class PivotGrid extends Widget { .toggleClass('dx-word-wrap', !!that.option('wordWrapEnabled')); eventsEngine.on($table, addNamespace(clickEventName, 'dxPivotGrid'), 'td', that._handleCellClick.bind(that)); + eventsEngine.on($table, addNamespace('keydown', 'dxPivotGrid'), 'td', that._handleCellKeyDown.bind(that)); return $table; } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index bd9ec652f5ad..9952e729a932 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -85,5 +85,70 @@ QUnit.module('PivotGrid markup tests', () => { clock.restore(); }); + const createExpandableDataSource = () => ({ + fields: [ + { dataField: 'region', area: 'row' }, + { dataField: 'city', area: 'row' }, + { dataField: 'year', area: 'column', expanded: true }, + { dataField: 'quarter', area: 'column' }, + { dataField: 'amount', area: 'data', summaryType: 'sum', dataType: 'number' } + ], + store: [ + { region: 'N', city: 'B', year: 2020, quarter: 'Q1', amount: 100 }, + { region: 'N', city: 'NY', year: 2020, quarter: 'Q2', amount: 200 }, + { region: 'S', city: 'M', year: 2021, quarter: 'Q1', amount: 300 } + ] + }); + + QUnit.test('Expandable td has aria-expanded reflecting expanded state', function(assert) { + const clock = sinon.useFakeTimers(); + try { + const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); + clock.tick(10); + + const $expandedTd = pivotGrid.$element().find('.dx-pivotgrid-expanded').first().closest('td'); + const $collapsedTd = pivotGrid.$element().find('.dx-pivotgrid-collapsed').first().closest('td'); + + assert.ok($expandedTd.length > 0, 'expanded td present'); + assert.ok($collapsedTd.length > 0, 'collapsed td present'); + assert.strictEqual($expandedTd.attr('aria-expanded'), 'true', 'expanded td has aria-expanded="true"'); + assert.strictEqual($collapsedTd.attr('aria-expanded'), 'false', 'collapsed td has aria-expanded="false"'); + } finally { + clock.restore(); + } + }); + + QUnit.test('Expandable td has tabindex="0"', function(assert) { + const clock = sinon.useFakeTimers(); + try { + const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); + clock.tick(10); + + const $expandedTd = pivotGrid.$element().find('.dx-pivotgrid-expanded').first().closest('td'); + const $collapsedTd = pivotGrid.$element().find('.dx-pivotgrid-collapsed').first().closest('td'); + + assert.strictEqual($expandedTd.attr('tabindex'), '0', 'expanded td is focusable'); + assert.strictEqual($collapsedTd.attr('tabindex'), '0', 'collapsed td is focusable'); + } finally { + clock.restore(); + } + }); + + QUnit.test('Non-expandable td has neither aria-expanded nor tabindex', function(assert) { + const clock = sinon.useFakeTimers(); + try { + const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); + clock.tick(10); + + const $nonExpandableTd = pivotGrid.$element().find('td:not([aria-expanded])').first(); + + assert.ok($nonExpandableTd.length > 0, 'non-expandable td exists'); + assert.strictEqual($nonExpandableTd.attr('aria-expanded'), undefined, 'no aria-expanded attribute'); + assert.strictEqual($nonExpandableTd.attr('tabindex'), undefined, 'no tabindex attribute'); + } finally { + clock.restore(); + } + }); + }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js index d3610a69ba07..ad9d101c0253 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js @@ -433,6 +433,95 @@ QUnit.module('dxPivotGrid', { assert.strictEqual(expandValueChangingArgs, undefined); }); + QUnit.test('expand column item by Enter keydown', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + } + }); + assert.ok(pivotGrid); + + const $collapsedTd = $('#pivotGrid').find('.dx-pivotgrid-collapsed').closest('td'); + assert.strictEqual($collapsedTd.length, 1); + + $collapsedTd.trigger($.Event('keydown', { key: 'Enter' })); + + this.clock.tick(10); + + assert.deepEqual(expandValueChangingArgs, { + area: 'column', + path: ['2012'], + expanded: true, + needExpandData: true + }); + }); + + QUnit.test('collapse column item by Space keydown', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + } + }); + assert.ok(pivotGrid); + + const $expandedTd = $('#pivotGrid').find('.dx-pivotgrid-expanded').closest('td'); + assert.strictEqual($expandedTd.length, 1); + + $expandedTd.trigger($.Event('keydown', { key: ' ' })); + + this.clock.tick(10); + + assert.deepEqual(expandValueChangingArgs, { + area: 'column', + path: ['2010'], + expanded: false + }); + }); + + QUnit.test('keydown with keys other than Enter and Space does not toggle expansion', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + } + }); + assert.ok(pivotGrid); + + const $collapsedTd = $('#pivotGrid').find('.dx-pivotgrid-collapsed').closest('td'); + assert.strictEqual($collapsedTd.length, 1); + + $collapsedTd.trigger($.Event('keydown', { key: 'Tab' })); + + this.clock.tick(10); + + assert.strictEqual(expandValueChangingArgs, undefined); + }); + + QUnit.test('keydown on a non-expandable td does not toggle expansion', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + } + }); + assert.ok(pivotGrid); + + const $nonExpandableTd = $('#pivotGrid').find('td:not([aria-expanded])').first(); + assert.ok($nonExpandableTd.length > 0); + + $nonExpandableTd.trigger($.Event('keydown', { key: 'Enter' })); + + this.clock.tick(10); + + assert.strictEqual(expandValueChangingArgs, undefined); + }); + QUnit.test('T248253. DataSource changed', function(assert) { let expandValueChangingArgs; const pivotGrid = createPivotGrid($.extend(this.testOptions, { From 6e8588ef907ae4d4cb27da818c1a0e101bf5cdec Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 29 May 2026 10:45:32 -0300 Subject: [PATCH 2/6] PivotGrid - Skip markup a11y tests on serverSide --- .../pivotGrid.markup.tests.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index 9952e729a932..da52cb0a83f3 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -101,6 +101,10 @@ QUnit.module('PivotGrid markup tests', () => { }); QUnit.test('Expandable td has aria-expanded reflecting expanded state', function(assert) { + if(!windowUtils.hasWindow()) { + assert.ok(true, 'skipped on serverSide'); + return; + } const clock = sinon.useFakeTimers(); try { const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); @@ -119,6 +123,10 @@ QUnit.module('PivotGrid markup tests', () => { }); QUnit.test('Expandable td has tabindex="0"', function(assert) { + if(!windowUtils.hasWindow()) { + assert.ok(true, 'skipped on serverSide'); + return; + } const clock = sinon.useFakeTimers(); try { const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); @@ -135,6 +143,10 @@ QUnit.module('PivotGrid markup tests', () => { }); QUnit.test('Non-expandable td has neither aria-expanded nor tabindex', function(assert) { + if(!windowUtils.hasWindow()) { + assert.ok(true, 'skipped on serverSide'); + return; + } const clock = sinon.useFakeTimers(); try { const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); From b90415ba32b9ee9240f6a7ceee86e442ee54fbdc Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 29 May 2026 12:15:50 -0300 Subject: [PATCH 3/6] PivotGrid - Refine keyboard a11y per review feedback --- .../scss/widgets/base/pivotGrid/_common.scss | 5 ++++ .../__internal/grids/pivot_grid/m_widget.ts | 2 +- .../pivotGrid.tests.js | 25 ++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/devextreme-scss/scss/widgets/base/pivotGrid/_common.scss b/packages/devextreme-scss/scss/widgets/base/pivotGrid/_common.scss index 87826aab0aca..0faf4d470dca 100644 --- a/packages/devextreme-scss/scss/widgets/base/pivotGrid/_common.scss +++ b/packages/devextreme-scss/scss/widgets/base/pivotGrid/_common.scss @@ -75,6 +75,11 @@ box-sizing: content-box; } + td[aria-expanded]:focus-visible { + outline: 2px solid currentColor; + outline-offset: -2px; + } + .dx-area-description-cell { position: relative; background-clip: padding-box; // T379462 diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index 67b29cfeb96b..14106e642a4b 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -888,7 +888,7 @@ class PivotGrid extends Widget { const args = this._createEventArgs(e.currentTarget, e); if (args.cell && isDefined(args.cell.expanded)) { e.preventDefault(); - this._handleCellClick({ currentTarget: e.currentTarget, preventDefault: noop }); + this._handleCellClick(e); } } } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js index ad9d101c0253..33914e15c297 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js @@ -512,7 +512,7 @@ QUnit.module('dxPivotGrid', { }); assert.ok(pivotGrid); - const $nonExpandableTd = $('#pivotGrid').find('td:not([aria-expanded])').first(); + const $nonExpandableTd = $('#pivotGrid').find('.dx-area-row-cell td').first(); assert.ok($nonExpandableTd.length > 0); $nonExpandableTd.trigger($.Event('keydown', { key: 'Enter' })); @@ -522,6 +522,29 @@ QUnit.module('dxPivotGrid', { assert.strictEqual(expandValueChangingArgs, undefined); }); + QUnit.test('onCellClick cancel prevents keyboard expansion', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + }, + onCellClick: function(args) { + args.cancel = true; + } + }); + assert.ok(pivotGrid); + + const $collapsedTd = $('#pivotGrid').find('.dx-pivotgrid-collapsed').closest('td'); + assert.strictEqual($collapsedTd.length, 1); + + $collapsedTd.trigger($.Event('keydown', { key: 'Enter' })); + + this.clock.tick(10); + + assert.strictEqual(expandValueChangingArgs, undefined); + }); + QUnit.test('T248253. DataSource changed', function(assert) { let expandValueChangingArgs; const pivotGrid = createPivotGrid($.extend(this.testOptions, { From 0764a9d20eae394da8f2f8e73c12c5ae773fd840 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 29 May 2026 15:22:47 -0300 Subject: [PATCH 4/6] PivotGrid - Add role="button" to expandable cells --- .../grids/pivot_grid/area_item/m_area_item.ts | 1 + .../pivotGrid.markup.tests.js | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts b/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts index 340579bfbfd9..eacf3c9f1fee 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts @@ -198,6 +198,7 @@ abstract class AreaItem { span.classList.add(PIVOTGRID_EXPAND_CLASS); div.appendChild(span); td.appendChild(div); + td.setAttribute('role', 'button'); td.setAttribute('aria-expanded', String(cell.expanded)); td.setAttribute('tabindex', '0'); } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index da52cb0a83f3..99ea944101cb 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -142,7 +142,27 @@ QUnit.module('PivotGrid markup tests', () => { } }); - QUnit.test('Non-expandable td has neither aria-expanded nor tabindex', function(assert) { + QUnit.test('Expandable td has role="button"', function(assert) { + if(!windowUtils.hasWindow()) { + assert.ok(true, 'skipped on serverSide'); + return; + } + const clock = sinon.useFakeTimers(); + try { + const pivotGrid = createPivotGrid({ dataSource: createExpandableDataSource() }); + clock.tick(10); + + const $expandedTd = pivotGrid.$element().find('.dx-pivotgrid-expanded').first().closest('td'); + const $collapsedTd = pivotGrid.$element().find('.dx-pivotgrid-collapsed').first().closest('td'); + + assert.strictEqual($expandedTd.attr('role'), 'button', 'expanded td has role="button"'); + assert.strictEqual($collapsedTd.attr('role'), 'button', 'collapsed td has role="button"'); + } finally { + clock.restore(); + } + }); + + QUnit.test('Non-expandable td has no role, aria-expanded, or tabindex', function(assert) { if(!windowUtils.hasWindow()) { assert.ok(true, 'skipped on serverSide'); return; @@ -155,6 +175,7 @@ QUnit.module('PivotGrid markup tests', () => { const $nonExpandableTd = pivotGrid.$element().find('td:not([aria-expanded])').first(); assert.ok($nonExpandableTd.length > 0, 'non-expandable td exists'); + assert.strictEqual($nonExpandableTd.attr('role'), undefined, 'no role attribute'); assert.strictEqual($nonExpandableTd.attr('aria-expanded'), undefined, 'no aria-expanded attribute'); assert.strictEqual($nonExpandableTd.attr('tabindex'), undefined, 'no tabindex attribute'); } finally { From 643501d6a4b152083c9844e04917c280b271c1ac Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 29 May 2026 15:43:03 -0300 Subject: [PATCH 5/6] PivotGrid - Ignore key auto-repeat in keyboard expand handler --- .../__internal/grids/pivot_grid/m_widget.ts | 3 +++ .../pivotGrid.tests.js | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index 14106e642a4b..eb710c031dc9 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -884,6 +884,9 @@ class PivotGrid extends Widget { } _handleCellKeyDown(e) { + if (e.repeat) { + return; + } if (e.key === 'Enter' || e.key === ' ') { const args = this._createEventArgs(e.currentTarget, e); if (args.cell && isDefined(args.cell.expanded)) { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js index 33914e15c297..f3d2b7f1a4a3 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js @@ -522,6 +522,26 @@ QUnit.module('dxPivotGrid', { assert.strictEqual(expandValueChangingArgs, undefined); }); + QUnit.test('keydown auto-repeat does not trigger expansion', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + } + }); + assert.ok(pivotGrid); + + const $collapsedTd = $('#pivotGrid').find('.dx-pivotgrid-collapsed').closest('td'); + assert.strictEqual($collapsedTd.length, 1); + + $collapsedTd.trigger($.Event('keydown', { key: 'Enter', repeat: true })); + + this.clock.tick(10); + + assert.strictEqual(expandValueChangingArgs, undefined); + }); + QUnit.test('onCellClick cancel prevents keyboard expansion', function(assert) { let expandValueChangingArgs; const pivotGrid = createPivotGrid({ From 74b5f609d1211dba2458f7849f03325809471db6 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 29 May 2026 18:39:08 -0300 Subject: [PATCH 6/6] PivotGrid - Restore focus after keyboard expand via shared a11y helpers --- .../grids/pivot_grid/area_item/m_area_item.ts | 1 + .../__internal/grids/pivot_grid/m_widget.ts | 7 +++++ .../pivotGrid.tests.js | 28 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts b/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts index eacf3c9f1fee..8160d13be582 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/area_item/m_area_item.ts @@ -199,6 +199,7 @@ abstract class AreaItem { div.appendChild(span); td.appendChild(div); td.setAttribute('role', 'button'); + td.setAttribute('aria-label', String(cell.text ?? cell.value ?? '')); td.setAttribute('aria-expanded', String(cell.expanded)); td.setAttribute('tabindex', '0'); } diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index eb710c031dc9..c2967c7f6ecd 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -20,6 +20,7 @@ import type { Properties } from '@js/ui/button'; import Button from '@js/ui/button'; import ContextMenu from '@js/ui/context_menu'; import Popup from '@js/ui/popup/ui.popup'; +import { restoreFocus, saveFocusedElementInfo } from '@js/ui/shared/accessibility'; import { current, isFluent } from '@js/ui/themes'; import Widget from '@ts/core/widget/widget'; import gridCoreUtils from '@ts/grids/grid_core/m_utils'; @@ -891,6 +892,12 @@ class PivotGrid extends Widget { const args = this._createEventArgs(e.currentTarget, e); if (args.cell && isDefined(args.cell.expanded)) { e.preventDefault(); + saveFocusedElementInfo(e.currentTarget, this); + const onReady = () => { + this.off('contentReady', onReady); + restoreFocus(this); + }; + this.on('contentReady', onReady); this._handleCellClick(e); } } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js index f3d2b7f1a4a3..d0bf5dc05e8c 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.tests.js @@ -542,6 +542,34 @@ QUnit.module('dxPivotGrid', { assert.strictEqual(expandValueChangingArgs, undefined); }); + QUnit.test('keyboard activation preserves focus on the same cell after re-render', function(assert) { + let expandValueChangingArgs; + const pivotGrid = createPivotGrid({ + dataSource: this.dataSource, + onExpandValueChanging: function(args) { + expandValueChangingArgs = $.extend({}, args); + } + }); + assert.ok(pivotGrid); + + const $collapsedTd = $('#pivotGrid').find('.dx-pivotgrid-collapsed').closest('td'); + assert.strictEqual($collapsedTd.length, 1); + const ariaLabelBefore = $collapsedTd.attr('aria-label'); + $collapsedTd.get(0).focus(); + + $collapsedTd.trigger($.Event('keydown', { key: 'Enter' })); + + this.clock.tick(100); + + assert.deepEqual(expandValueChangingArgs, { + area: 'column', + path: ['2012'], + expanded: true, + needExpandData: true + }); + assert.strictEqual($(document.activeElement).attr('aria-label'), ariaLabelBefore, 'focus restored to the same cell after expand'); + }); + QUnit.test('onCellClick cancel prevents keyboard expansion', function(assert) { let expandValueChangingArgs; const pivotGrid = createPivotGrid({