d5-testing-library 1.9.0-alpha.8 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,8 +17,9 @@ import {
17
17
  safeWait,
18
18
  staleElementAction,
19
19
  waitElementIsClickable_default,
20
- waitElementIsVisible_default
21
- } from "./chunk-7WV6OWRZ.mjs";
20
+ waitElementIsVisible_default,
21
+ withCustomTimeouts_default
22
+ } from "./chunk-RPSLW2WB.mjs";
22
23
 
23
24
  // src/pageObjects/elements/Table/Table.ts
24
25
  import { By as By6 } from "selenium-webdriver";
@@ -76,21 +77,30 @@ var Cell = class extends AbstractElementWithParent {
76
77
  async getDateValue(cellEl, cellElClass) {
77
78
  const value = (await cellEl.getText()).trim();
78
79
  if (value === "") return null;
79
- const isWithTime = cellElClass.includes("with-time");
80
- try {
81
- if (isWithTime) {
82
- const [datePart, timePart] = value.split(", ");
83
- const [day, month, year] = datePart.split(".").map(Number);
84
- const [hours, minutes] = timePart.split(":").map(Number);
85
- return new Date(Date.UTC(year, month - 1, day, hours, minutes));
86
- } else {
87
- const [day, month, year] = value.split(".").map(Number);
88
- return new Date(Date.UTC(year, month - 1, day));
80
+ const getDate = (stringDate) => {
81
+ const isWithTime = cellElClass.includes("with-time");
82
+ try {
83
+ if (isWithTime) {
84
+ const [datePart, timePart] = stringDate.split(", ");
85
+ const [day, month, year] = datePart.split(".").map(Number);
86
+ const [hours, minutes] = timePart.split(":").map(Number);
87
+ return new Date(year, month - 1, day, hours, minutes, 0, 0);
88
+ } else {
89
+ const [day, month, year] = stringDate.split(".").map(Number);
90
+ return new Date(Date.UTC(year, month - 1, day));
91
+ }
92
+ } catch (error) {
93
+ console.error(`Error parsing date value "${stringDate}":`, error);
94
+ return null;
89
95
  }
90
- } catch (error) {
91
- console.error(`Error parsing date value "${value}":`, error);
92
- return null;
96
+ };
97
+ const periodValue = value.split(" - ");
98
+ if (periodValue.length > 1) {
99
+ const dateFrom = getDate(periodValue[0]);
100
+ const dateTo = getDate(periodValue[1]);
101
+ return [dateFrom, dateTo];
93
102
  }
103
+ return getDate(value);
94
104
  }
95
105
  async getElement() {
96
106
  if (this._index == null) {
@@ -117,6 +127,7 @@ var Cell = class extends AbstractElementWithParent {
117
127
  var DX_SELECTION_CLASS = "dx-selection";
118
128
  var DX_ROW_EDIT_CLASS = "dx-edit-row";
119
129
  var DX_DATA_ROW_CLASS = "dx-data-row";
130
+ var FIRST_CLICKED_CELL_SELECTOR = 'td[aria-colindex="1"]';
120
131
  var Row = class extends AbstractElementWithParent {
121
132
  index;
122
133
  getColumnBy;
@@ -157,15 +168,16 @@ var Row = class extends AbstractElementWithParent {
157
168
  await staleElementAction(async () => {
158
169
  const rowEl = await this.getElement();
159
170
  const isSelected = (await this.getClasses()).includes(DX_SELECTION_CLASS);
171
+ const clickedElement = await rowEl.findElement(By3.css(FIRST_CLICKED_CELL_SELECTOR));
160
172
  if (isSelected && !preserve) {
161
173
  await this.driver.actions({ async: true }).keyUp(Key.CONTROL).perform();
162
174
  }
163
175
  if (preserve && !isSelected) {
164
176
  await this.driver.actions({ async: true }).keyDown(Key.CONTROL).perform();
165
- await click(rowEl, this.driver);
177
+ await click(clickedElement, this.driver);
166
178
  return;
167
179
  }
168
- await click(rowEl, this.driver);
180
+ await click(clickedElement, this.driver);
169
181
  });
170
182
  await safeWait(
171
183
  async () => {
@@ -490,9 +502,18 @@ var Table = class extends AbstractElementWithParent {
490
502
  await this.selectRowByIndex(index, true);
491
503
  }
492
504
  }
493
- async getRows() {
505
+ getRowElements(timeout) {
494
506
  const rowsFullCssSelector = `${this.getFullCssSelector()} ${this.tableContentCssSelector} .dx-row.dx-data-row`;
495
- const rows = await this.driver.findElements(By6.css(rowsFullCssSelector));
507
+ return withCustomTimeouts_default({
508
+ driver: this.driver,
509
+ timeout,
510
+ callback: () => {
511
+ return this.driver.findElements(By6.css(rowsFullCssSelector));
512
+ }
513
+ });
514
+ }
515
+ async getRows() {
516
+ const rows = await this.getRowElements();
496
517
  const result = [];
497
518
  rows.forEach((_, index) => {
498
519
  const newRow = new Row(
@@ -578,6 +599,72 @@ var Table = class extends AbstractElementWithParent {
578
599
  await contextMenu(cellElement, this.driver);
579
600
  });
580
601
  }
602
+ /**
603
+ * Отримує значення комірки таблиці за ім'ям комірки та індексом рядка.
604
+ *
605
+ * @param {string} cellName - Ім'я комірки (поля) в таблиці
606
+ * @param {number} rowIndex - Індекс рядка (починається з 0)
607
+ * @throws {Error} Викидає помилку, якщо rowIndex не вказано
608
+ * @returns {Promise<string>} Повертає значення комірки
609
+ *
610
+ * @example
611
+ * const table = new Table(driver);
612
+ *
613
+ * // Отримання значення комірки 'Name' в першому рядку (індекс 0)
614
+ * const cellValue = await table.getCellValueByCellName('Name', 0);
615
+ * expect(cellValue).toBe('Очікуване значення');
616
+ */
617
+ getCellValueByCellName(cellName, rowIndex) {
618
+ if (rowIndex == null) {
619
+ throw new Error("Error: getCellValue(): rowIndex is required");
620
+ }
621
+ const row = this.getRowByIndex(rowIndex);
622
+ return row.getCell(cellName).getValue();
623
+ }
624
+ /**
625
+ * Перевіряє, чи є таблиця порожньою (не містить жодного рядка з даними).
626
+ *
627
+ * @returns {Promise<boolean>} Повертає true, якщо таблиця порожня, false - якщо містить рядки
628
+ *
629
+ * @example
630
+ * const table = new Table(driver);
631
+ *
632
+ * // Перевірка чи порожня таблиця
633
+ * const empty = await table.isEmpty();
634
+ * expect(empty).toBe(true);
635
+ */
636
+ async isEmpty() {
637
+ try {
638
+ await this.waitRowsCount(0);
639
+ return true;
640
+ } catch {
641
+ return false;
642
+ }
643
+ }
644
+ /**
645
+ * Очікує, поки кількість рядків у таблиці не стане рівною заданому значенню.
646
+ * Використовується для синхронізації тестів з динамічним завантаженням даних.
647
+ *
648
+ * @param {number} count - Очікувана кількість рядків у таблиці
649
+ * @returns {Promise<void>} Повертає Promise, який виконується, коли кількість рядків відповідає очікуваній
650
+ * @throws {Error} Викидає помилку, якщо очікування перевищує тайм-аут
651
+ *
652
+ * @example
653
+ * const table = new Table(driver);
654
+ *
655
+ * // Очікування, поки таблиця не стане порожньою
656
+ * await table.waitRowsCount(0);
657
+ *
658
+ * // Очікування, поки в таблиці не з'явиться 5 рядків
659
+ * await table.waitRowsCount(5);
660
+ * console.log('Таблиця містить 5 рядків');
661
+ */
662
+ async waitRowsCount(count) {
663
+ await safeWait(async () => {
664
+ const rows = await this.getRowElements(1e3);
665
+ return rows.length === count;
666
+ }, this.driver, `Rows count not equal: ${count}`);
667
+ }
581
668
  };
582
669
 
583
670
  // src/pageObjects/elements/TableToolbar/ToolbarGroupButton.ts
@@ -589,6 +676,7 @@ var TOOLBAR_BUTTON_CLASS = "toolbar-button";
589
676
  var TOOLBAR_BUTTON_TEXT_CLASS = "dx-button-text";
590
677
  var getToolbarButtonSelector = (name) => `#${TOOLBAR_BUTTON_CLASS}-${name}`;
591
678
  var getToolbarButtonTextSelector = (name) => `${getToolbarButtonSelector(name)} .${TOOLBAR_BUTTON_TEXT_CLASS}`;
679
+ var getToolbarButtonTextByTestIdSelector = (testId) => `${byTestIdCssSelector(testId)} .${TOOLBAR_BUTTON_TEXT_CLASS}`;
592
680
  var ToolbarButton = class extends AbstractButton {
593
681
  name;
594
682
  constructor(parentCssSelector, name, driver) {
@@ -620,7 +708,8 @@ var ToolbarGroupButton = class extends AbstractButton {
620
708
  }
621
709
  async getTitle() {
622
710
  try {
623
- const buttonTextContainer = await this.driver.findElement(By8.css(getToolbarButtonTextSelector(this.name)));
711
+ const buttonTestId = await this.getDataTestId();
712
+ const buttonTextContainer = await this.driver.findElement(By8.css(getToolbarButtonTextByTestIdSelector(buttonTestId)));
624
713
  return await buttonTextContainer.getText();
625
714
  } catch (_) {
626
715
  return null;
@@ -1010,6 +1099,12 @@ var FormFilterField = class extends AbstractEditor {
1010
1099
  const filterOperation = await this.initOperation();
1011
1100
  return await filterOperation.getIsBlank();
1012
1101
  }
1102
+ async isReadonly() {
1103
+ return super.isReadonly();
1104
+ }
1105
+ async isDisabled() {
1106
+ return super.isDisabled();
1107
+ }
1013
1108
  };
1014
1109
 
1015
1110
  // src/pageObjects/elements/Filters/FilterPanel.ts
@@ -1111,6 +1206,12 @@ var PanelFilterField = class extends AbstractEditor {
1111
1206
  const filterOperation = await this.initOperation();
1112
1207
  return await filterOperation.getIsBlank();
1113
1208
  }
1209
+ async isReadonly() {
1210
+ return super.isReadonly();
1211
+ }
1212
+ async isDisabled() {
1213
+ return super.isDisabled();
1214
+ }
1114
1215
  };
1115
1216
 
1116
1217
  // src/pageObjects/elements/Filters/FilterPanel.ts
@@ -1183,12 +1284,18 @@ var HeaderFilterField = class extends AbstractEditor {
1183
1284
  async remove(itemText) {
1184
1285
  return super.remove(itemText);
1185
1286
  }
1287
+ async isReadonly() {
1288
+ return super.isReadonly();
1289
+ }
1290
+ async isDisabled() {
1291
+ return super.isDisabled();
1292
+ }
1186
1293
  };
1187
1294
 
1188
1295
  // src/pageObjects/elements/Filters/ColumnFilter.ts
1189
1296
  var APPLY_SELECTOR = ".apply-button";
1190
1297
  var CANCEL_SELECTOR = ".cancel-button";
1191
- var HEADER_FILTER_ICON = ".dx-column-indicators .dx-header-filter";
1298
+ var HEADER_FILTER_ICON = ".indicators-container .filter-icon";
1192
1299
  var HEADER_FILTER_CONTAINER = ".header-filter";
1193
1300
  var HEADER_FILTER_BUTTONS = ".header-filter-buttons";
1194
1301
  var ColumnFilter = class extends AbstractElement {
@@ -1222,24 +1329,15 @@ var ColumnFilter = class extends AbstractElement {
1222
1329
  const columnEl = await this._column.getElement();
1223
1330
  const actions = this.driver.actions({ async: true });
1224
1331
  await actions.move({ origin: columnEl }).perform();
1225
- const elements = await columnEl.findElements(By11.css(HEADER_FILTER_ICON));
1226
- let headerFilterIcon = null;
1332
+ const headerFilterIconBy = By11.css(HEADER_FILTER_ICON);
1333
+ let headerFilterIcon = await columnEl.findElement(headerFilterIconBy);
1227
1334
  await safeWait(
1228
- async () => {
1229
- let result = false;
1230
- for (let element of elements) {
1231
- if (await element.isDisplayed()) {
1232
- headerFilterIcon = element;
1233
- result = true;
1234
- break;
1235
- }
1236
- }
1237
- return result;
1335
+ () => {
1336
+ return headerFilterIcon.isDisplayed();
1238
1337
  },
1239
1338
  this.driver,
1240
1339
  `HeaderFilter "${this._name}" is not visible`
1241
1340
  );
1242
- if (!headerFilterIcon) throw new Error(`HeaderFilter "${this._name}" is not visible`);
1243
1341
  await click(headerFilterIcon, this.driver);
1244
1342
  const filter = new HeaderFilterField("", this._formName, this._name, this.driver);
1245
1343
  const filterEl = await filter.getElement();
@@ -1359,6 +1457,18 @@ var ColumnFilter = class extends AbstractElement {
1359
1457
  const filterOperation = await this.initOperation();
1360
1458
  return await filterOperation.getIsBlank();
1361
1459
  }
1460
+ async isReadonly() {
1461
+ const filter = await this.initFilter();
1462
+ const result = await filter.isReadonly();
1463
+ await this.cancel();
1464
+ return result;
1465
+ }
1466
+ async isDisabled() {
1467
+ const filter = await this.initFilter();
1468
+ const result = await filter.isDisabled();
1469
+ await this.cancel();
1470
+ return result;
1471
+ }
1362
1472
  };
1363
1473
 
1364
1474
  // src/pageObjects/elements/Forms/ListForm.ts