diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1045321 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1045321 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1045321 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1045321 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1113525.page-size-select (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1113525.page-size-select (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1113525.page-size-select (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1113525.page-size-select (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1159578-master-detail-with-renderAsync-1 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1159578-master-detail-with-renderAsync-1 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1159578-master-detail-with-renderAsync-1 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1159578-master-detail-with-renderAsync-1 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1159578-master-detail-with-renderAsync-2 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1159578-master-detail-with-renderAsync-2 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1159578-master-detail-with-renderAsync-2 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1159578-master-detail-with-renderAsync-2 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=false-1 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=false-1 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=false-1 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=false-1 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=false-2 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=false-2 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=false-2 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=false-2 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=false-3 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=false-3 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=false-3 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=false-3 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=true-1 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=true-1 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=true-1 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=true-1 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=true-2 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=true-2 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=true-2 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=true-2 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=true-3 (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=true-3 (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/T1167889-master-detail-with-scrolling.useNative=true-3 (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/etalons/T1167889-master-detail-with-scrolling.useNative=true-3 (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/functional.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/functional.ts new file mode 100644 index 000000000000..92ff0b4f7236 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/functional.ts @@ -0,0 +1,117 @@ +import { ClientFunction } from 'testcafe'; +import DataGrid from 'devextreme-testcafe-models/dataGrid'; +import url from '../../../../helpers/getPageUrl'; +import { createWidget } from '../../../../helpers/createWidget'; + +const getDetailGridLoadCount = ClientFunction(() => (window as any).detailGridLoadCount as number); + +fixture.disablePageReloads`Master detail.Functional` + .page(url(__dirname, '../../../container.html')); + +test('Detail grid should not reload data when the collapsed master row reenters the viewport with standard scrolling and virtual row rendering (T1326188)', async (t) => { + // arrange + const dataGrid = new DataGrid('#container'); + + await t.expect(dataGrid.isReady()).ok(); + + // act - expand the master row + await t.click(dataGrid.getDataRow(0).getCommandCell(0).element); + + let detailGrid = dataGrid.getMasterRow(0).getDataGrid(); + + // assert + await t + .expect(dataGrid.getDataRow(0).isExpanded) + .ok() + .expect(detailGrid.element.exists) + .ok() + .expect(getDetailGridLoadCount()) + .eql(1); + + // act - collapse the master row + await t.click(dataGrid.getDataRow(0).getCommandCell(0).element); + + // assert + await t + .expect(dataGrid.getDataRow(0).isExpanded) + .notOk() + .expect(detailGrid.element.visible) + .notOk() + .expect(getDetailGridLoadCount()) + .eql(1); + + // act + await dataGrid.scrollTo(t, { y: 10000 }); + + // assert + await t + .expect(dataGrid.isReady()) + .ok() + .expect(dataGrid.getDataRow(199).element.exists) + .ok(); + + // act + await dataGrid.scrollTo(t, { y: 0 }); + + detailGrid = dataGrid.getMasterRow(0).getDataGrid(); + + // assert + await t + .expect(dataGrid.isReady()) + .ok() + .expect(dataGrid.getDataRow(0).element.exists) + .ok() + .expect(detailGrid.element.exists) + .notOk() + .expect(getDetailGridLoadCount()) + .eql(1, 'Detail grid data should not be reloaded after scrolling back to the collapsed master row'); +}).before(async () => { + await ClientFunction(() => { + (window as any).detailGridLoadCount = 0; + })(); + + return createWidget('dxDataGrid', { + dataSource: [...new Array(200)].map((_, index) => ({ + id: index, + text: `item ${index}`, + })), + keyExpr: 'id', + height: 400, + scrolling: { + mode: 'standard', + rowRenderingMode: 'virtual', + // @ts-expect-error private option + updateTimeout: 0, + useNative: false, + }, + paging: { + enabled: false, + }, + columns: ['id', 'text'], + masterDetail: { + enabled: true, + template(container) { + ($('
') as any) + .dxDataGrid({ + keyExpr: 'id', + height: 180, + columns: ['id', 'text'], + dataSource: { + load() { + ((window as any).detailGridLoadCount as number) += 1; + + return [ + { id: 1, text: 'detail 1' }, + { id: 2, text: 'detail 2' }, + ]; + }, + key: 'id', + } as any, + }) + .appendTo(container); + }, + }, + }); +}).after(async () => ClientFunction(() => { + delete (window as any).detailGridLoadCount; +})()); diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/visual.ts similarity index 96% rename from e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail.ts rename to e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/visual.ts index 8a4aabdba5b8..2856fe1104aa 100644 --- a/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail.ts +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/masterDetail/visual.ts @@ -1,12 +1,12 @@ import { ClientFunction } from 'testcafe'; import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; import DataGrid from 'devextreme-testcafe-models/dataGrid'; -import url from '../../../helpers/getPageUrl'; -import { createWidget } from '../../../helpers/createWidget'; -import { testScreenshot } from '../../../helpers/themeUtils'; +import url from '../../../../helpers/getPageUrl'; +import { createWidget } from '../../../../helpers/createWidget'; +import { testScreenshot } from '../../../../helpers/themeUtils'; -fixture.disablePageReloads`Master detail` - .page(url(__dirname, '../../container.html')); +fixture.disablePageReloads`Master detail.Visual` + .page(url(__dirname, '../../../container.html')); // visual: material.blue.light // visual: generic.light diff --git a/packages/devextreme/js/__internal/grids/grid_core/data_controller/m_data_controller.ts b/packages/devextreme/js/__internal/grids/grid_core/data_controller/m_data_controller.ts index 54d8693d62c7..e8fe7487c881 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/data_controller/m_data_controller.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/data_controller/m_data_controller.ts @@ -1791,6 +1791,10 @@ export class DataController extends DataHelperMixin(modules.Controller) { public isViewportChanging(): boolean { return false; } + + public resetCachedProcessedItems(): void { + this._cachedProcessedItems = null; + } } export const dataControllerModule: Module = { defaultOptions() { diff --git a/packages/devextreme/js/__internal/grids/grid_core/master_detail/m_master_detail.ts b/packages/devextreme/js/__internal/grids/grid_core/master_detail/m_master_detail.ts index aa6982bf02cd..9bddb33090bf 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/master_detail/m_master_detail.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/master_detail/m_master_detail.ts @@ -118,6 +118,7 @@ export const dataMasterDetailExtenderMixin = (Base: ModuleType) changeType: 'update', rowIndices: that._getRowIndicesForExpand(key), }); + that.resetCachedProcessedItems(); // @ts-expect-error result = new Deferred().resolve();