Skip to content

Commit 2fbe275

Browse files
Merge branch '26_1' into 26_1_T1327953
2 parents 3d6b2dc + 1aaa7ca commit 2fbe275

18 files changed

Lines changed: 1488 additions & 20 deletions

File tree

-8.74 KB
Loading

packages/devextreme/js/__internal/grids/data_grid/module_not_extended/ai_assistant.ts renamed to packages/devextreme/js/__internal/grids/data_grid/ai_assistant/ai_assistant.ts

File renamed without changes.
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
import {
2+
afterEach,
3+
beforeEach,
4+
describe,
5+
expect,
6+
it,
7+
jest,
8+
} from '@jest/globals';
9+
import type { Properties } from '@js/ui/data_grid';
10+
import {
11+
afterTest,
12+
beforeTest,
13+
createDataGrid,
14+
} from '@ts/grids/grid_core/__tests__/__mock__/helpers/utils';
15+
import type { CommandResult } from '@ts/grids/grid_core/ai_assistant/types';
16+
import type { InternalGrid } from '@ts/grids/grid_core/m_types';
17+
18+
import { clearGroupingCommand, groupingCommand } from '../grouping';
19+
20+
const createCallbacks = (): {
21+
success: jest.Mock<(message?: string) => CommandResult>;
22+
failure: jest.Mock<(message?: string) => CommandResult>;
23+
} => ({
24+
success: jest.fn((message?: string) => ({ status: 'success' as const, message: message ?? '' })),
25+
failure: jest.fn((message?: string) => ({ status: 'failure' as const, message: message ?? '' })),
26+
});
27+
28+
const createGrid = async (
29+
options: Record<string, unknown> = {},
30+
): Promise<InternalGrid> => {
31+
const { instance } = await createDataGrid({
32+
dataSource: [
33+
{ id: 1, name: 'Alpha', age: 10 },
34+
{ id: 2, name: 'Beta', age: 20 },
35+
],
36+
columns: [
37+
{ dataField: 'id', dataType: 'number' },
38+
{ dataField: 'name', caption: 'Full Name', dataType: 'string' },
39+
{ dataField: 'age', dataType: 'number' },
40+
],
41+
...options,
42+
} as unknown as Properties);
43+
return instance as unknown as InternalGrid;
44+
};
45+
46+
describe('groupingCommand', () => {
47+
beforeEach(() => beforeTest());
48+
afterEach(() => afterTest());
49+
50+
describe('schema', () => {
51+
it('accepts valid args with non-negative integer groupIndex', () => {
52+
expect(groupingCommand.schema.safeParse({
53+
dataField: 'name',
54+
groupIndex: 0,
55+
}).success).toBe(true);
56+
});
57+
58+
it('accepts null groupIndex (ungroup)', () => {
59+
expect(groupingCommand.schema.safeParse({
60+
dataField: 'name',
61+
groupIndex: null,
62+
}).success).toBe(true);
63+
});
64+
65+
it('rejects when dataField is missing', () => {
66+
expect(groupingCommand.schema.safeParse({
67+
groupIndex: 0,
68+
}).success).toBe(false);
69+
});
70+
71+
it('rejects when groupIndex is missing', () => {
72+
expect(groupingCommand.schema.safeParse({
73+
dataField: 'name',
74+
}).success).toBe(false);
75+
});
76+
77+
it('rejects when dataField is not a string', () => {
78+
expect(groupingCommand.schema.safeParse({
79+
dataField: 123,
80+
groupIndex: 0,
81+
}).success).toBe(false);
82+
});
83+
84+
it('rejects when groupIndex is negative', () => {
85+
expect(groupingCommand.schema.safeParse({
86+
dataField: 'name',
87+
groupIndex: -1,
88+
}).success).toBe(false);
89+
});
90+
91+
it('rejects when groupIndex is not an integer', () => {
92+
expect(groupingCommand.schema.safeParse({
93+
dataField: 'name',
94+
groupIndex: 1.5,
95+
}).success).toBe(false);
96+
});
97+
98+
it('rejects unknown properties', () => {
99+
expect(groupingCommand.schema.safeParse({
100+
dataField: 'name',
101+
groupIndex: 0,
102+
extra: 1,
103+
}).success).toBe(false);
104+
});
105+
});
106+
107+
describe('execute', () => {
108+
it('returns failure and skips columnOption write when column.allowGrouping is false', async () => {
109+
const instance = await createGrid({
110+
columns: [
111+
{ dataField: 'id', dataType: 'number' },
112+
{
113+
dataField: 'name', caption: 'Full Name', dataType: 'string', allowGrouping: false,
114+
},
115+
],
116+
});
117+
const columnsController = instance.getController('columns');
118+
const spy = jest.spyOn(columnsController, 'columnOption');
119+
const callbacks = createCallbacks();
120+
121+
const result = await groupingCommand.execute(instance, callbacks)({
122+
dataField: 'name',
123+
groupIndex: 0,
124+
});
125+
126+
expect(result.status).toBe('failure');
127+
expect(callbacks.success).not.toHaveBeenCalled();
128+
expect(spy).not.toHaveBeenCalledWith(
129+
expect.anything(),
130+
'groupIndex',
131+
expect.anything(),
132+
);
133+
});
134+
135+
it('returns failure and skips columnOption write when dataField does not match any column', async () => {
136+
const instance = await createGrid();
137+
const columnsController = instance.getController('columns');
138+
const spy = jest.spyOn(columnsController, 'columnOption');
139+
const callbacks = createCallbacks();
140+
141+
const result = await groupingCommand.execute(instance, callbacks)({
142+
dataField: 'unknown',
143+
groupIndex: 0,
144+
});
145+
146+
expect(result.status).toBe('failure');
147+
expect(callbacks.success).not.toHaveBeenCalled();
148+
expect(spy).not.toHaveBeenCalledWith(
149+
expect.anything(),
150+
'groupIndex',
151+
expect.anything(),
152+
);
153+
});
154+
155+
it('calls columnsController.columnOption(column.index, "groupIndex", groupIndex) for non-null groupIndex', async () => {
156+
const instance = await createGrid();
157+
const columnsController = instance.getController('columns');
158+
const spy = jest.spyOn(columnsController, 'columnOption');
159+
const callbacks = createCallbacks();
160+
161+
const result = await groupingCommand.execute(instance, callbacks)({
162+
dataField: 'name',
163+
groupIndex: 0,
164+
});
165+
166+
const nameColumn = columnsController.columnOption('name') as { index: number };
167+
expect(spy).toHaveBeenCalledWith(nameColumn.index, 'groupIndex', 0);
168+
expect(result.status).toBe('success');
169+
});
170+
171+
it('passes undefined when groupIndex is null (ungroups the column)', async () => {
172+
const instance = await createGrid();
173+
const columnsController = instance.getController('columns');
174+
const spy = jest.spyOn(columnsController, 'columnOption');
175+
const callbacks = createCallbacks();
176+
177+
const result = await groupingCommand.execute(instance, callbacks)({
178+
dataField: 'name',
179+
groupIndex: null,
180+
});
181+
182+
const nameColumn = columnsController.columnOption('name') as { index: number };
183+
expect(spy).toHaveBeenCalledWith(nameColumn.index, 'groupIndex', undefined);
184+
expect(result.status).toBe('success');
185+
});
186+
187+
it('returns failure when columnOption throws', async () => {
188+
const instance = await createGrid();
189+
const columnsController = instance.getController('columns');
190+
const originalColumnOption = columnsController.columnOption.bind(columnsController);
191+
jest.spyOn(columnsController, 'columnOption').mockImplementation((...args: unknown[]) => {
192+
if (args.length >= 3) {
193+
throw new Error('Error setting groupIndex');
194+
}
195+
return (originalColumnOption as (...a: unknown[]) => unknown)(...args);
196+
});
197+
const callbacks = createCallbacks();
198+
199+
const result = await groupingCommand.execute(instance, callbacks)({
200+
dataField: 'name',
201+
groupIndex: 0,
202+
});
203+
204+
expect(result.status).toBe('failure');
205+
});
206+
});
207+
208+
describe('default message', () => {
209+
it('uses `Group data against "[caption]".` for non-null groupIndex', async () => {
210+
const instance = await createGrid();
211+
const callbacks = createCallbacks();
212+
213+
await groupingCommand.execute(instance, callbacks)({
214+
dataField: 'name',
215+
groupIndex: 0,
216+
});
217+
218+
expect(callbacks.success).toHaveBeenCalledWith(
219+
'Group data against "Full Name".',
220+
);
221+
});
222+
223+
it('uses `Ungroup data against "[caption]".` for null groupIndex', async () => {
224+
const instance = await createGrid();
225+
const callbacks = createCallbacks();
226+
227+
await groupingCommand.execute(instance, callbacks)({
228+
dataField: 'name',
229+
groupIndex: null,
230+
});
231+
232+
expect(callbacks.success).toHaveBeenCalledWith(
233+
'Ungroup data against "Full Name".',
234+
);
235+
});
236+
237+
it('passes the same default message to failure when executability fails', async () => {
238+
const instance = await createGrid({
239+
columns: [
240+
{ dataField: 'id', dataType: 'number' },
241+
{
242+
dataField: 'name', caption: 'Full Name', dataType: 'string', allowGrouping: false,
243+
},
244+
],
245+
});
246+
const callbacks = createCallbacks();
247+
248+
await groupingCommand.execute(instance, callbacks)({
249+
dataField: 'name',
250+
groupIndex: 0,
251+
});
252+
253+
expect(callbacks.failure).toHaveBeenCalledWith(
254+
'Group data against "Full Name".',
255+
);
256+
});
257+
258+
it('falls back to the raw dataField when no column matches', async () => {
259+
const instance = await createGrid();
260+
const callbacks = createCallbacks();
261+
262+
await groupingCommand.execute(instance, callbacks)({
263+
dataField: 'unknown',
264+
groupIndex: 0,
265+
});
266+
267+
expect(callbacks.failure).toHaveBeenCalledWith(
268+
'Group data against "unknown".',
269+
);
270+
});
271+
});
272+
});
273+
274+
describe('clearGroupingCommand', () => {
275+
beforeEach(() => beforeTest());
276+
afterEach(() => afterTest());
277+
278+
describe('schema', () => {
279+
it('accepts an empty object', () => {
280+
expect(clearGroupingCommand.schema.safeParse({}).success).toBe(true);
281+
});
282+
283+
it('rejects unknown properties', () => {
284+
expect(clearGroupingCommand.schema.safeParse({
285+
extra: 1,
286+
}).success).toBe(false);
287+
});
288+
});
289+
290+
describe('execute', () => {
291+
it('calls columnsController.clearGrouping() exactly once', async () => {
292+
const instance = await createGrid();
293+
const columnsController = instance.getController('columns');
294+
const spy = jest.spyOn(columnsController, 'clearGrouping');
295+
const callbacks = createCallbacks();
296+
297+
const result = await clearGroupingCommand.execute(instance, callbacks)();
298+
299+
expect(spy).toHaveBeenCalledTimes(1);
300+
expect(result.status).toBe('success');
301+
});
302+
303+
it('returns failure when clearGrouping throws', async () => {
304+
const instance = await createGrid();
305+
const columnsController = instance.getController('columns');
306+
jest.spyOn(columnsController, 'clearGrouping').mockImplementation(() => {
307+
throw new Error('Error');
308+
});
309+
const callbacks = createCallbacks();
310+
311+
const result = await clearGroupingCommand.execute(instance, callbacks)();
312+
313+
expect(result.status).toBe('failure');
314+
});
315+
});
316+
317+
describe('default message', () => {
318+
it('uses the literal `Clear grouping.`', async () => {
319+
const instance = await createGrid();
320+
const callbacks = createCallbacks();
321+
322+
await clearGroupingCommand.execute(instance, callbacks)();
323+
324+
expect(callbacks.success).toHaveBeenCalledWith('Clear grouping.');
325+
});
326+
327+
it('passes the same default message to failure when executability fails', async () => {
328+
const instance = await createGrid();
329+
const columnsController = instance.getController('columns');
330+
jest.spyOn(columnsController, 'clearGrouping').mockImplementation(() => {
331+
throw new Error('Error');
332+
});
333+
const callbacks = createCallbacks();
334+
335+
await clearGroupingCommand.execute(instance, callbacks)();
336+
337+
expect(callbacks.failure).toHaveBeenCalledWith('Clear grouping.');
338+
});
339+
});
340+
});

0 commit comments

Comments
 (0)