From 481e479f8d048cf04558c7f8d43c0c9d31b315ca Mon Sep 17 00:00:00 2001 From: "anna.shakhova" Date: Wed, 14 Jan 2026 14:57:00 +0100 Subject: [PATCH 1/3] DataGrid: remove unnecessary code from filter_row --- .../js/__internal/grids/grid_core/filter/m_filter_row.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts b/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts index 14c26228c344..8d93673f3f23 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts @@ -13,6 +13,7 @@ import Menu from '@js/ui/menu'; import Overlay from '@js/ui/overlay/ui.overlay'; import { selectView } from '@js/ui/shared/accessibility'; import type { ColumnsController } from '@ts/grids/grid_core/columns_controller/m_columns_controller'; +import type MenuInternal from '@ts/ui/menu/menu'; import type { ColumnHeadersView } from '../column_headers/m_column_headers'; import type { ColumnsResizerViewController } from '../columns_resizing_reordering/m_columns_resizing_reordering'; @@ -650,15 +651,11 @@ const columnHeadersView = (Base: ModuleType) => class ColumnH editorFactoryController.loseFocus(); }, onSubmenuHiding() { - // @ts-expect-error - eventsEngine.trigger($menu, 'blur'); restoreFocus(); }, onContentReady(e) { eventsEngine.on($menu, 'blur', () => { - const menu = e.component; - // @ts-expect-error - menu._hideSubmenuAfterTimeout(); + (e.component as unknown as MenuInternal)._hideSubmenuAfterTimeout(); restoreFocus(); }); }, From 09055b18142801e1c30953d6939b85194d09a0af Mon Sep 17 00:00:00 2001 From: "anna.shakhova" Date: Fri, 16 Jan 2026 11:05:16 +0100 Subject: [PATCH 2/3] DataGrid: move overlay to headers --- .../grids/grid_core/filter/m_filter_row.ts | 10 ++-- .../filterRow.tests.js | 46 ++++++++++--------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts b/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts index 8d93673f3f23..051bafb8ad1c 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_row.ts @@ -301,6 +301,7 @@ const columnHeadersView = (Base: ModuleType) => class ColumnH hideOnParentScroll: true, _hideOnParentScrollTarget: $overlay, wrapperAttr: { class: filterRangeOverlayClass }, + container: this.element(), animation: false, position: { my: 'top', @@ -338,10 +339,13 @@ const columnHeadersView = (Base: ModuleType) => class ColumnH that._renderEditor($editor, editorOptions); eventsEngine.on($editor.find(EDITORS_INPUT_SELECTOR), 'keydown', (e) => { if (normalizeKeyName(e) === 'tab' && !e.shiftKey) { - e.preventDefault(); that._hideFilterRange(); - // @ts-expect-error - eventsEngine.trigger($cell.next().find('[tabindex]').first(), 'focus'); + + if ($cell.next().length) { + e.preventDefault(); + // @ts-expect-error + eventsEngine.trigger($cell.next().find('[tabindex]').first(), 'focus'); + } } }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/filterRow.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/filterRow.tests.js index fcb267a32f6a..b615aee7f2b0 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/filterRow.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/filterRow.tests.js @@ -1382,6 +1382,10 @@ QUnit.module('Filter Row with real dataController and columnsController', { return filterMenuItems.find('.dx-menu-item').eq(index); } + function getFilterRowOverlay() { + return $('.dx-datagrid-headers').children('.dx-datagrid-filter-range-overlay'); + } + // T104040 QUnit.test('Not apply filter when changed filter operation with empty filter value', function(assert) { // arrange @@ -1596,7 +1600,7 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert assert.equal($testElement.find('.dx-filter-range-content').length, 1, 'has filter range content'); - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 0, 'no overlay wrapper'); + assert.equal(getFilterRowOverlay().length, 0, 'no overlay wrapper'); }); QUnit.test('Overlay of between operation does not hide after scroll event', function(assert) { @@ -1625,14 +1629,14 @@ QUnit.module('Filter Row with real dataController and columnsController', { $('#qunit-fixture').find('.dx-menu-item:contains(\'Between\')').trigger('dxclick'); // select filter operation is 'between' // assert - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 1, 'has overlay wrapper'); + assert.equal(getFilterRowOverlay().length, 1, 'has overlay wrapper'); // arrange $('.dx-viewport').find('.dx-filter-range-content').trigger('scroll'); // assert // T1280071 - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 0, 'overlay wrapper is removed'); + assert.equal(getFilterRowOverlay().length, 0, 'overlay wrapper is removed'); }); // T428602 @@ -1659,7 +1663,7 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert assert.equal($testElement.find('.dx-filter-range-content').length, 1, 'has filter range content'); - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 1, 'has overlay wrapper'); + assert.equal(getFilterRowOverlay().length, 1, 'has overlay wrapper'); }); QUnit.test('Show filter range popup when column with selectedFilterOperation is \'isBetween\'', function(assert) { @@ -1682,8 +1686,8 @@ QUnit.module('Filter Row with real dataController and columnsController', { that.clock.tick(10); // assert - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 1, 'has overlay wrapper'); - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').length, 2, 'count number box'); + assert.equal(getFilterRowOverlay().length, 1, 'has overlay wrapper'); + assert.equal(getFilterRowOverlay().find('.dx-numberbox').length, 2, 'count number box'); }); QUnit.test('Show filter range popup when column with selectedFilterOperation is \'isBetween\' and filter value is array', function(assert) { @@ -1708,8 +1712,8 @@ QUnit.module('Filter Row with real dataController and columnsController', { that.clock.tick(10); // assert - const $startRange = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').first(); - const $endRange = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').last(); + const $startRange = getFilterRowOverlay().find('.dx-numberbox').first(); + const $endRange = getFilterRowOverlay().find('.dx-numberbox').last(); assert.equal($startRange.length, 1, 'has number box'); assert.equal($endRange.length, 1, 'has number box'); assert.strictEqual($startRange.find('input').val(), '15', 'value of the first editor'); @@ -1864,7 +1868,7 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert const column = that.columnsController.getVisibleColumns()[1]; assert.strictEqual(column.selectedFilterOperation, 'between', 'selected filter operation'); - assert.strictEqual($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('input').eq(0).val(), '', 'start value of the range'); + assert.strictEqual(getFilterRowOverlay().find('input').eq(0).val(), '', 'start value of the range'); assert.strictEqual(column.filterValue, null, 'filter value of the column'); }); @@ -1889,9 +1893,9 @@ QUnit.module('Filter Row with real dataController and columnsController', { that.clock.tick(10); // assert - const $startRangeInput = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').first().find(TEXTEDITOR_INPUT_SELECTOR); + const $startRangeInput = getFilterRowOverlay().find('.dx-numberbox').first().find(TEXTEDITOR_INPUT_SELECTOR); assert.equal($startRangeInput.length, 1, 'has input'); - const $endRangeInput = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').last().find(TEXTEDITOR_INPUT_SELECTOR); + const $endRangeInput = getFilterRowOverlay().find('.dx-numberbox').last().find(TEXTEDITOR_INPUT_SELECTOR); assert.equal($endRangeInput.length, 1, 'has input'); // act @@ -1930,9 +1934,9 @@ QUnit.module('Filter Row with real dataController and columnsController', { $($testElement.find('td').last().find('.dx-filter-range-content')).trigger('focusin'); that.clock.tick(10); - const $startRangeInput = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').first().find(TEXTEDITOR_INPUT_SELECTOR); + const $startRangeInput = getFilterRowOverlay().find('.dx-numberbox').first().find(TEXTEDITOR_INPUT_SELECTOR); assert.equal($startRangeInput.length, 1, 'has input'); - const $endRangeInput = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox').last().find(TEXTEDITOR_INPUT_SELECTOR); + const $endRangeInput = getFilterRowOverlay().find('.dx-numberbox').last().find(TEXTEDITOR_INPUT_SELECTOR); assert.equal($endRangeInput.length, 1, 'has input'); const changedSpy = sinon.spy(); @@ -2171,14 +2175,14 @@ QUnit.module('Filter Row with real dataController and columnsController', { that.clock.tick(10); // assert - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 1, 'has overlay wrapper'); + assert.equal(getFilterRowOverlay().length, 1, 'has overlay wrapper'); // act that.columnHeadersView.render($testElement); that.columnHeadersView.resize(); // assert - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 0, 'hasn\'t overlay wrapper'); + assert.equal(getFilterRowOverlay().length, 0, 'hasn\'t overlay wrapper'); }); QUnit.test('Add custom tabIndex to filter range content', function(assert) { @@ -2869,9 +2873,9 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert const $cells = $testElement.find('td'); - const $numberBoxElements = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox'); + const $numberBoxElements = getFilterRowOverlay().find('.dx-numberbox'); assert.equal($cells.first().find('.dx-datagrid-filter-range-overlay').length, 1, 'has filter range popup'); - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 1, 'has popup wrapper'); + assert.equal(getFilterRowOverlay().length, 1, 'has popup wrapper'); assert.equal($numberBoxElements.length, 2, 'count number box'); // act @@ -2879,7 +2883,7 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert assert.equal($cells.first().find('.dx-filter-range-content').length, 1, 'has filter range content'); - assert.ok(!$('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 'not has popup wrapper'); + assert.ok(!getFilterRowOverlay().length, 'not has popup wrapper'); assert.ok($cells.last().find('.dx-menu').first().is(':focus'), 'focus on menu of the second cell'); }); @@ -2904,9 +2908,9 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert const $cells = $testElement.find('td'); - const $numberBoxElements = $('.dx-viewport').children('.dx-datagrid-filter-range-overlay').find('.dx-numberbox'); + const $numberBoxElements = getFilterRowOverlay().find('.dx-numberbox'); assert.equal($cells.first().find('.dx-datagrid-filter-range-overlay').length, 1, 'has filter range popup'); - assert.equal($('.dx-viewport').children('.dx-datagrid-filter-range-overlay').length, 1, 'has popup wrapper'); + assert.equal(getFilterRowOverlay().length, 1, 'has popup wrapper'); assert.equal($numberBoxElements.length, 2, 'count number box'); // act @@ -2914,7 +2918,7 @@ QUnit.module('Filter Row with real dataController and columnsController', { // assert assert.equal($cells.first().find('.dx-filter-range-content').length, 1, 'has filter range content'); - assert.ok(!$('.dx-viewport').children('.dx-datagrid-filter-range-popup').length, 'not has popup wrapper'); + assert.ok(!getFilterRowOverlay().length, 'not has popup wrapper'); assert.ok($cells.first().find('.dx-menu').first().is(':focus'), 'focus on menu of the first cell'); }); } From a2e28958d10c63dbe5626fe22abd980f2f93f28e Mon Sep 17 00:00:00 2001 From: "anna.shakhova" Date: Fri, 16 Jan 2026 12:52:28 +0100 Subject: [PATCH 3/3] add tests --- ...1163100_changeFIlterIcon.visual_matrix.ts} | 0 .../T1072609 (material.blue.light).png | Bin 0 -> 6018 bytes .../filterRow/{filterRow.ts => functional.ts} | 231 +++++++----------- .../tests/dataGrid/common/filterRow/visual.ts | 127 ++++++++++ 4 files changed, 212 insertions(+), 146 deletions(-) rename e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/{T1163100_changeFIlterIcon.ts => T1163100_changeFIlterIcon.visual_matrix.ts} (100%) create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/etalons/T1072609 (material.blue.light).png rename e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/{filterRow.ts => functional.ts} (54%) create mode 100644 e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/visual.ts diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/T1163100_changeFIlterIcon.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/T1163100_changeFIlterIcon.visual_matrix.ts similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/T1163100_changeFIlterIcon.ts rename to e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/T1163100_changeFIlterIcon.visual_matrix.ts diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/etalons/T1072609 (material.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/etalons/T1072609 (material.blue.light).png new file mode 100644 index 0000000000000000000000000000000000000000..348086e36a95cf5db0cdd2b1758932ab0a6444a2 GIT binary patch literal 6018 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 createWidget('dxDataGrid', { @@ -52,60 +50,6 @@ test('Filter should reset if the filter row editor text is cleared (T1257261)', }, })); -// visual: material.blue.light -test('Filter row\'s height should be adjusted by content (T1072609)', async (t) => { - const dataGrid = new DataGrid('#container'); - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); - - await testScreenshot(t, takeScreenshot, 'T1072609.png', { element: dataGrid.element }); - await t - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); -}).before(async () => createWidget('dxDataGrid', { - columns: [{ - dataField: 'Date', - dataType: 'date', - width: 140, - selectedFilterOperation: 'between', - filterValue: [new Date(2022, 2, 28), new Date(2022, 2, 29)], - }], - filterRow: { visible: true }, - wordWrapEnabled: true, - showBorders: true, -})); - -test('FilterRow range overlay screenshot', async (t) => { - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); - const dataGrid = new DataGrid('#container'); - const filterEditor = dataGrid.getFilterEditor(1, FilterTextBox); - - await t - .click(filterEditor.menuButton); - await t - .click(filterEditor.menu.getItemByText('Between')); - // act - await testScreenshot(t, takeScreenshot, 'filter-row-overlay.png', { element: dataGrid.element }); - await t - .expect(compareResults.isValid()) - .ok() - // assert - .expect(dataGrid.getFilterRangeOverlay().exists) - .ok() - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); -}).before(async () => createWidget('dxDataGrid', { - dataSource: getNumberData(20, 2), - height: 400, - showBorders: true, - filterRow: { - visible: true, - applyFilter: 'auto', - }, - scrolling: { - showScrollbar: 'never', - }, -})); - // T1267481 test('Filter Row\'s Reset button does not work after a custom filter is set in Filter Builder', async (t) => { const dataGrid = new DataGrid('#container'); @@ -157,35 +101,37 @@ test('Filter Row\'s Reset button does not work after a custom filter is set in F }); }); -// T1287288 -// visual: fluent.blue.light -test('Focus overlay should be visible in filter row when focusedRowEnabled is enabled', async (t) => { - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); +// T1290381 +test('DataGrid - filter row\'s search-box\'s aria-label should be customizable via localization', async (t) => { const dataGrid = new DataGrid('#container'); - const filterEditor = dataGrid.getFilterEditor(1, FilterTextBox); + const filterEditor = dataGrid.getFilterEditor(0, FilterTextBox); + + await dataGrid.isReady(); + + const ariaLabel = await filterEditor.menuButton.getAttribute('aria-label'); await t - .click(dataGrid.getDataCell(0, 0).element) - .click(filterEditor.input) - // assert - .expect(filterEditor.input.focused) - .ok(); - await testScreenshot(t, takeScreenshot, 'filter-row-focus-overlay.png', { element: dataGrid.element }); - await t - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); -}).before(async () => createWidget('dxDataGrid', { - dataSource: [ - { ID: 1, Field: 'Item 1' }, - { ID: 2, Field: 'Item 2' }, - { ID: 3, Field: 'Item 3' }, - ], - keyExpr: 'ID', - focusedRowEnabled: true, - filterRow: { visible: true }, - showBorders: true, - columns: ['ID', 'Field'], -})); + .expect(ariaLabel) + .eql('custom text'); +}).before(async (t) => { + await t.eval(() => { + (window as any).DevExpress.localization.loadMessages({ + en: { + 'dxDataGrid-ariaSearchBox': 'custom text', + }, + }); + }); + + return createWidget('dxDataGrid', { + columns: [{ + dataField: 'test', + dataType: 'string', + }], + filterRow: { + visible: true, + }, + }); +}); test('DataGrid - NVDA reads filter menu items as "Search box 1 of 8" (T1290386)', async (t) => { const dataGrid = new DataGrid('#container'); @@ -219,67 +165,60 @@ test('DataGrid - NVDA reads filter menu items as "Search box 1 of 8" (T1290386)' }, })); -test('DataGrid - The `between` filter dropdown sticks to the viewport edge during horizontal scrolling (T1280071)', async (t) => { - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); - const dataGrid = new DataGrid('#container'); - const filterEditor = dataGrid.getFilterEditor(0, FilterTextBox); - - await dataGrid.isReady(); +// T1312521 +[true, false].forEach((grouped) => { + test('DataGrid - filter range overlay in last column on Tab pressed moves focus to next tabbable element (T1312521)', async (t) => { + const dataGrid = new DataGrid('#container'); + const filterCell = dataGrid.getFilterCell(2); + const firstCell = grouped ? dataGrid.getGroupRow(0) : dataGrid.getDataCell(0, 0); + + await t + .click(filterCell) + .pressKey('tab') + .pressKey('tab') + .expect(firstCell.isFocused) + .ok(); + }).before(async () => createWidget('dxDataGrid', { + dataSource: [ + { Group: 'group1', Value: 'field1', Range: 10 }, + { Group: 'group1', Value: 'field2', Range: 20 }, + { Group: 'group2', Value: 'field3', Range: 30 }, + { Group: 'group2', Value: 'field4', Range: 40 }, + ], + filterRow: { visible: true }, + columns: [ + { + dataField: 'Group', + groupIndex: grouped ? 0 : undefined, + }, + 'Value', + { + dataField: 'Range', + selectedFilterOperation: 'between', + }, + ], + })); +}); - await t - .click(filterEditor.menuButton) - .click(filterEditor.menu.getItemByText('Between')); +test('DataGrid - filter range overlay in last column on Tab pressed moves focus to next tabbable element with empty data (T1312521)', async (t) => { + const dataGrid = new DataGrid('#container'); + const filterCell = dataGrid.getFilterCell(2); - await dataGrid.scrollBy(t, { x: 999 }); - await testScreenshot(t, takeScreenshot, 'filter-row-filter-range-hide-on-scroll.png'); await t - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); + .click(filterCell) + .pressKey('tab') + .pressKey('tab') + .expect(dataGrid.getRowsView().focused) + .ok(); }).before(async () => createWidget('dxDataGrid', { - dataSource: [ - { ID: 1, Text: 'Item 1' }, - { ID: 2, Text: '' }, - { ID: 3, Text: 'Item 3' }, + dataSource: [], + filterRow: { visible: true }, + columns: [ + 'Group', + 'Value', + { + dataField: 'Range', + selectedFilterOperation: 'between', + }, ], - keyExpr: 'ID', - filterRow: { - visible: true, - }, - scrolling: { - useNative: true, - }, - columnWidth: 400, - width: 500, })); - -// T1290381 -test('DataGrid - filter row\'s search-box\'s aria-label should be customizable via localization', async (t) => { - const dataGrid = new DataGrid('#container'); - const filterEditor = dataGrid.getFilterEditor(0, FilterTextBox); - - await dataGrid.isReady(); - - const ariaLabel = await filterEditor.menuButton.getAttribute('aria-label'); - - await t - .expect(ariaLabel) - .eql('custom text'); -}).before(async (t) => { - await t.eval(() => { - (window as any).DevExpress.localization.loadMessages({ - en: { - 'dxDataGrid-ariaSearchBox': 'custom text', - }, - }); - }); - - return createWidget('dxDataGrid', { - columns: [{ - dataField: 'test', - dataType: 'string', - }], - filterRow: { - visible: true, - }, - }); -}); diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/visual.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/visual.ts new file mode 100644 index 000000000000..0c46a4adf9d9 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/filterRow/visual.ts @@ -0,0 +1,127 @@ +import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; +import DataGrid from 'devextreme-testcafe-models/dataGrid'; +import FilterTextBox from 'devextreme-testcafe-models/dataGrid/editors/filterTextBox'; +import url from '../../../../helpers/getPageUrl'; +import { createWidget } from '../../../../helpers/createWidget'; +import { getNumberData } from '../../helpers/generateDataSourceData'; +import { testScreenshot } from '../../../../helpers/themeUtils'; + +fixture`FilterRow` + .page(url(__dirname, '../../../container.html')); + +test.meta({ + themes: ['material.blue.light'], +})('Filter row\'s height should be adjusted by content (T1072609)', async (t) => { + const dataGrid = new DataGrid('#container'); + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + await testScreenshot(t, takeScreenshot, 'T1072609.png', { element: dataGrid.element }); + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => createWidget('dxDataGrid', { + columns: [{ + dataField: 'Date', + dataType: 'date', + width: 140, + selectedFilterOperation: 'between', + filterValue: [new Date(2022, 2, 28), new Date(2022, 2, 29)], + }], + filterRow: { visible: true }, + wordWrapEnabled: true, + showBorders: true, +})); + +test('FilterRow range overlay screenshot', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid('#container'); + const filterEditor = dataGrid.getFilterEditor(1, FilterTextBox); + + await t + .click(filterEditor.menuButton); + await t + .click(filterEditor.menu.getItemByText('Between')); + // act + await testScreenshot(t, takeScreenshot, 'filter-row-overlay.png', { element: dataGrid.element }); + await t + .expect(compareResults.isValid()) + .ok() + // assert + .expect(dataGrid.getFilterRangeOverlay().exists) + .ok() + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => createWidget('dxDataGrid', { + dataSource: getNumberData(20, 2), + height: 400, + showBorders: true, + filterRow: { + visible: true, + applyFilter: 'auto', + }, + scrolling: { + showScrollbar: 'never', + }, +})); + +// T1287288 +test('Focus overlay should be visible in filter row when focusedRowEnabled is enabled', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid('#container'); + const filterEditor = dataGrid.getFilterEditor(1, FilterTextBox); + + await t + .click(dataGrid.getDataCell(0, 0).element) + .click(filterEditor.input) + // assert + .expect(filterEditor.input.focused) + .ok(); + await testScreenshot(t, takeScreenshot, 'filter-row-focus-overlay.png', { element: dataGrid.element }); + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [ + { ID: 1, Field: 'Item 1' }, + { ID: 2, Field: 'Item 2' }, + { ID: 3, Field: 'Item 3' }, + ], + keyExpr: 'ID', + focusedRowEnabled: true, + filterRow: { visible: true }, + showBorders: true, + columns: ['ID', 'Field'], +})); + +test('DataGrid - The `between` filter dropdown sticks to the viewport edge during horizontal scrolling (T1280071)', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid('#container'); + const filterEditor = dataGrid.getFilterEditor(0, FilterTextBox); + + await dataGrid.isReady(); + + await t + .click(filterEditor.menuButton) + .click(filterEditor.menu.getItemByText('Between')); + + await dataGrid.scrollBy(t, { x: 999 }); + await testScreenshot(t, takeScreenshot, 'filter-row-filter-range-hide-on-scroll.png'); + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [ + { ID: 1, Text: 'Item 1' }, + { ID: 2, Text: '' }, + { ID: 3, Text: 'Item 3' }, + ], + keyExpr: 'ID', + filterRow: { + visible: true, + }, + scrolling: { + useNative: true, + }, + columnWidth: 400, + width: 500, +}));