Skip to content

Commit 8566436

Browse files
authored
Scheduler - Rewrite deleteAppointments.ts testcafe tests to jest (DevExpress#33120)
1 parent 4a195e8 commit 8566436

6 files changed

Lines changed: 341 additions & 104 deletions

File tree

e2e/testcafe-devextreme/tests/scheduler/common/deleteAppointments.ts

Lines changed: 0 additions & 102 deletions
This file was deleted.

packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ export class PopupModel {
1010
this.queries = within(element);
1111
}
1212

13+
get deleteSeriesButton(): HTMLElement {
14+
return this.queries.getByRole('button', { name: 'Delete series' }) as HTMLElement;
15+
}
16+
17+
get deleteAppointmentButton(): HTMLElement {
18+
return this.queries.getByRole('button', { name: 'Delete appointment' }) as HTMLElement;
19+
}
20+
1321
getLabelIdByText = (labelText: string): string => {
1422
const labels = Array.from(this.element.querySelectorAll('label'));
1523

packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/scheduler.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { POPUP_DIALOG_CLASS } from '../../../m_scheduler';
66
import type { AppointmentModel } from './appointment';
77
import { createAppointmentModel } from './appointment';
88
import { PopupModel } from './popup';
9+
import { TooltipModel } from './tooltip';
910

1011
const getTexts = (
1112
cells: ArrayLike<Element>,
@@ -25,6 +26,10 @@ export class SchedulerModel {
2526
return this.getPopup();
2627
}
2728

29+
get tooltip(): TooltipModel {
30+
return new TooltipModel();
31+
}
32+
2833
get toolbar(): ToolbarModel {
2934
return new ToolbarModel(this.queries.getByRole('toolbar'));
3035
}
@@ -55,6 +60,17 @@ export class SchedulerModel {
5560
return getTexts(collectors);
5661
}
5762

63+
getCollectorButton(index = 0): HTMLElement {
64+
const allButtons = this.queries.queryAllByRole('button') as HTMLElement[];
65+
const collectors = allButtons.filter((btn) => btn.classList.contains('dx-scheduler-appointment-collector'));
66+
67+
if (collectors.length === 0) {
68+
throw new Error('Collector button not found');
69+
}
70+
71+
return collectors[index];
72+
}
73+
5874
getDateTableContent(): string[] {
5975
const cells = this.container.querySelectorAll('.dx-scheduler-date-table-cell');
6076
return getTexts(cells);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { within } from '@testing-library/dom';
2+
3+
const TOOLTIP_WRAPPER_SELECTOR = '.dx-overlay-wrapper.dx-scheduler-appointment-tooltip-wrapper';
4+
5+
export class TooltipModel {
6+
private get element(): HTMLElement | null {
7+
return document.querySelector<HTMLElement>(TOOLTIP_WRAPPER_SELECTOR);
8+
}
9+
10+
isVisible(): boolean {
11+
return this.element !== null;
12+
}
13+
14+
getScrollableContent(): Element | null {
15+
return this.element?.querySelector('.dx-scrollable .dx-scrollview-content') ?? null;
16+
}
17+
18+
getDeleteButton(index = 0): HTMLElement {
19+
const tooltip = this.element;
20+
const buttons = tooltip
21+
? within(tooltip).queryAllByRole('button').filter((btn) => btn.classList.contains('dx-tooltip-appointment-item-delete-button'))
22+
: [];
23+
24+
if (buttons.length === 0) {
25+
throw new Error('Tooltip delete button not found');
26+
}
27+
28+
return buttons[index];
29+
}
30+
31+
getAppointmentItem(index = 0): HTMLElement | null {
32+
const tooltip = this.element;
33+
if (!tooltip) {
34+
return null;
35+
}
36+
return within(tooltip).queryAllByRole('option')[index] ?? null;
37+
}
38+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import {
2+
afterEach, beforeEach, describe, expect, it, jest,
3+
} from '@jest/globals';
4+
import fx from '@js/common/core/animation/fx';
5+
6+
import { createScheduler } from './__mock__/create_scheduler';
7+
import { setupSchedulerTestEnvironment } from './__mock__/m_mock_scheduler';
8+
9+
describe('Appointment tooltip behavior', () => {
10+
beforeEach(() => {
11+
fx.off = true;
12+
setupSchedulerTestEnvironment();
13+
});
14+
15+
afterEach(() => {
16+
fx.off = false;
17+
jest.useRealTimers();
18+
document.body.innerHTML = '';
19+
});
20+
21+
describe('Deleting appointments', () => {
22+
it('should delete appointment on delete button click in tooltip', async () => {
23+
const data = [
24+
{
25+
text: 'Apt1',
26+
startDate: new Date(2017, 4, 22, 9, 30),
27+
endDate: new Date(2017, 4, 22, 10, 30),
28+
},
29+
{
30+
text: 'Apt2',
31+
startDate: new Date(2017, 4, 22, 9, 30),
32+
endDate: new Date(2017, 4, 22, 10, 30),
33+
},
34+
];
35+
36+
const { POM, scheduler } = await createScheduler({
37+
dataSource: [...data],
38+
views: [{ type: 'month', maxAppointmentsPerCell: 1 }],
39+
currentView: 'month',
40+
currentDate: new Date(2017, 4, 22),
41+
height: 600,
42+
});
43+
44+
POM.getCollectorButton().click();
45+
POM.tooltip.getDeleteButton().click();
46+
47+
expect(POM.tooltip.isVisible()).toBe(false);
48+
expect((scheduler as any).getDataSource().items()).toEqual([data[0]]);
49+
});
50+
51+
it('should not delete appointment by Delete key when editing.allowDeleting=false', async () => {
52+
const data = [
53+
{
54+
text: 'Apt1',
55+
startDate: new Date(2017, 4, 22, 9, 30),
56+
endDate: new Date(2017, 4, 22, 10, 30),
57+
},
58+
{
59+
text: 'Apt2',
60+
startDate: new Date(2017, 4, 22, 9, 30),
61+
endDate: new Date(2017, 4, 22, 10, 30),
62+
},
63+
];
64+
65+
const { POM, scheduler } = await createScheduler({
66+
dataSource: [...data],
67+
views: [{ type: 'month', maxAppointmentsPerCell: 1 }],
68+
currentView: 'month',
69+
currentDate: new Date(2017, 4, 22),
70+
height: 600,
71+
editing: {
72+
allowDeleting: false,
73+
},
74+
});
75+
76+
POM.getCollectorButton().click();
77+
78+
const tooltipScrollableContent = POM.tooltip.getScrollableContent();
79+
tooltipScrollableContent?.dispatchEvent(new FocusEvent('focusin', { bubbles: true }));
80+
tooltipScrollableContent?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Delete', bubbles: true }));
81+
82+
expect((scheduler as any).getDataSource().items()).toEqual([...data]);
83+
});
84+
85+
it('should not delete disabled appointment by Delete key when focused in tooltip from collector', async () => {
86+
const data = [
87+
{
88+
text: 'Apt1',
89+
startDate: new Date(2017, 4, 22, 9, 30),
90+
endDate: new Date(2017, 4, 22, 10, 30),
91+
},
92+
{
93+
text: 'Apt2',
94+
startDate: new Date(2017, 4, 22, 9, 30),
95+
endDate: new Date(2017, 4, 22, 10, 30),
96+
disabled: true,
97+
},
98+
];
99+
100+
const { POM, scheduler } = await createScheduler({
101+
dataSource: [...data],
102+
views: [{ type: 'month', maxAppointmentsPerCell: 1 }],
103+
currentView: 'month',
104+
currentDate: new Date(2017, 4, 22),
105+
height: 600,
106+
});
107+
108+
POM.getCollectorButton().click();
109+
110+
const tooltipScrollableContent = POM.tooltip.getScrollableContent();
111+
tooltipScrollableContent?.dispatchEvent(new FocusEvent('focusin', { bubbles: true }));
112+
tooltipScrollableContent?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Delete', bubbles: true }));
113+
114+
expect((scheduler as any).getDataSource().items()).toEqual([...data]);
115+
});
116+
117+
it('should delete single occurrence on delete button click and clicking \'Delete appointment\'', async () => {
118+
const data = [
119+
{
120+
text: 'Apt1',
121+
startDate: new Date(2017, 4, 22, 9, 30),
122+
endDate: new Date(2017, 4, 22, 10, 30),
123+
},
124+
{
125+
text: 'Apt2',
126+
startDate: new Date(2017, 4, 22, 9, 30),
127+
endDate: new Date(2017, 4, 22, 10, 30),
128+
recurrenceRule: 'FREQ=DAILY',
129+
},
130+
];
131+
132+
const { POM, scheduler } = await createScheduler({
133+
dataSource: [{ ...data[0] }, { ...data[1] }],
134+
views: [{ type: 'month', maxAppointmentsPerCell: 1 }],
135+
currentView: 'month',
136+
currentDate: new Date(2017, 4, 22),
137+
editing: true,
138+
height: 600,
139+
});
140+
141+
POM.getCollectorButton().click();
142+
POM.tooltip.getDeleteButton(0).click();
143+
POM.popup.deleteAppointmentButton.click();
144+
145+
const items = (scheduler as any).getDataSource().items();
146+
147+
expect(items).toEqual([
148+
data[0],
149+
expect.objectContaining(data[1]),
150+
]);
151+
152+
expect(items[1].recurrenceException).toContain('20170522');
153+
});
154+
155+
it('should delete all occurrences on delete and clicking \'Delete series\'', async () => {
156+
const data = [
157+
{
158+
text: 'Apt1',
159+
startDate: new Date(2017, 4, 22, 9, 30),
160+
endDate: new Date(2017, 4, 22, 10, 30),
161+
},
162+
{
163+
text: 'Apt2',
164+
startDate: new Date(2017, 4, 22, 9, 30),
165+
endDate: new Date(2017, 4, 22, 10, 30),
166+
recurrenceRule: 'FREQ=DAILY',
167+
},
168+
];
169+
170+
const { POM, scheduler } = await createScheduler({
171+
dataSource: [{ ...data[0] }, { ...data[1] }],
172+
views: [{ type: 'month', maxAppointmentsPerCell: 1 }],
173+
currentView: 'month',
174+
currentDate: new Date(2017, 4, 22),
175+
editing: true,
176+
height: 600,
177+
});
178+
179+
POM.getCollectorButton().click();
180+
POM.tooltip.getDeleteButton(0).click();
181+
POM.popup.deleteSeriesButton.click();
182+
183+
expect((scheduler as any).getDataSource().items()).toEqual([data[0]]);
184+
});
185+
});
186+
});

0 commit comments

Comments
 (0)