diff --git a/apps/demos/testing/skipped-tests.js b/apps/demos/testing/skipped-tests.js index 87ca5003503b..15e5cf306a86 100644 --- a/apps/demos/testing/skipped-tests.js +++ b/apps/demos/testing/skipped-tests.js @@ -3,8 +3,8 @@ export const skippedTests = { // WebGL initialization error at the provider. There is no point in adding a mask Map: ['ProvidersAndTypes', 'Markers', 'Routes'], - // Remote WidgetsGalleryDataService is unstable - DataGrid: ['RemoteGrouping', 'RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], + // Remote WidgetsGalleryDataService is unstable (RemoteGrouping is covered by a separate mocked test) + DataGrid: ['RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], // AI answers are not stable TreeList: ['AIColumns'], @@ -13,8 +13,8 @@ export const skippedTests = { // WebGL initialization error at the provider. There is no point in adding a mask Map: ['ProvidersAndTypes', 'Markers', 'Routes'], - // Remote WidgetsGalleryDataService is unstable - DataGrid: ['RemoteGrouping', 'RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], + // Remote WidgetsGalleryDataService is unstable (RemoteGrouping is covered by a separate mocked test) + DataGrid: ['RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], // AI answers are not stable TreeList: ['AIColumns'], @@ -23,8 +23,8 @@ export const skippedTests = { // WebGL initialization error at the provider. There is no point in adding a mask Map: ['ProvidersAndTypes', 'Markers', 'Routes'], - // Remote WidgetsGalleryDataService is unstable - DataGrid: ['RemoteGrouping', 'RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], + // Remote WidgetsGalleryDataService is unstable (RemoteGrouping is covered by a separate mocked test) + DataGrid: ['RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], // AI answers are not stable TreeList: ['AIColumns'], @@ -33,8 +33,8 @@ export const skippedTests = { // WebGL initialization error at the provider. There is no point in adding a mask Map: ['ProvidersAndTypes', 'Markers', 'Routes'], - // Remote WidgetsGalleryDataService is unstable - DataGrid: ['RemoteGrouping', 'RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], + // Remote WidgetsGalleryDataService is unstable (RemoteGrouping is covered by a separate mocked test) + DataGrid: ['RemoteVirtualScrolling', 'CustomDataSource', 'AIColumns'], // AI answers are not stable TreeList: ['AIColumns'], diff --git a/apps/demos/testing/widgets/datagrid/RemoteGrouping.test.ts b/apps/demos/testing/widgets/datagrid/RemoteGrouping.test.ts index 71ebeba18176..7a23ca3a6825 100644 --- a/apps/demos/testing/widgets/datagrid/RemoteGrouping.test.ts +++ b/apps/demos/testing/widgets/datagrid/RemoteGrouping.test.ts @@ -2,8 +2,10 @@ import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; import { Selector as $, ClientFunction } from 'testcafe'; import { runManualTest } from '../../../utils/visual-tests/matrix-test-helper'; import { testScreenshot } from '../../../utils/visual-tests/helpers/theme-utils'; +import { remoteGroupingMock } from './apiMocks/remoteGroupingMock'; fixture('DataGrid.RemoteGrouping') + .requestHooks(remoteGroupingMock) .before(async (ctx) => { ctx.initialWindowSize = [900, 600]; }); diff --git a/apps/demos/testing/widgets/datagrid/apiMocks/remoteGroupingMock.ts b/apps/demos/testing/widgets/datagrid/apiMocks/remoteGroupingMock.ts new file mode 100644 index 000000000000..d7ac12827aa8 --- /dev/null +++ b/apps/demos/testing/widgets/datagrid/apiMocks/remoteGroupingMock.ts @@ -0,0 +1,123 @@ +import { RequestMock } from 'testcafe'; + +const CORS = { 'access-control-allow-origin': '*' }; + +const toGroup = ({ key, count }: { key: string; count: number }) => ({ + key, + items: null, + count, + summary: [count], +}); + +const storeGroupsInitPage = { + data: [ + { key: 'Contoso Albany Store', count: 2058 }, + { key: 'Contoso Alexandria Store', count: 2021 }, + { key: 'Contoso Amsterdam Store', count: 2064 }, + { key: 'Contoso Anchorage Store', count: 2072 }, + { key: 'Contoso Annapolis Store', count: 2131 }, + { key: 'Contoso Appleton Store', count: 2045 }, + { key: 'Contoso Arlington Store', count: 2049 }, + { key: 'Contoso Ashgabat No.2 Store', count: 3275 }, + { key: 'Contoso Ashgabat No.1 Store', count: 3285 }, + { key: 'Contoso Asia Online Store', count: 56357 }, + { key: 'Contoso Asia Reseller', count: 38313 }, + { key: 'Contoso Athens Store', count: 2218 }, + { key: 'Contoso Atlantic City Store', count: 2104 }, + { key: 'Contoso Attleboro Store', count: 2043 }, + { key: 'Contoso Aurora Store', count: 2075 }, + { key: 'Contoso Austin Store', count: 2029 }, + { key: 'Contoso Back River Store', count: 2015 }, + { key: 'Contoso Bacliff Store', count: 2100 }, + { key: 'Contoso Baildon Store', count: 2144 }, + { key: 'Contoso Baltimore Store', count: 2103 }, + ].map(toGroup), + totalCount: 1000000, + groupCount: 306, +}; + +const storeGroupsScrolledPage = { + data: [ + { key: 'Contoso Guangzhou Store', count: 476 }, + { key: 'Contoso Hackensack Store', count: 2090 }, + { key: 'Contoso Hartford Store', count: 2079 }, + { key: 'Contoso Haverhill Store', count: 2075 }, + { key: 'Contoso Hillsboro Store', count: 2113 }, + { key: 'Contoso Hingham Store', count: 1972 }, + { key: 'Contoso Hoboken Store', count: 2033 }, + { key: 'Contoso Hofheim Store', count: 2182 }, + { key: 'Contoso Holyoke Store', count: 1980 }, + { key: 'Contoso Hong Kong No.1 Store', count: 3271 }, + { key: 'Contoso Hong Kong No.2 Store', count: 2960 }, + { key: 'Contoso Houston No.1 Store', count: 2078 }, + { key: 'Contoso Houston No.2 Store', count: 2117 }, + { key: 'Contoso Houston No.3 Store', count: 2002 }, + { key: 'Contoso Houston No.4 Store', count: 2068 }, + { key: 'Contoso Howard Store', count: 2023 }, + { key: 'Contoso Humble Store', count: 2050 }, + { key: 'Contoso Islamabad No.2 Store', count: 2177 }, + { key: 'Contoso Islamabad No.1 Store', count: 3207 }, + { key: 'Contoso Ithaca Store', count: 2036 }, + ].map(toGroup), + totalCount: 1000000, + groupCount: 306, +}; + +const categoryGroups = { + data: [ + { key: 'Audio', count: 63 }, + { key: 'Cameras and camcorders', count: 349 }, + { key: 'Cell phones', count: 254 }, + { key: 'Computers', count: 548 }, + { key: 'Games and Toys', count: 48 }, + { key: 'Home Appliances', count: 592 }, + { key: 'Music, Movies and Audio Books', count: 82 }, + { key: 'TV and Video', count: 177 }, + ].map(toGroup), + totalCount: 2113, + groupCount: 8, +}; + +const emptyGroups = { data: [], totalCount: 0, groupCount: 0 }; + +const isSalesUrl = (url: string): boolean => /\/api\/Sales\b/i.test(url); + +const hasFilter = (url: string): boolean => /[?&]filter=/.test(url); + +const groupParam = (url: string): string => { + const match = url.match(/[?&]group=([^&]*)/); + return match ? decodeURIComponent(match[1]) : ''; +}; + +const isGroupedBy = (url: string, selector: string): boolean => groupParam(url).includes(`"selector":"${selector}"`); + +const skipOf = (url: string): number => { + const match = url.match(/[?&]skip=(\d+)/); + return match ? Number(match[1]) : 0; +}; + +const entries: { match: (url: string) => boolean; data: object }[] = [ + { + match: (url) => isSalesUrl(url) && isGroupedBy(url, 'StoreName') && !hasFilter(url) && skipOf(url) === 0, + data: storeGroupsInitPage, + }, + { + match: (url) => isSalesUrl(url) && isGroupedBy(url, 'StoreName') && !hasFilter(url) && skipOf(url) > 0, + data: storeGroupsScrolledPage, + }, + { + match: (url) => isSalesUrl(url) && isGroupedBy(url, 'ProductCategoryName') && hasFilter(url), + data: categoryGroups, + }, + { + match: (url) => isSalesUrl(url), + data: emptyGroups, + }, +]; + +export const remoteGroupingMock = entries.reduce( + (mock, { match, data }) => mock + .onRequestTo((req) => match(req.url)) + .respond(data, 200, CORS), + RequestMock(), +); diff --git a/apps/demos/utils/visual-tests/matrix-test-helper.ts b/apps/demos/utils/visual-tests/matrix-test-helper.ts index a737d579a569..3e7e7f66d595 100644 --- a/apps/demos/utils/visual-tests/matrix-test-helper.ts +++ b/apps/demos/utils/visual-tests/matrix-test-helper.ts @@ -203,12 +203,11 @@ export function shouldRunTestAtIndex(testIndex) { return part === currentPart; } -// Remote WidgetsGalleryDataService is unstable, so RemoteGrouping is skipped const SKIPPED_TESTS = { - jQuery: { DataGrid: ['RemoteGrouping'] }, - Angular: { DataGrid: ['RemoteGrouping'] }, - Vue: { DataGrid: ['RemoteGrouping'] }, - React: { DataGrid: ['RemoteGrouping'] }, + jQuery: {}, + Angular: {}, + Vue: {}, + React: {}, }; export function shouldSkipDemo(framework, component, demoName, skippedTests) {