Skip to content

Commit 5ee331d

Browse files
authored
CardView: editing operations, add/edit/delete (throw error if needed) (Gv6qwVwI) (DevExpress#29879)
1 parent d15accf commit 5ee331d

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* eslint-disable spellcheck/spell-checker */
2+
import {
3+
afterEach, beforeEach, describe, expect, it, jest,
4+
} from '@jest/globals';
5+
import $ from '@js/core/renderer';
6+
import CardView from '@ts/grids/new/card_view/widget';
7+
import type { Options as GridCoreOptions } from '@ts/grids/new/grid_core/options';
8+
import { throwError } from '@ts/grids/new/grid_core/options_validation/utils';
9+
import { rerender } from 'inferno';
10+
11+
const SELECTORS = {
12+
cardView: '.dx-cardview',
13+
addButton: '[aria-label="add"]',
14+
editButton: '[aria-label="edit"]',
15+
deleteButton: '[aria-label="remove"]',
16+
};
17+
18+
const setup = (options: GridCoreOptions = {}): CardView => {
19+
const container = document.createElement('div');
20+
const { body } = document;
21+
body.append(container);
22+
23+
const cardView = new CardView(container, options);
24+
rerender();
25+
return cardView;
26+
};
27+
28+
const getAddButton = (): Element | null => document.querySelector(SELECTORS.addButton);
29+
30+
const getEditButton = (): Element | null => document.querySelector(SELECTORS.editButton);
31+
32+
const getDeleteButton = (): Element | null => document.querySelector(SELECTORS.deleteButton);
33+
34+
const checkError = (): void => expect(throwError).toHaveBeenCalledWith('E1042', 'CardView');
35+
36+
jest.mock('@ts/grids/new/grid_core/options_validation/utils', () => ({
37+
throwError: jest.fn().mockImplementation(() => ({})),
38+
}));
39+
40+
describe('editing validation', () => {
41+
afterEach(() => {
42+
const cardView = document.querySelector(SELECTORS.cardView);
43+
// @ts-expect-error bad typed renderer
44+
$(cardView ?? undefined as any)?.dxCardView('dispose');
45+
document.body.innerHTML = '';
46+
});
47+
48+
beforeEach(() => {
49+
jest.clearAllMocks();
50+
});
51+
52+
it('should throw error when no keyExpr and clicking on add', () => {
53+
setup({
54+
dataSource: [{ value: 'test1' }],
55+
editing: { allowAdding: true },
56+
});
57+
58+
const addButton = getAddButton();
59+
addButton?.dispatchEvent(new MouseEvent('click'));
60+
61+
checkError();
62+
});
63+
64+
it('should throw error when no keyExpr and clicking on edit', () => {
65+
setup({
66+
dataSource: [{ value: 'test1' }],
67+
editing: { allowUpdating: true },
68+
});
69+
const editButton = getEditButton();
70+
editButton?.dispatchEvent(new MouseEvent('click'));
71+
72+
checkError();
73+
});
74+
75+
it('should throw error when no keyExpr and clicking on delete', () => {
76+
setup({
77+
dataSource: [{ value: 'test1' }],
78+
editing: { allowDeleting: true },
79+
});
80+
const deleteButton = getDeleteButton();
81+
deleteButton?.dispatchEvent(new MouseEvent('click'));
82+
83+
checkError();
84+
});
85+
});

packages/devextreme/js/__internal/grids/new/grid_core/editing/controller.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { isDefined } from '@js/core/utils/type';
55
import { confirm } from '@js/ui/dialog';
66
import { computed, type Signal } from '@preact/signals-core';
77
import { generateNewRowTempKey } from '@ts/grids/grid_core/editing/m_editing_utils';
8+
import { OptionsValidationController } from '@ts/grids/new/grid_core/options_validation/index';
89

910
import { ColumnsController } from '../columns_controller/columns_controller';
1011
import { DataController } from '../data_controller/data_controller';
@@ -64,6 +65,11 @@ export class EditingController {
6465
}
6566

6667
const oldItem = this.itemsController.findItemByKey(items, editCardKey)!;
68+
69+
if (!oldItem) {
70+
return null;
71+
}
72+
6773
const newData = applyChanges(
6874
[oldItem.data],
6975
changes,
@@ -85,6 +91,7 @@ export class EditingController {
8591
OptionsController, ItemsController,
8692
ColumnsController, DataController,
8793
KeyboardNavigationController,
94+
OptionsValidationController,
8895
] as const;
8996

9097
constructor(
@@ -93,9 +100,12 @@ export class EditingController {
93100
private readonly columnController: ColumnsController,
94101
private readonly dataController: DataController,
95102
private readonly kbn: KeyboardNavigationController,
103+
private readonly optionsValidationController: OptionsValidationController,
96104
) {}
97105

98106
public editCard(key: Key): void {
107+
this.optionsValidationController.validateKeyExpr();
108+
99109
const eventArgs = {
100110
cancel: false,
101111
key,
@@ -110,6 +120,8 @@ export class EditingController {
110120
}
111121

112122
public async addCard(): Promise<void> {
123+
this.optionsValidationController.validateKeyExpr();
124+
113125
const eventArgs = {
114126
promise: undefined,
115127
data: {},
@@ -155,6 +167,8 @@ export class EditingController {
155167
}
156168

157169
public async deleteCard(key: Key): Promise<void> {
170+
this.optionsValidationController.validateKeyExpr();
171+
158172
const confirmStatus = await this.confirmDelete();
159173

160174
if (!confirmStatus) {

0 commit comments

Comments
 (0)