From 68831f2b94dca00319f7a211d8942cddb5a2788f Mon Sep 17 00:00:00 2001 From: "anna.shakhova" Date: Fri, 23 Jan 2026 16:37:58 +0100 Subject: [PATCH 1/2] GridCore: fix data controller odata test --- .../data_controller/data_controller.test.ts | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts index 3ca473caea03..05466cd199ea 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts @@ -1,5 +1,9 @@ -import { describe, expect, it } from '@jest/globals'; +import { + describe, expect, it, jest, +} from '@jest/globals'; import { CustomStore } from '@js/common/data'; +import ajax from '@js/core/utils/ajax'; +import { Deferred } from '@js/core/utils/deferred'; import { getContext } from '../di.test_utils'; import type { Options } from '../options'; @@ -97,12 +101,27 @@ describe('DataController', () => { describe('regressions', () => { it('should work good with odata store', async () => { + const sendRequestSpy = jest.spyOn(ajax, 'sendRequest').mockImplementation(() => { + const response = { + d: { + results: [{ Product_ID: 1 }, { Product_ID: 2 }, { Product_ID: 3 }], + __count: 10, + }, + }; + + // @ts-expect-error + const deferred = new Deferred(); + deferred.resolve(response, 'success'); + + return deferred.promise(); + }); + const { dataController } = setup({ dataSource: { store: { type: 'odata', version: 2, - url: 'https://js.devexpress.com/Demos/DevAV/odata/Products', + url: 'https://www.example.com/odata', key: 'Product_ID', }, select: [ @@ -122,18 +141,36 @@ describe('DataController', () => { }, }); - const getCurrentItemIds = () => dataController.items.value.map((item) => item.Product_ID); + const expectedFilter = 'Product_Current_Inventory gt 0'; + const expectedSelect = 'Product_ID,Product_Name,Product_Cost,Product_Sale_Price,Product_Retail_Price,Product_Current_Inventory'; await dataController.waitLoaded(); expect(dataController.pageIndex.value).toBe(0); - expect(getCurrentItemIds()).toEqual([1, 2, 4]); + expect(sendRequestSpy).toHaveBeenCalledTimes(1); + expect(sendRequestSpy).toHaveBeenLastCalledWith(expect.objectContaining({ + data: expect.objectContaining({ + $top: 3, + $filter: expectedFilter, + $select: expectedSelect, + }), + })); dataController.pageIndex.value = 1; await dataController.waitLoaded(); expect(dataController.pageIndex.value).toBe(1); - expect(getCurrentItemIds()).toEqual([5, 6, 7]); + expect(sendRequestSpy).toHaveBeenCalledTimes(2); + expect(sendRequestSpy).toHaveBeenLastCalledWith(expect.objectContaining({ + data: expect.objectContaining({ + $top: 3, + $skip: 3, + $filter: expectedFilter, + $select: expectedSelect, + }), + })); + + sendRequestSpy.mockRestore(); }); }); }); From daf2e2b0fcd09e107f5b57e26f9e5c305adf2555 Mon Sep 17 00:00:00 2001 From: "anna.shakhova" Date: Mon, 26 Jan 2026 10:52:00 +0100 Subject: [PATCH 2/2] return result check --- .../data_controller/data_controller.test.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts index 05466cd199ea..bcfd8a3b12f0 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.test.ts @@ -3,12 +3,14 @@ import { } from '@jest/globals'; import { CustomStore } from '@js/common/data'; import ajax from '@js/core/utils/ajax'; +import type { DeferredObj } from '@js/core/utils/deferred'; import { Deferred } from '@js/core/utils/deferred'; import { getContext } from '../di.test_utils'; import type { Options } from '../options'; import { OptionsControllerMock } from '../options_controller/options_controller.mock'; import { DataController } from './data_controller'; +import type { DataObject } from './types'; const setup = (options?: Options) => { const context = getContext(options ?? {}); @@ -101,10 +103,14 @@ describe('DataController', () => { describe('regressions', () => { it('should work good with odata store', async () => { - const sendRequestSpy = jest.spyOn(ajax, 'sendRequest').mockImplementation(() => { + const sendRequestSpy = jest.spyOn(ajax, 'sendRequest').mockImplementation((params: any) => { + const isFirstPage = params.data.$skip === undefined || params.data.$skip === 0; + const firstPageItems = [{ Product_ID: 1 }, { Product_ID: 2 }, { Product_ID: 4 }]; + const secondPageItems = [{ Product_ID: 5 }, { Product_ID: 6 }, { Product_ID: 7 }]; + const response = { d: { - results: [{ Product_ID: 1 }, { Product_ID: 2 }, { Product_ID: 3 }], + results: isFirstPage ? firstPageItems : secondPageItems, __count: 10, }, }; @@ -113,7 +119,7 @@ describe('DataController', () => { const deferred = new Deferred(); deferred.resolve(response, 'success'); - return deferred.promise(); + return deferred.promise() as DeferredObj<{ Product_ID: number }[]>; }); const { dataController } = setup({ @@ -141,6 +147,10 @@ describe('DataController', () => { }, }); + const getCurrentItemIds = (): number[] => ( + dataController.items.value as (DataObject & { Product_ID: number })[] + ).map((item) => item.Product_ID); + const expectedFilter = 'Product_Current_Inventory gt 0'; const expectedSelect = 'Product_ID,Product_Name,Product_Cost,Product_Sale_Price,Product_Retail_Price,Product_Current_Inventory'; @@ -155,6 +165,7 @@ describe('DataController', () => { $select: expectedSelect, }), })); + expect(getCurrentItemIds()).toEqual([1, 2, 4]); dataController.pageIndex.value = 1; await dataController.waitLoaded(); @@ -169,6 +180,7 @@ describe('DataController', () => { $select: expectedSelect, }), })); + expect(getCurrentItemIds()).toEqual([5, 6, 7]); sendRequestSpy.mockRestore(); });