d5-testing-library 1.9.0-alpha.3 → 1.9.0-alpha.33
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.
- package/README.md +1 -0
- package/dist/FormEdit-VFV53QIZ.mjs +7 -0
- package/dist/ListForm-KIHLT7EU.mjs +7 -0
- package/dist/TreeView-TFBZB2UK.mjs +8 -0
- package/dist/{chunk-IYYD4X7U.mjs → chunk-EFNMD3S7.mjs} +1 -1
- package/dist/{chunk-SDT2W3SL.mjs → chunk-GVYXH7L3.mjs} +1 -1
- package/dist/{chunk-ROHBQLRX.mjs → chunk-RPSLW2WB.mjs} +399 -67
- package/dist/{chunk-GP4LKGNA.mjs → chunk-TSE33S3X.mjs} +175 -38
- package/dist/cjs/d5-testing-library.cjs +3474 -173
- package/dist/cjs/d5-testing-library.d.ts +84 -4
- package/dist/d5-testing-library.d.mts +84 -4
- package/dist/d5-testing-library.legacy-esm.js +2843 -5
- package/dist/d5-testing-library.mjs +2843 -5
- package/package.json +12 -12
- package/dist/FormEdit-3LEWNAX2.mjs +0 -7
- package/dist/ListForm-GQBL7TEK.mjs +0 -7
- package/dist/TreeView-SO5WRZ7F.mjs +0 -8
|
@@ -17,14 +17,15 @@ import {
|
|
|
17
17
|
safeWait,
|
|
18
18
|
staleElementAction,
|
|
19
19
|
waitElementIsClickable_default,
|
|
20
|
-
waitElementIsVisible_default
|
|
21
|
-
|
|
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";
|
|
25
26
|
|
|
26
27
|
// src/pageObjects/elements/Table/elements/Row.ts
|
|
27
|
-
import { By as By3 } from "selenium-webdriver";
|
|
28
|
+
import { By as By3, Key } from "selenium-webdriver";
|
|
28
29
|
|
|
29
30
|
// src/pageObjects/elements/Table/elements/Cell.ts
|
|
30
31
|
import { By as By2 } 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
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
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;
|
|
@@ -153,10 +164,20 @@ var Row = class extends AbstractElementWithParent {
|
|
|
153
164
|
getCellByTitle(title) {
|
|
154
165
|
return this._getCell({ title });
|
|
155
166
|
}
|
|
156
|
-
async select() {
|
|
167
|
+
async select(preserve = false) {
|
|
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));
|
|
172
|
+
if (isSelected && !preserve) {
|
|
173
|
+
await this.driver.actions({ async: true }).keyUp(Key.CONTROL).perform();
|
|
174
|
+
}
|
|
175
|
+
if (preserve && !isSelected) {
|
|
176
|
+
await this.driver.actions({ async: true }).keyDown(Key.CONTROL).perform();
|
|
177
|
+
await click(clickedElement, this.driver);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
await click(clickedElement, this.driver);
|
|
160
181
|
});
|
|
161
182
|
await safeWait(
|
|
162
183
|
async () => {
|
|
@@ -366,7 +387,7 @@ var DXContextMenuList = class extends AbstractDropDownMenuList {
|
|
|
366
387
|
async isVisible() {
|
|
367
388
|
try {
|
|
368
389
|
await waitElementIsVisible_default({
|
|
369
|
-
element: await this.driver.findElement(By5.css(`.dx-overlay-wrapper .dx-
|
|
390
|
+
element: await this.driver.findElement(By5.css(`.dx-overlay-wrapper .dx-context-menu`)),
|
|
370
391
|
driver: this.driver,
|
|
371
392
|
errorMessage: "Cannot find dropdown element"
|
|
372
393
|
});
|
|
@@ -467,13 +488,32 @@ var Table = class extends AbstractElementWithParent {
|
|
|
467
488
|
/**
|
|
468
489
|
* Вибрати рядок по індексу.
|
|
469
490
|
* @param index починається з 0
|
|
491
|
+
* @param preserve boolean який изначає, чи повинні раніше вибрані рядки залишатися вибраними
|
|
470
492
|
*/
|
|
471
|
-
selectRowByIndex(index) {
|
|
472
|
-
return this.getRowByIndex(index).select();
|
|
493
|
+
selectRowByIndex(index, preserve = false) {
|
|
494
|
+
return this.getRowByIndex(index).select(preserve);
|
|
473
495
|
}
|
|
474
|
-
|
|
496
|
+
/**
|
|
497
|
+
* Вибрати масив рядків по індексу.
|
|
498
|
+
* @param indexes починається з 0
|
|
499
|
+
*/
|
|
500
|
+
async selectRowsByIndexes(indexes) {
|
|
501
|
+
for (const index of indexes) {
|
|
502
|
+
await this.selectRowByIndex(index, true);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
getRowElements(timeout) {
|
|
475
506
|
const rowsFullCssSelector = `${this.getFullCssSelector()} ${this.tableContentCssSelector} .dx-row.dx-data-row`;
|
|
476
|
-
|
|
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();
|
|
477
517
|
const result = [];
|
|
478
518
|
rows.forEach((_, index) => {
|
|
479
519
|
const newRow = new Row(
|
|
@@ -559,6 +599,72 @@ var Table = class extends AbstractElementWithParent {
|
|
|
559
599
|
await contextMenu(cellElement, this.driver);
|
|
560
600
|
});
|
|
561
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
|
+
}
|
|
562
668
|
};
|
|
563
669
|
|
|
564
670
|
// src/pageObjects/elements/TableToolbar/ToolbarGroupButton.ts
|
|
@@ -570,6 +676,7 @@ var TOOLBAR_BUTTON_CLASS = "toolbar-button";
|
|
|
570
676
|
var TOOLBAR_BUTTON_TEXT_CLASS = "dx-button-text";
|
|
571
677
|
var getToolbarButtonSelector = (name) => `#${TOOLBAR_BUTTON_CLASS}-${name}`;
|
|
572
678
|
var getToolbarButtonTextSelector = (name) => `${getToolbarButtonSelector(name)} .${TOOLBAR_BUTTON_TEXT_CLASS}`;
|
|
679
|
+
var getToolbarButtonTextByTestIdSelector = (testId) => `${byTestIdCssSelector(testId)} .${TOOLBAR_BUTTON_TEXT_CLASS}`;
|
|
573
680
|
var ToolbarButton = class extends AbstractButton {
|
|
574
681
|
name;
|
|
575
682
|
constructor(parentCssSelector, name, driver) {
|
|
@@ -601,7 +708,8 @@ var ToolbarGroupButton = class extends AbstractButton {
|
|
|
601
708
|
}
|
|
602
709
|
async getTitle() {
|
|
603
710
|
try {
|
|
604
|
-
const
|
|
711
|
+
const buttonTestId = await this.getDataTestId();
|
|
712
|
+
const buttonTextContainer = await this.driver.findElement(By8.css(getToolbarButtonTextByTestIdSelector(buttonTestId)));
|
|
605
713
|
return await buttonTextContainer.getText();
|
|
606
714
|
} catch (_) {
|
|
607
715
|
return null;
|
|
@@ -776,6 +884,14 @@ var ToolbarItem = class extends AbstractElementWithParent {
|
|
|
776
884
|
return false;
|
|
777
885
|
}
|
|
778
886
|
}
|
|
887
|
+
async isPressed() {
|
|
888
|
+
try {
|
|
889
|
+
await this.init();
|
|
890
|
+
return this._button.isPressed();
|
|
891
|
+
} catch (error) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
779
895
|
async getTitle() {
|
|
780
896
|
await this.init();
|
|
781
897
|
return await this._button.getTitle();
|
|
@@ -983,6 +1099,12 @@ var FormFilterField = class extends AbstractEditor {
|
|
|
983
1099
|
const filterOperation = await this.initOperation();
|
|
984
1100
|
return await filterOperation.getIsBlank();
|
|
985
1101
|
}
|
|
1102
|
+
async isReadonly() {
|
|
1103
|
+
return super.isReadonly();
|
|
1104
|
+
}
|
|
1105
|
+
async isDisabled() {
|
|
1106
|
+
return super.isDisabled();
|
|
1107
|
+
}
|
|
986
1108
|
};
|
|
987
1109
|
|
|
988
1110
|
// src/pageObjects/elements/Filters/FilterPanel.ts
|
|
@@ -1084,6 +1206,12 @@ var PanelFilterField = class extends AbstractEditor {
|
|
|
1084
1206
|
const filterOperation = await this.initOperation();
|
|
1085
1207
|
return await filterOperation.getIsBlank();
|
|
1086
1208
|
}
|
|
1209
|
+
async isReadonly() {
|
|
1210
|
+
return super.isReadonly();
|
|
1211
|
+
}
|
|
1212
|
+
async isDisabled() {
|
|
1213
|
+
return super.isDisabled();
|
|
1214
|
+
}
|
|
1087
1215
|
};
|
|
1088
1216
|
|
|
1089
1217
|
// src/pageObjects/elements/Filters/FilterPanel.ts
|
|
@@ -1156,12 +1284,18 @@ var HeaderFilterField = class extends AbstractEditor {
|
|
|
1156
1284
|
async remove(itemText) {
|
|
1157
1285
|
return super.remove(itemText);
|
|
1158
1286
|
}
|
|
1287
|
+
async isReadonly() {
|
|
1288
|
+
return super.isReadonly();
|
|
1289
|
+
}
|
|
1290
|
+
async isDisabled() {
|
|
1291
|
+
return super.isDisabled();
|
|
1292
|
+
}
|
|
1159
1293
|
};
|
|
1160
1294
|
|
|
1161
1295
|
// src/pageObjects/elements/Filters/ColumnFilter.ts
|
|
1162
1296
|
var APPLY_SELECTOR = ".apply-button";
|
|
1163
1297
|
var CANCEL_SELECTOR = ".cancel-button";
|
|
1164
|
-
var HEADER_FILTER_ICON = ".
|
|
1298
|
+
var HEADER_FILTER_ICON = ".indicators-container .filter-icon";
|
|
1165
1299
|
var HEADER_FILTER_CONTAINER = ".header-filter";
|
|
1166
1300
|
var HEADER_FILTER_BUTTONS = ".header-filter-buttons";
|
|
1167
1301
|
var ColumnFilter = class extends AbstractElement {
|
|
@@ -1195,24 +1329,15 @@ var ColumnFilter = class extends AbstractElement {
|
|
|
1195
1329
|
const columnEl = await this._column.getElement();
|
|
1196
1330
|
const actions = this.driver.actions({ async: true });
|
|
1197
1331
|
await actions.move({ origin: columnEl }).perform();
|
|
1198
|
-
const
|
|
1199
|
-
let headerFilterIcon =
|
|
1332
|
+
const headerFilterIconBy = By11.css(HEADER_FILTER_ICON);
|
|
1333
|
+
let headerFilterIcon = await columnEl.findElement(headerFilterIconBy);
|
|
1200
1334
|
await safeWait(
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
for (let element of elements) {
|
|
1204
|
-
if (await element.isDisplayed()) {
|
|
1205
|
-
headerFilterIcon = element;
|
|
1206
|
-
result = true;
|
|
1207
|
-
break;
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
return result;
|
|
1335
|
+
() => {
|
|
1336
|
+
return headerFilterIcon.isDisplayed();
|
|
1211
1337
|
},
|
|
1212
1338
|
this.driver,
|
|
1213
1339
|
`HeaderFilter "${this._name}" is not visible`
|
|
1214
1340
|
);
|
|
1215
|
-
if (!headerFilterIcon) throw new Error(`HeaderFilter "${this._name}" is not visible`);
|
|
1216
1341
|
await click(headerFilterIcon, this.driver);
|
|
1217
1342
|
const filter = new HeaderFilterField("", this._formName, this._name, this.driver);
|
|
1218
1343
|
const filterEl = await filter.getElement();
|
|
@@ -1332,6 +1457,18 @@ var ColumnFilter = class extends AbstractElement {
|
|
|
1332
1457
|
const filterOperation = await this.initOperation();
|
|
1333
1458
|
return await filterOperation.getIsBlank();
|
|
1334
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
|
+
}
|
|
1335
1472
|
};
|
|
1336
1473
|
|
|
1337
1474
|
// src/pageObjects/elements/Forms/ListForm.ts
|