diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts index e9490bc2ad6c..2033ea59043d 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts @@ -1,8 +1,13 @@ +import { within } from '@testing-library/dom'; + export class PopupModel { element: HTMLDivElement; + private readonly queries: ReturnType; + constructor(element: HTMLDivElement) { this.element = element; + this.queries = within(element); } getLabelIdByText = (labelText: string): string => { @@ -104,27 +109,25 @@ export class PopupModel { getDoneButton = (): HTMLButtonElement => { const doneButton = this.element.querySelector('.dx-button.dx-popup-done') as HTMLButtonElement; + if (!doneButton) { throw new Error('Done button not found'); } + return doneButton; }; getCancelButton = (): HTMLButtonElement => { const cancelButton = this.element.querySelector('.dx-button.dx-popup-cancel') as HTMLButtonElement; + if (!cancelButton) { throw new Error('Cancel button not found'); } + return cancelButton; }; - getCloseButton = (): HTMLButtonElement => { - const closeButton = this.element.querySelector('.dx-closebutton.dx-button') as HTMLButtonElement; - if (!closeButton) { - throw new Error('Close button not found'); - } - return closeButton; - }; + getCloseButton = (): HTMLButtonElement => this.queries.getByRole('button', { name: 'Close' }) as HTMLButtonElement; getFormEditor = (fieldName: string): HTMLElement | null => { const form = this.getForm(); @@ -134,11 +137,5 @@ export class PopupModel { return form.querySelector(`[data-field="${fieldName}"]`); }; - getEditSeriesButton = (): HTMLElement => { - const editSeriesButton = document.querySelector('[aria-label="Edit series"]') as HTMLElement; - if (!editSeriesButton) { - throw new Error('Edit series button not found'); - } - return editSeriesButton; - }; + getEditSeriesButton = (): HTMLElement => this.queries.getByRole('button', { name: 'Edit series' }) as HTMLElement; } diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/scheduler.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/scheduler.ts index 1b86bd2b5be0..2dc18d453e0b 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/scheduler.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/scheduler.ts @@ -1,3 +1,4 @@ +import { within } from '@testing-library/dom'; import { ToolbarModel } from '@ts/scheduler/__tests__/__mock__/model/toolbar'; import { APPOINTMENT_POPUP_CLASS } from '../../../appointment_popup/m_popup'; @@ -7,14 +8,17 @@ import { createAppointmentModel } from './appointment'; import { PopupModel } from './popup'; const getTexts = ( - cells: NodeListOf, + cells: ArrayLike, ): string[] => Array.from(cells).map((cell) => cell.textContent?.trim() ?? ''); export class SchedulerModel { container: HTMLDivElement; + private readonly queries: ReturnType; + constructor(container: HTMLDivElement) { this.container = container; + this.queries = within(container); } get popup(): PopupModel { @@ -22,25 +26,33 @@ export class SchedulerModel { } get toolbar(): ToolbarModel { - return new ToolbarModel(this.container.querySelector('.dx-scheduler-header')); + return new ToolbarModel(this.queries.getByRole('toolbar')); } getStatusContent(): string { - return this.container.querySelector('.dx-scheduler-a11y-status-container')?.textContent ?? ''; + const statusElement = this.container.querySelector('.dx-scheduler-a11y-status-container'); + return statusElement?.textContent ?? ''; } getAppointment(text?: string): AppointmentModel { if (!text) { - return createAppointmentModel(this.container.querySelector('.dx-scheduler-appointment')); + const appointments = this.getAppointments(); + return appointments.length > 0 ? appointments[0] : createAppointmentModel(null); } return this.getAppointments() .find((appointment) => appointment.getText() === text) ?? createAppointmentModel(null); } getAppointments(): AppointmentModel[] { - return [...this.container.querySelectorAll('.dx-scheduler-appointment')].map( - (element) => createAppointmentModel(element as HTMLDivElement), - ); + const allButtons = this.queries.queryAllByRole('button') as HTMLElement[]; + const appointments = allButtons.filter((btn) => btn.classList.contains('dx-scheduler-appointment')); + return appointments.map((element) => createAppointmentModel(element as HTMLDivElement)); + } + + getCollectorTexts(): string[] { + const allButtons = this.queries.queryAllByRole('button') as HTMLElement[]; + const collectors = allButtons.filter((btn) => btn.classList.contains('dx-scheduler-appointment-collector')); + return getTexts(collectors); } getDateTableContent(): string[] { diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/toolbar.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/toolbar.ts index 4b02fa69eaf5..6d5236fd3292 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/toolbar.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/toolbar.ts @@ -1,15 +1,20 @@ +import { within } from '@testing-library/dom'; + export class ToolbarModel { - element: HTMLDivElement | null; + element: HTMLElement; + + private readonly queries: ReturnType; - constructor(element: HTMLDivElement | null) { + constructor(element: HTMLElement) { this.element = element; + this.queries = within(element); } - getPrevButton(): HTMLDivElement | null | undefined { - return this.element?.querySelector('.dx-scheduler-navigator-previous'); + getPrevButton(): HTMLElement { + return this.queries.getByRole('button', { name: 'Previous page' }) as HTMLElement; } - getNextButton(): HTMLDivElement | null | undefined { - return this.element?.querySelector('.dx-scheduler-navigator-next'); + getNextButton(): HTMLElement { + return this.queries.getByRole('button', { name: 'Next page' }) as HTMLElement; } } diff --git a/packages/devextreme/package.json b/packages/devextreme/package.json index f03cefc1f87b..f3a7724eb7ce 100644 --- a/packages/devextreme/package.json +++ b/packages/devextreme/package.json @@ -84,6 +84,9 @@ "@jest/globals": "29.7.0", "@stylistic/eslint-plugin": "catalog:", "@testcafe-community/axe": "3.5.0", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/user-event": "^14.5.2", "@types/enzyme": "3.10.18", "@types/jquery": "3.5.29", "@types/react": "16.14.34", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5aaab17ecd0e..fe67d6fdbedd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1264,6 +1264,15 @@ importers: '@testcafe-community/axe': specifier: 3.5.0 version: 3.5.0(axe-core@4.11.1)(testcafe@3.7.4) + '@testing-library/dom': + specifier: ^10.4.0 + version: 10.4.0 + '@testing-library/jest-dom': + specifier: ^6.6.3 + version: 6.6.3 + '@testing-library/user-event': + specifier: ^14.5.2 + version: 14.5.2(@testing-library/dom@10.4.0) '@types/enzyme': specifier: 3.10.18 version: 3.10.18 @@ -19011,7 +19020,7 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -19481,7 +19490,7 @@ snapshots: dependencies: '@babel/core': 7.23.9 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -19490,7 +19499,7 @@ snapshots: dependencies: '@babel/core': 7.24.0 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -19499,7 +19508,7 @@ snapshots: dependencies: '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -19508,7 +19517,7 @@ snapshots: dependencies: '@babel/core': 7.26.9 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -19665,7 +19674,7 @@ snapshots: '@babel/highlight@7.25.9': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -21581,12 +21590,12 @@ snapshots: '@babel/types@7.27.1': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/types@7.28.5': dependencies: @@ -27032,7 +27041,7 @@ snapshots: babel-plugin-macros@2.8.0: dependencies: - '@babel/runtime': 7.26.10 + '@babel/runtime': 7.28.6 cosmiconfig: 6.0.0 resolve: 1.22.10 @@ -37263,7 +37272,7 @@ snapshots: regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.26.10 + '@babel/runtime': 7.28.6 regex-cache@0.4.4: dependencies: