d5-testing-library 2.0.0-alpha.1 → 2.0.0-alpha.11

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.
@@ -76,11 +76,14 @@ var init_AbstractElement = __esm({
76
76
  joinRelativeCssSelectors(selectors) {
77
77
  return selectors.join(" ");
78
78
  }
79
- getLocator() {
79
+ syncLocator() {
80
80
  return this.page.locator(`css=${this.getFullCssSelector()}`);
81
81
  }
82
+ getLocator() {
83
+ return this.syncLocator();
84
+ }
82
85
  async getAttribute(attr) {
83
- const locator = this.getLocator();
86
+ const locator = this.syncLocator();
84
87
  if (await locator.isVisible()) {
85
88
  return locator.getAttribute(attr);
86
89
  }
@@ -329,7 +332,7 @@ var init_AbstractEditor = __esm({
329
332
  async setInputValue(value) {
330
333
  const input = this.getInputLocator();
331
334
  await input.click();
332
- await input.fill(value + "");
335
+ await input.pressSequentially(value + "");
333
336
  await input.press("Enter");
334
337
  }
335
338
  async clear() {
@@ -403,6 +406,7 @@ var init_types = __esm({
403
406
  ControlClass2["BooleanSelector"] = "buttons-group";
404
407
  ControlClass2["ButtonGroup"] = "button-group-field";
405
408
  ControlClass2["HeaderFilterDictionary"] = "header-filter-dictionary";
409
+ ControlClass2["FileUploader"] = "file-uploader";
406
410
  return ControlClass2;
407
411
  })(ControlClass || {});
408
412
  }
@@ -453,7 +457,7 @@ var init_xpathHelper = __esm({
453
457
  "use strict";
454
458
  XPathHelper = class {
455
459
  static getClassAndValueXpath(cssClass, value) {
456
- return `div[contains(@class, '${cssClass}') and contains(.,'${value}')]`;
460
+ return `div[contains(@class, '${cssClass}') and .='${value}']`;
457
461
  }
458
462
  };
459
463
  }
@@ -470,7 +474,7 @@ function isEmptyValue(value) {
470
474
  }
471
475
  return false;
472
476
  }
473
- var types, isObject, isEmptyObject, type, isNull, isArray, isDefined, isString, isDate, isArrayOfDates, isUndefined;
477
+ var types, isObject, isEmptyObject, type, isNull, isArray, isDefined, isString, isNumeric, isDate, isArrayOfDates, isUndefined;
474
478
  var init_typesUtil = __esm({
475
479
  "src/utils/typesUtil.ts"() {
476
480
  "use strict";
@@ -503,6 +507,9 @@ var init_typesUtil = __esm({
503
507
  isString = function(object) {
504
508
  return typeof object === "string";
505
509
  };
510
+ isNumeric = function(object) {
511
+ return typeof object === "number" && isFinite(object) || !isNaN(object - parseFloat(object));
512
+ };
506
513
  isDate = function(object) {
507
514
  return type(object) === "date";
508
515
  };
@@ -552,7 +559,7 @@ var init_SelectBoxEditor = __esm({
552
559
  const inputEl = this.getInputLocator();
553
560
  await inputEl.click();
554
561
  try {
555
- await inputEl.fill(value);
562
+ await inputEl.pressSequentially(value + "");
556
563
  await inputEl.press("Enter");
557
564
  await dropDownOptionClick(value, this.page, false);
558
565
  } catch {
@@ -655,12 +662,12 @@ var init_TagBox = __esm({
655
662
  try {
656
663
  await dropDownOptionClick(value, this.page, false);
657
664
  } catch {
658
- await input.fill(value);
665
+ await input.pressSequentially(value + "");
659
666
  await dropDownOptionClick(value, this.page, true);
660
667
  }
661
668
  await this.waitOptionSelection(value);
662
669
  if (value !== lastElement) {
663
- await input.fill("");
670
+ await input.pressSequentially("");
664
671
  }
665
672
  }
666
673
  async confirmSelection() {
@@ -1057,7 +1064,6 @@ var init_SingleDateEditor = __esm({
1057
1064
  init_BaseDateEditor();
1058
1065
  init_utils();
1059
1066
  init_ClearButtonStrategy();
1060
- init_src();
1061
1067
  SingleDateEditor = class extends BaseDateEditor {
1062
1068
  constructor(parentCssSelector, elementCssSelector, page) {
1063
1069
  super(parentCssSelector, elementCssSelector, page);
@@ -1080,11 +1086,7 @@ var init_SingleDateEditor = __esm({
1080
1086
  }
1081
1087
  async setValue(value) {
1082
1088
  if (value instanceof Date) {
1083
- await wait(async () => {
1084
- await this.setDateValue(value);
1085
- const updatedValue = await this.getValue();
1086
- return updatedValue.toDateString() === value.toDateString();
1087
- }, this.page);
1089
+ await this.setDateValue(value);
1088
1090
  } else {
1089
1091
  throw new Error(`Value is incorrect. It should be a Date object`);
1090
1092
  }
@@ -1180,7 +1182,7 @@ var init_DateEditor = __esm({
1180
1182
  });
1181
1183
 
1182
1184
  // src/pageObjects/elements/Editors/HeaderFilterDictionary.ts
1183
- var TAGS_SELECTOR2, DX_TAG_CONTAINER2, DX_TEXTEDITOR_EMPTY3, CUSTOM_OPTION_LIST_SELECTOR, SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2, TAG_BOX_LIST_ITEM_SELECTOR, combinedOptionHeaderFilterDictValueXpath, dropDownHeaderFilterDictionaryOptionClick, HeaderFilterDictionary;
1185
+ var TAGS_SELECTOR2, DX_TAG_CONTAINER2, DX_TEXTEDITOR_EMPTY3, CUSTOM_OPTION_LIST_SELECTOR, SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2, TAG_BOX_LIST_ITEM_SELECTOR, dropDownHeaderFilterDictionaryOptionClick, HeaderFilterDictionary;
1184
1186
  var init_HeaderFilterDictionary = __esm({
1185
1187
  "src/pageObjects/elements/Editors/HeaderFilterDictionary.ts"() {
1186
1188
  "use strict";
@@ -1193,12 +1195,11 @@ var init_HeaderFilterDictionary = __esm({
1193
1195
  CUSTOM_OPTION_LIST_SELECTOR = "custom-list";
1194
1196
  SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2 = "d5-multi-select-item";
1195
1197
  TAG_BOX_LIST_ITEM_SELECTOR = '.dx-overlay-wrapper .dx-list-item[aria-selected="true"]';
1196
- combinedOptionHeaderFilterDictValueXpath = (value) => `//div[contains(@class, '${SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2}') and contains(text(), '${value}')]`;
1197
1198
  dropDownHeaderFilterDictionaryOptionClick = async (optionValue, page, dataTEST = "", delay = true) => {
1198
1199
  const calendarPopoverSelector = byTestIdCssSelector(`${dataTEST}`);
1199
1200
  const calendarPopover = page.locator(calendarPopoverSelector);
1200
1201
  const customOptionList = calendarPopover.locator(`.${CUSTOM_OPTION_LIST_SELECTOR}`);
1201
- const optElement = customOptionList.locator(`xpath=${combinedOptionHeaderFilterDictValueXpath(optionValue)}`);
1202
+ const optElement = customOptionList.locator(`.${SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2}`, { hasText: optionValue });
1202
1203
  try {
1203
1204
  await optElement.waitFor({ state: "visible", timeout: delay ? void 0 : 600 });
1204
1205
  await optElement.click();
@@ -1222,28 +1223,28 @@ var init_HeaderFilterDictionary = __esm({
1222
1223
  await this.selectOption(inputEl, value, lastElement);
1223
1224
  }
1224
1225
  }
1225
- async waitOptionSelection() {
1226
- const selectedItem = this.page.locator(TAG_BOX_LIST_ITEM_SELECTOR);
1227
- await selectedItem.waitFor({ state: "visible" });
1226
+ async waitOptionSelection(value) {
1227
+ await this.page.locator(`${TAG_BOX_LIST_ITEM_SELECTOR}`).filter({ hasText: value }).first().waitFor({ state: "visible" });
1228
1228
  }
1229
1229
  async selectOption(inputEl, value, lastElement) {
1230
1230
  try {
1231
- await inputEl.fill(value);
1231
+ await inputEl.pressSequentially(value + "");
1232
1232
  const dataTEST = await this.getDataTestId();
1233
1233
  await dropDownHeaderFilterDictionaryOptionClick(value, this.page, dataTEST);
1234
1234
  if (value !== lastElement) {
1235
- await inputEl.fill("");
1235
+ await inputEl.pressSequentially("");
1236
1236
  }
1237
1237
  } catch (error) {
1238
1238
  throw error;
1239
1239
  }
1240
- await this.waitOptionSelection();
1240
+ await this.waitOptionSelection(value);
1241
1241
  }
1242
1242
  async getHeaderFilterDictionaryInputValue() {
1243
1243
  if (await this.isHeaderFilterDictionaryEmpty()) {
1244
1244
  return [];
1245
1245
  }
1246
1246
  const tags = this.page.locator(`${this.getFullCssSelector()} .${DX_TAG_CONTAINER2} ${TAGS_SELECTOR2}`);
1247
+ await tags.first().waitFor({ state: "visible" });
1247
1248
  const count = await tags.count();
1248
1249
  const values = [];
1249
1250
  for (let i = 0; i < count; i++) {
@@ -1269,6 +1270,130 @@ var init_HeaderFilterDictionary = __esm({
1269
1270
  }
1270
1271
  });
1271
1272
 
1273
+ // src/pageObjects/elements/Editors/FileUploader.ts
1274
+ var FILE_NAME_SELECTOR, FILE_SIZE_ATTRIBUTE, FILE_DATE_ATTRIBUTE, FILE_TYPE_ATTRIBUTE, SELECT_FILE_BUTTON_SELECTOR, DOWNLOAD_FILE_BUTTON_SELECTOR, METADATA_SELECTOR, CLEAR_BUTTON_SELECTOR, FileUploader;
1275
+ var init_FileUploader = __esm({
1276
+ "src/pageObjects/elements/Editors/FileUploader.ts"() {
1277
+ "use strict";
1278
+ init_AbstractElementWithParent();
1279
+ init_typesUtil();
1280
+ FILE_NAME_SELECTOR = ".file-text";
1281
+ FILE_SIZE_ATTRIBUTE = "data-filesize";
1282
+ FILE_DATE_ATTRIBUTE = "data-moddate";
1283
+ FILE_TYPE_ATTRIBUTE = "data-filetype";
1284
+ SELECT_FILE_BUTTON_SELECTOR = ".select-file-button";
1285
+ DOWNLOAD_FILE_BUTTON_SELECTOR = ".download-file-button";
1286
+ METADATA_SELECTOR = ".file-text-file-info-wrapper";
1287
+ CLEAR_BUTTON_SELECTOR = ".clear-button";
1288
+ FileUploader = class extends AbstractElementWithParent {
1289
+ constructor(parentCssSelector, elementCssSelector, page) {
1290
+ super(parentCssSelector, elementCssSelector, page);
1291
+ }
1292
+ /**
1293
+ * Returns the metadata container element for the uploaded file.
1294
+ * Returns null when metadata is not rendered or not visible.
1295
+ */
1296
+ async getMedataElement() {
1297
+ const root = this.getFullCssSelector();
1298
+ const locator = this.page.locator(`${root} ${METADATA_SELECTOR}`);
1299
+ if (!await locator.isVisible()) return null;
1300
+ return locator;
1301
+ }
1302
+ /**
1303
+ * Returns the name of the uploaded file, or null if not present.
1304
+ */
1305
+ async getFileName() {
1306
+ const root = this.getFullCssSelector();
1307
+ const locator = this.page.locator(`${root} ${FILE_NAME_SELECTOR}`);
1308
+ if (!await locator.isVisible()) return null;
1309
+ const text = await locator.innerText();
1310
+ return text?.trim() || null;
1311
+ }
1312
+ /**
1313
+ * Returns the size of the uploaded file, or null if not present.
1314
+ */
1315
+ async getFileSize() {
1316
+ const element = await this.getMedataElement();
1317
+ if (!element) return null;
1318
+ const result = (await element.getAttribute(FILE_SIZE_ATTRIBUTE))?.trim();
1319
+ return isNaN(+result) ? null : +result;
1320
+ }
1321
+ /**
1322
+ * Returns the upload/modification date of the file, or null if not present.
1323
+ */
1324
+ async getFileDate() {
1325
+ const element = await this.getMedataElement();
1326
+ if (!element) return null;
1327
+ const fileModDate = (await element.getAttribute(FILE_DATE_ATTRIBUTE))?.trim();
1328
+ if (isNumeric(+fileModDate)) {
1329
+ const dateString = (/* @__PURE__ */ new Date(+fileModDate)).toISOString();
1330
+ return new Date(dateString.split("T")[0]);
1331
+ }
1332
+ return fileModDate ? new Date(fileModDate.split("T")[0]) : null;
1333
+ }
1334
+ /**
1335
+ * Returns the MIME/content type of the uploaded file from metadata.
1336
+ * Returns null when the type attribute is absent or empty.
1337
+ */
1338
+ async getFileType() {
1339
+ const element = await this.getMedataElement();
1340
+ if (!element) return null;
1341
+ const fileType = (await element.getAttribute(FILE_TYPE_ATTRIBUTE))?.trim();
1342
+ return fileType || null;
1343
+ }
1344
+ /**
1345
+ * Returns current file information: name, size and upload/modification date.
1346
+ * Returns null if no file is uploaded.
1347
+ */
1348
+ async getValue() {
1349
+ const name = await this.getFileName();
1350
+ const size = await this.getFileSize();
1351
+ const date = await this.getFileDate();
1352
+ const type2 = await this.getFileType();
1353
+ if (!name && !size && !date && !type2) return null;
1354
+ return { FileName: name, FileSize: size, FileType: type2, ModDate: date };
1355
+ }
1356
+ /**
1357
+ * Uploads a file by clicking the select-file-button and providing the file path.
1358
+ * @param filePath - Absolute or relative path to the file on disk.
1359
+ */
1360
+ async setValue(filePath) {
1361
+ const root = this.getFullCssSelector();
1362
+ const fileChooserPromise = this.page.waitForEvent("filechooser");
1363
+ await this.page.locator(`${root} ${SELECT_FILE_BUTTON_SELECTOR}`).click();
1364
+ const fileChooser = await fileChooserPromise;
1365
+ await fileChooser.setFiles(filePath);
1366
+ }
1367
+ /**
1368
+ * Downloads the currently uploaded file by clicking the download-file-button.
1369
+ * Returns the suggested file name of the downloaded file.
1370
+ */
1371
+ async download() {
1372
+ const root = this.getFullCssSelector();
1373
+ const buttonLocator = this.page.locator(
1374
+ `${root} ${DOWNLOAD_FILE_BUTTON_SELECTOR}`
1375
+ );
1376
+ if (await buttonLocator.isHidden()) return "";
1377
+ const downloadPromise = this.page.waitForEvent("download");
1378
+ await buttonLocator.click();
1379
+ const download = await downloadPromise;
1380
+ return download.suggestedFilename();
1381
+ }
1382
+ /**
1383
+ * Removes the currently uploaded file by clicking the delete-file-button.
1384
+ * Does nothing if no file is uploaded.
1385
+ */
1386
+ async clear() {
1387
+ if (await this.getValue() === null) return;
1388
+ const root = this.getFullCssSelector();
1389
+ const deleteButton = this.page.locator(`${root} ${CLEAR_BUTTON_SELECTOR}`);
1390
+ if (await deleteButton.isHidden()) return;
1391
+ await deleteButton.click();
1392
+ }
1393
+ };
1394
+ }
1395
+ });
1396
+
1272
1397
  // src/pageObjects/elements/Editors/editorFactory.ts
1273
1398
  var editorFactory;
1274
1399
  var init_editorFactory = __esm({
@@ -1286,6 +1411,7 @@ var init_editorFactory = __esm({
1286
1411
  init_ButtonGroup();
1287
1412
  init_DateEditor();
1288
1413
  init_HeaderFilterDictionary();
1414
+ init_FileUploader();
1289
1415
  editorFactory = async (parentCssSelector, elementCssSelector, page) => {
1290
1416
  const elementInstance = new AbstractFormElement(parentCssSelector, elementCssSelector, page);
1291
1417
  const classString = await elementInstance.getClasses();
@@ -1306,6 +1432,8 @@ var init_editorFactory = __esm({
1306
1432
  return new ButtonGroup(parentCssSelector, elementCssSelector, page);
1307
1433
  if (classString.includes("header-filter-dictionary" /* HeaderFilterDictionary */))
1308
1434
  return new HeaderFilterDictionary(parentCssSelector, elementCssSelector, page);
1435
+ if (classString.includes("file-uploader" /* FileUploader */))
1436
+ return new FileUploader(parentCssSelector, elementCssSelector, page);
1309
1437
  throw new Error("Unknown type of editor. Please write ticket to the support");
1310
1438
  };
1311
1439
  }
@@ -1385,6 +1513,15 @@ function createSubSystemTestId(itemName) {
1385
1513
  function createEditorButtonTestId(itemName) {
1386
1514
  return `${"editor-button" /* EDITOR_BUTTON */}-${itemName}`;
1387
1515
  }
1516
+ function createLabelFieldTestId(formName, itemName) {
1517
+ return `${"label" /* LABEL */}-${createFieldTestId(formName, itemName)}`;
1518
+ }
1519
+ function createLabelDocFilterTestId(formName, itemName) {
1520
+ return `${"label" /* LABEL */}-${createDocFilterTestId(formName, itemName)}`;
1521
+ }
1522
+ function createLabelLayoutFilterTestId(formName, itemName) {
1523
+ return `${"label" /* LABEL */}-${createLayoutFilterTestId(formName, itemName)}`;
1524
+ }
1388
1525
  var init_createDataTestId = __esm({
1389
1526
  "src/utils/createDataTestId.ts"() {
1390
1527
  "use strict";
@@ -1863,7 +2000,7 @@ var init_AbstractForm = __esm({
1863
2000
  async exists() {
1864
2001
  try {
1865
2002
  const container = this.page.locator(this.containerCssSelector);
1866
- await waitElementIsVisible_default({ locator: container });
2003
+ await waitElementIsVisible_default({ locator: container, timeout: 3e3 });
1867
2004
  return true;
1868
2005
  } catch (error) {
1869
2006
  return false;
@@ -1996,14 +2133,14 @@ var init_Cell = __esm({
1996
2133
  }
1997
2134
  return getDate(value);
1998
2135
  }
1999
- async element() {
2136
+ async getLocator() {
2000
2137
  if (this._index == null) {
2001
2138
  this.index = await this.getCellIndex();
2002
2139
  }
2003
- return this.getLocator();
2140
+ return this.syncLocator();
2004
2141
  }
2005
2142
  async getValue() {
2006
- const cellEl = await this.element();
2143
+ const cellEl = await this.getLocator();
2007
2144
  const cellElClass = await cellEl.getAttribute("class") ?? "";
2008
2145
  if (cellElClass.includes("boolean-column" /* Boolean */)) return this.getBooleanValue(cellEl);
2009
2146
  if (cellElClass.includes("tags-column" /* Tags */)) return this.getTagsValue(cellEl);
@@ -2151,9 +2288,9 @@ var init_Column = __esm({
2151
2288
  constructor({ parentCssSelector, headerCssSelector, name, caption, index, page }) {
2152
2289
  super(parentCssSelector, "", page);
2153
2290
  this._name = name;
2291
+ this.headerCssSelector = headerCssSelector;
2154
2292
  this.index = index;
2155
2293
  this._caption = caption;
2156
- this.headerCssSelector = headerCssSelector;
2157
2294
  }
2158
2295
  set index(index) {
2159
2296
  this._index = index;
@@ -2162,9 +2299,9 @@ var init_Column = __esm({
2162
2299
  get index() {
2163
2300
  return this._index;
2164
2301
  }
2165
- async element() {
2302
+ async getLocator() {
2166
2303
  await this.getIndex();
2167
- return this.getLocator();
2304
+ return this.syncLocator();
2168
2305
  }
2169
2306
  async getColumnHeaderIndexBy(cssSelector) {
2170
2307
  const column = this.page.locator(`${this.parentCssSelector} ${this.headerCssSelector} ${cssSelector}`);
@@ -2177,7 +2314,7 @@ var init_Column = __esm({
2177
2314
  return this.getColumnHeaderIndexBy(getColumnByNameCssSelector(this._name));
2178
2315
  }
2179
2316
  async caption() {
2180
- const el = await this.element();
2317
+ const el = await this.getLocator();
2181
2318
  const text = await el.innerText();
2182
2319
  return text?.trim() ?? null;
2183
2320
  }
@@ -2230,6 +2367,25 @@ var init_EditorButton = __esm({
2230
2367
  }
2231
2368
  });
2232
2369
 
2370
+ // src/pageObjects/elements/EditorTitle.ts
2371
+ var CAPTION_TEXT_CLASS, EditorTitle;
2372
+ var init_EditorTitle = __esm({
2373
+ "src/pageObjects/elements/EditorTitle.ts"() {
2374
+ "use strict";
2375
+ init_AbstractElementWithParent();
2376
+ CAPTION_TEXT_CLASS = " .caption-text";
2377
+ EditorTitle = class extends AbstractElementWithParent {
2378
+ constructor({ parentCssSelector, elementCssSelector, page }) {
2379
+ super(parentCssSelector, elementCssSelector, page);
2380
+ }
2381
+ async getTitle() {
2382
+ const captionElement = this.getLocator().locator(CAPTION_TEXT_CLASS);
2383
+ return captionElement.innerText();
2384
+ }
2385
+ };
2386
+ }
2387
+ });
2388
+
2233
2389
  // src/pageObjects/elements/AbstractEditor.ts
2234
2390
  var AbstractEditor;
2235
2391
  var init_AbstractEditor2 = __esm({
@@ -2238,10 +2394,13 @@ var init_AbstractEditor2 = __esm({
2238
2394
  init_AbstractElementWithParent();
2239
2395
  init_Editors();
2240
2396
  init_EditorButton();
2397
+ init_EditorTitle();
2241
2398
  AbstractEditor = class extends AbstractElementWithParent {
2242
2399
  editor;
2243
- constructor(parentCssSelector, elementCssSelector, page) {
2400
+ _titleCssSelector;
2401
+ constructor({ parentCssSelector, elementCssSelector, titleCssSelector, page }) {
2244
2402
  super(parentCssSelector, elementCssSelector, page);
2403
+ this._titleCssSelector = titleCssSelector;
2245
2404
  }
2246
2405
  async initEditor() {
2247
2406
  if (!this.editor) {
@@ -2337,6 +2496,32 @@ var init_AbstractEditor2 = __esm({
2337
2496
  button(name) {
2338
2497
  return new EditorButton(this.getFullCssSelector(), name, this.page);
2339
2498
  }
2499
+ /**
2500
+ * Повертає загловок едітора
2501
+ * @example
2502
+ * expect(await formEdit.field('NumberFld').title()).toBe('Title1');
2503
+ * expect(await formEdit.field('TextFld').title()).toBe('Title2`);
2504
+ */
2505
+ async title() {
2506
+ return new EditorTitle({
2507
+ elementCssSelector: this._titleCssSelector,
2508
+ parentCssSelector: this.parentCssSelector,
2509
+ page: this.page
2510
+ }).getTitle();
2511
+ }
2512
+ /**
2513
+ * Вивантажує файл і повертає назву файла. Доступний тільки для поля FileUploader.
2514
+ * @example
2515
+ * const fileName = await formEdit.field('FileField').downloadFile();
2516
+ * expect(filename()).toBe('file.pdf');
2517
+ */
2518
+ async download() {
2519
+ await this.initEditor();
2520
+ if (!this.editor.download) {
2521
+ throw new Error("download is only available for the FileUploader field type.");
2522
+ }
2523
+ return this.editor.download();
2524
+ }
2340
2525
  };
2341
2526
  }
2342
2527
  });
@@ -2351,7 +2536,12 @@ var init_FormField = __esm({
2351
2536
  init_AbstractEditor2();
2352
2537
  FormField = class extends AbstractEditor {
2353
2538
  constructor(parentCssSelector, formName, name, page) {
2354
- super(parentCssSelector, byTestIdCssSelector(createFieldTestId(formName, name)), page);
2539
+ super({
2540
+ parentCssSelector,
2541
+ elementCssSelector: byTestIdCssSelector(createFieldTestId(formName, name)),
2542
+ titleCssSelector: byTestIdCssSelector(createLabelFieldTestId(formName, name)),
2543
+ page
2544
+ });
2355
2545
  }
2356
2546
  };
2357
2547
  }
@@ -2525,6 +2715,7 @@ var init_Table = __esm({
2525
2715
  this.getRowByIndex(index);
2526
2716
  return new Column({
2527
2717
  parentCssSelector: this.getFullCssSelector(),
2718
+ headerCssSelector: this.headerCssSelector,
2528
2719
  page: this.page,
2529
2720
  index
2530
2721
  });
@@ -2637,7 +2828,7 @@ var init_Table = __esm({
2637
2828
  [row] = await this.getSelectedRows();
2638
2829
  }
2639
2830
  if (!row) throw new Error("No row available row for context menu");
2640
- const cellElement = await row.getCell(fieldName).element();
2831
+ const cellElement = await row.getCell(fieldName).getLocator();
2641
2832
  await cellElement.click({ button: "right" });
2642
2833
  });
2643
2834
  }
@@ -2696,10 +2887,14 @@ var init_Table = __esm({
2696
2887
  * console.log('Таблиця містить 5 рядків');
2697
2888
  */
2698
2889
  async waitRowsCount(count) {
2699
- await wait(async () => {
2700
- const rowsCount = await this.getRowElements().count();
2701
- return rowsCount === count;
2702
- }, this.page, `Rows count not equal: ${count}`);
2890
+ await wait(
2891
+ async () => {
2892
+ const rowsCount = await this.getRowElements().count();
2893
+ return rowsCount === count;
2894
+ },
2895
+ this.page,
2896
+ `Rows count not equal: ${count}`
2897
+ );
2703
2898
  }
2704
2899
  };
2705
2900
  }
@@ -2951,6 +3146,7 @@ var init_ToolbarItem = __esm({
2951
3146
  init_locators();
2952
3147
  init_ToolbarMenu();
2953
3148
  init_waitElementIsVisible();
3149
+ init_wait();
2954
3150
  GROUP_BUTTON_CLASS = "toolbar-group-button";
2955
3151
  toolbarItemSelector = (form, name) => byTestIdCssSelector(`ftb-${form}-${name}`);
2956
3152
  ToolbarItem = class extends AbstractElementWithParent {
@@ -2974,7 +3170,10 @@ var init_ToolbarItem = __esm({
2974
3170
  async click() {
2975
3171
  try {
2976
3172
  await this.init();
2977
- await waitElementIsVisible_default({ locator: this._button.getLocator() });
3173
+ await wait(async () => {
3174
+ const element = this._button.getLocator();
3175
+ return await element.isEnabled() && await element.isVisible();
3176
+ }, this.page);
2978
3177
  await this._button.click();
2979
3178
  } catch (error) {
2980
3179
  throw new Error(`Cannot click on toolbar item: ${this._itemName}`);
@@ -3149,7 +3348,12 @@ var init_FormFilterField = __esm({
3149
3348
  formName;
3150
3349
  name;
3151
3350
  constructor(parentCssSelector, formName, name, page) {
3152
- super(parentCssSelector, byTestIdCssSelector(createLayoutFilterTestId(formName, name)), page);
3351
+ super({
3352
+ parentCssSelector,
3353
+ elementCssSelector: byTestIdCssSelector(createLayoutFilterTestId(formName, name)),
3354
+ titleCssSelector: byTestIdCssSelector(createLabelLayoutFilterTestId(formName, name)),
3355
+ page
3356
+ });
3153
3357
  this.formName = formName;
3154
3358
  this.name = name;
3155
3359
  }
@@ -3263,7 +3467,12 @@ var init_PanelFilterField = __esm({
3263
3467
  formName;
3264
3468
  name;
3265
3469
  constructor(parentCssSelector, formName, name, page) {
3266
- super(parentCssSelector, byTestIdCssSelector(createDocFilterTestId(formName, name)), page);
3470
+ super({
3471
+ parentCssSelector,
3472
+ elementCssSelector: byTestIdCssSelector(createDocFilterTestId(formName, name)),
3473
+ titleCssSelector: byTestIdCssSelector(createLabelDocFilterTestId(formName, name)),
3474
+ page
3475
+ });
3267
3476
  this.formName = formName;
3268
3477
  this.name = name;
3269
3478
  }
@@ -3431,7 +3640,12 @@ var init_HeaderFilterField = __esm({
3431
3640
  init_AbstractEditor2();
3432
3641
  HeaderFilterField = class extends AbstractEditor {
3433
3642
  constructor(parentCssSelector, formName, name, page) {
3434
- super(parentCssSelector, byTestIdCssSelector(createHeaderFilterTestId(formName, name)), page);
3643
+ super({
3644
+ parentCssSelector,
3645
+ elementCssSelector: byTestIdCssSelector(createHeaderFilterTestId(formName, name)),
3646
+ titleCssSelector: "",
3647
+ page
3648
+ });
3435
3649
  }
3436
3650
  async getValue() {
3437
3651
  return super.getValue();
@@ -3493,7 +3707,7 @@ var init_ColumnFilter = __esm({
3493
3707
  await this.getCancelButton().click();
3494
3708
  }
3495
3709
  async initFilter() {
3496
- const columnEl = await this._column.element();
3710
+ const columnEl = await this._column.getLocator();
3497
3711
  await columnEl.hover();
3498
3712
  const headerFilterIcon = columnEl.locator(HEADER_FILTER_ICON);
3499
3713
  await headerFilterIcon.waitFor({ state: "visible" });
@@ -1,4 +1,4 @@
1
- import { Page, Locator } from '@playwright/test';
1
+ import { Locator, Page } from '@playwright/test';
2
2
  import * as playwright_core from 'playwright-core';
3
3
 
4
4
  type IConfig = {
@@ -9,13 +9,14 @@ type IConfig = {
9
9
  };
10
10
  declare function config(cfg?: IConfig): IConfig;
11
11
 
12
- declare abstract class AbstractElement {
12
+ declare abstract class AbstractElement<TLocator extends Locator | Promise<Locator> = Locator> {
13
13
  page: Page;
14
14
  protected elementCssSelector: string;
15
15
  protected constructor(page: Page, elementCssSelector?: string);
16
16
  protected getFullCssSelector(): string;
17
17
  protected joinRelativeCssSelectors(selectors: string[]): string;
18
- getLocator(): Locator;
18
+ protected syncLocator(): Locator;
19
+ getLocator(): TLocator;
19
20
  getAttribute(attr: string): Promise<string>;
20
21
  getClasses(): Promise<string>;
21
22
  getDataTestId(): Promise<string>;
@@ -95,6 +96,7 @@ interface Editor {
95
96
  clear?(): Promise<void>;
96
97
  isReadonly?(): Promise<boolean>;
97
98
  isDisabled?(): Promise<boolean>;
99
+ download?(): Promise<string>;
98
100
  }
99
101
  declare enum ControlClass {
100
102
  Text = "text-control",
@@ -108,14 +110,15 @@ declare enum ControlClass {
108
110
  SingleDateRange = "single-date-range-control",
109
111
  BooleanSelector = "buttons-group",
110
112
  ButtonGroup = "button-group-field",
111
- HeaderFilterDictionary = "header-filter-dictionary"
113
+ HeaderFilterDictionary = "header-filter-dictionary",
114
+ FileUploader = "file-uploader"
112
115
  }
113
116
 
114
117
  interface ClearStrategy {
115
118
  clear(editor: Editor): Promise<void>;
116
119
  }
117
120
 
118
- declare abstract class AbstractElementWithParent extends AbstractElement {
121
+ declare abstract class AbstractElementWithParent<TLocator extends Locator | Promise<Locator> = Locator> extends AbstractElement<TLocator> {
119
122
  protected parentCssSelector: string;
120
123
  constructor(parentCssSelector: string, elementCssSelector: string, page: Page);
121
124
  protected getFullCssSelector(): string;
@@ -347,7 +350,13 @@ declare class EditorButton extends AbstractElementWithParent {
347
350
 
348
351
  declare class AbstractEditor extends AbstractElementWithParent implements Editor {
349
352
  protected editor: Editor;
350
- constructor(parentCssSelector: string, elementCssSelector: string, page: Page);
353
+ protected _titleCssSelector: string;
354
+ constructor({ parentCssSelector, elementCssSelector, titleCssSelector, page }: {
355
+ parentCssSelector: string;
356
+ elementCssSelector: string;
357
+ titleCssSelector: string;
358
+ page: Page;
359
+ });
351
360
  protected initEditor(): Promise<void>;
352
361
  /**
353
362
  * Возвращает значение в поле
@@ -404,6 +413,20 @@ declare class AbstractEditor extends AbstractElementWithParent implements Editor
404
413
  * await form.field('Name').button('editorButton).click()
405
414
  */
406
415
  button(name: string): EditorButton;
416
+ /**
417
+ * Повертає загловок едітора
418
+ * @example
419
+ * expect(await formEdit.field('NumberFld').title()).toBe('Title1');
420
+ * expect(await formEdit.field('TextFld').title()).toBe('Title2`);
421
+ */
422
+ title(): Promise<string>;
423
+ /**
424
+ * Вивантажує файл і повертає назву файла. Доступний тільки для поля FileUploader.
425
+ * @example
426
+ * const fileName = await formEdit.field('FileField').downloadFile();
427
+ * expect(filename()).toBe('file.pdf');
428
+ */
429
+ download(): Promise<string>;
407
430
  }
408
431
 
409
432
  declare class FormField extends AbstractEditor {
@@ -500,7 +523,7 @@ declare class ToolbarItem extends AbstractElementWithParent implements Button {
500
523
  get menu(): ToolbarMenu;
501
524
  }
502
525
 
503
- declare class Cell extends AbstractElementWithParent {
526
+ declare class Cell extends AbstractElementWithParent<Promise<Locator>> {
504
527
  private _index;
505
528
  private readonly getCellIndex;
506
529
  constructor(parentCssSelector: string, getCellIndex: () => Promise<number>, page: Page, index?: number);
@@ -509,7 +532,7 @@ declare class Cell extends AbstractElementWithParent {
509
532
  private getTagsValue;
510
533
  private getNumberValue;
511
534
  private getDateValue;
512
- element(): Promise<Locator>;
535
+ getLocator(): Promise<Locator>;
513
536
  getValue(): Promise<string | number | 1 | 0 | string[] | Date | Date[] | null>;
514
537
  getIndex(): number;
515
538
  }
@@ -522,7 +545,7 @@ interface ConstructorParams$1 {
522
545
  index?: number;
523
546
  page: Page;
524
547
  }
525
- declare class Column extends AbstractElementWithParent {
548
+ declare class Column extends AbstractElementWithParent<Promise<Locator>> {
526
549
  private _index;
527
550
  private _caption;
528
551
  private _name;
@@ -530,7 +553,7 @@ declare class Column extends AbstractElementWithParent {
530
553
  constructor({ parentCssSelector, headerCssSelector, name, caption, index, page }: ConstructorParams$1);
531
554
  private set index(value);
532
555
  private get index();
533
- element(): Promise<Locator>;
556
+ getLocator(): Promise<Locator>;
534
557
  private getColumnHeaderIndexBy;
535
558
  private getIndexByCaption;
536
559
  private getIndexByName;