d5-testing-library 1.9.0-alpha.12 → 1.9.0-alpha.14

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.
@@ -0,0 +1,7 @@
1
+ import {
2
+ FormEdit
3
+ } from "./chunk-V7GHM2NF.mjs";
4
+ import "./chunk-CQXQ4R4T.mjs";
5
+ export {
6
+ FormEdit as default
7
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ ListForm
3
+ } from "./chunk-V6E4WPJM.mjs";
4
+ import "./chunk-CQXQ4R4T.mjs";
5
+ export {
6
+ ListForm as default
7
+ };
@@ -0,0 +1,8 @@
1
+ import {
2
+ TreeView
3
+ } from "./chunk-D6IQ3ESA.mjs";
4
+ import "./chunk-V6E4WPJM.mjs";
5
+ import "./chunk-CQXQ4R4T.mjs";
6
+ export {
7
+ TreeView as default
8
+ };
@@ -352,22 +352,34 @@ var ClearButtonStrategy = class {
352
352
  }
353
353
  };
354
354
 
355
+ // src/utils/withCustomTimeouts.ts
356
+ async function withCustomTimeouts({ driver, timeout, callback }) {
357
+ const { implicit: defaultTimeout } = await driver.manage().getTimeouts();
358
+ try {
359
+ await driver.manage().setTimeouts({ implicit: timeout ?? defaultTimeout });
360
+ return await callback();
361
+ } finally {
362
+ await driver.manage().setTimeouts({ implicit: defaultTimeout });
363
+ }
364
+ }
365
+ var withCustomTimeouts_default = withCustomTimeouts;
366
+
355
367
  // src/pageObjects/elements/Editors/SelectBoxEditor.ts
356
368
  var SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS = "d5-multi-select-item";
357
369
  var combinedValueXpath = (value) => `//body/div[@id="root"]/div[contains(@class, "dx-overlay-wrapper")]//${XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value)}`;
358
370
  var dropDownOptionClick = async (optionValue, driver, delay = true) => {
359
- const { implicit } = await driver.manage().getTimeouts();
360
- let optElement = null;
361
- const timeout = delay ? implicit : 200;
362
371
  let err = null;
363
372
  try {
364
- await driver.manage().setTimeouts({ implicit: timeout });
365
- optElement = await driver.findElement(By5.xpath(combinedValueXpath(optionValue)));
366
- await click(optElement, driver);
373
+ await withCustomTimeouts_default({
374
+ driver,
375
+ timeout: delay ? void 0 : 200,
376
+ callback: async () => {
377
+ let optElement = await driver.findElement(By5.xpath(combinedValueXpath(optionValue)));
378
+ await click(optElement, driver);
379
+ }
380
+ });
367
381
  } catch (e) {
368
382
  err = new Error(`Item not found: "${optionValue}"`);
369
- } finally {
370
- await driver.manage().setTimeouts({ implicit });
371
383
  }
372
384
  if (err)
373
385
  throw err;
@@ -560,9 +572,20 @@ import { By as By9 } from "selenium-webdriver";
560
572
  import { By as By8, Key as Key3 } from "selenium-webdriver";
561
573
 
562
574
  // src/pageObjects/elements/Editors/Date/utils.ts
563
- var formatDMYDate = (date) => {
564
- const [year, month, day] = date.toJSON().split("T")[0].split("-");
565
- return `${day}${month}${year}`;
575
+ var formatDMYDate = (date, isTimeAllowed = false) => {
576
+ const [year, month, day] = date.toISOString().split("T")[0].split("-");
577
+ if (!isTimeAllowed) {
578
+ return `${day}${month}${year}`;
579
+ }
580
+ const hours = String(date.getHours()).padStart(2, "0");
581
+ const minutes = String(date.getMinutes()).padStart(2, "0");
582
+ return `${day}${month}${year}${hours}${minutes}`;
583
+ };
584
+ var formatToDateTime = (dateString) => {
585
+ const [datePart, timePart] = dateString.split("T");
586
+ const [year, month, day] = datePart.split("-").map(Number);
587
+ const [hours, minutes] = timePart.split(":").map(Number);
588
+ return new Date(year, month - 1, day, hours, minutes, 0, 0);
566
589
  };
567
590
 
568
591
  // src/pageObjects/elements/Editors/Date/BaseDateEditor.ts
@@ -570,11 +593,17 @@ var BTN_CALENDAR_POPOVER_OPEN_SELECTOR = "calendar-popover-open-button";
570
593
  var BTN_CALENDAR_POPOVER_DATE_FROM_INPUT_SELECTOR = "DateRange__inputs-item--dateFrom";
571
594
  var BTN_CALENDAR_POPOVER_DATE_TO_INPUT_SELECTOR = "DateRange__inputs-item--dateTo";
572
595
  var BTN_SAVE_SELECTOR = "DateRange__button-save";
596
+ var DATETIME_ALLOWED_SELECTOR = "dx-datebox-datetime";
573
597
  var BaseDateEditor = class extends AbstractDXEditorWithInput {
574
598
  constructor(parentCssSelector, elementCssSelector, driver) {
575
599
  super(parentCssSelector, elementCssSelector, driver);
576
600
  this.setClearStrategy(new InputClearStrategy());
577
601
  }
602
+ async getIsAllowedTime() {
603
+ const dateField = await this.driver.findElement(By8.css(`${this.getFullCssSelector()}`));
604
+ const classString = await dateField.getAttribute("class");
605
+ return classString.includes(DATETIME_ALLOWED_SELECTOR);
606
+ }
578
607
  async setArrayValue(value) {
579
608
  const dateField = await this.driver.findElement(By8.css(`${this.getFullCssSelector()}`));
580
609
  const dateFieldDataTestID = await this.getDataTestId();
@@ -594,7 +623,8 @@ var BaseDateEditor = class extends AbstractDXEditorWithInput {
594
623
  }
595
624
  async setSingleValue(value, inputEl) {
596
625
  const actions = this.driver.actions({ async: true });
597
- const formattedDate = formatDMYDate(value);
626
+ const isTimeAllowed = await this.getIsAllowedTime();
627
+ const formattedDate = formatDMYDate(value, isTimeAllowed);
598
628
  await click(inputEl, this.driver);
599
629
  await actions.move({ origin: inputEl }).sendKeys(Key3.HOME).perform();
600
630
  await actions.move({ origin: inputEl }).sendKeys(formattedDate, Key3.ENTER).perform();
@@ -623,6 +653,10 @@ var SingleDateEditor = class extends BaseDateEditor {
623
653
  }
624
654
  async getValue() {
625
655
  const value = await this.getDateValue();
656
+ const isTimeAllowed = await this.getIsAllowedTime();
657
+ if (isTimeAllowed) {
658
+ return value == "" ? null : formatToDateTime(value);
659
+ }
626
660
  return value == "" ? null : new Date(value);
627
661
  }
628
662
  setValue(value) {
@@ -708,21 +742,21 @@ var SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2 = "d5-multi-select-item";
708
742
  var TAG_BOX_LIST_ITEM_SELECTOR = '.dx-overlay-wrapper .dx-list-item[aria-selected="true"]';
709
743
  var combinedOptionHeaderFilterDictValueXpath = (value) => `//div[contains(@class, '${SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2}') and contains(text(), '${value}')]`;
710
744
  var dropDownHeaderFilterDictionaryOptionClick = async (optionValue, driver, dataTEST = "", delay = true) => {
711
- const { implicit } = await driver.manage().getTimeouts();
712
- let optElement = null;
713
- const timeout = delay ? implicit : 600;
714
745
  let err = null;
715
746
  try {
716
747
  const calendarPopoverSelector = byTestIdCssSelector(`${dataTEST}`);
717
- await driver.manage().setTimeouts({ implicit: timeout });
718
- const calendarPopoverElement = await driver.findElement(By11.css(calendarPopoverSelector));
719
- const customOptionList = calendarPopoverElement.findElement(By11.css(`.${CUSTOM_OPTION_LIST_SELECTOR}`));
720
- optElement = await customOptionList.findElement(By11.xpath(combinedOptionHeaderFilterDictValueXpath(optionValue)));
721
- await click(optElement, driver);
748
+ await withCustomTimeouts_default({
749
+ driver,
750
+ timeout: delay ? void 0 : 600,
751
+ callback: async () => {
752
+ const calendarPopoverElement = await driver.findElement(By11.css(calendarPopoverSelector));
753
+ const customOptionList = calendarPopoverElement.findElement(By11.css(`.${CUSTOM_OPTION_LIST_SELECTOR}`));
754
+ const optElement = await customOptionList.findElement(By11.xpath(combinedOptionHeaderFilterDictValueXpath(optionValue)));
755
+ await click(optElement, driver);
756
+ }
757
+ });
722
758
  } catch (e) {
723
759
  err = new Error(`Item not found: "${optionValue}"`);
724
- } finally {
725
- await driver.manage().setTimeouts({ implicit });
726
760
  }
727
761
  if (err)
728
762
  throw err;
@@ -1294,15 +1328,15 @@ async function classDependencyInjector(formType) {
1294
1328
  let SubFormFactoryClass;
1295
1329
  switch (formType) {
1296
1330
  case "1" /* LIST */:
1297
- SubFormFactoryClass = (await import("./ListForm-ZXNRKZ6M.mjs")).default;
1331
+ SubFormFactoryClass = (await import("./ListForm-RNTNKBTA.mjs")).default;
1298
1332
  break;
1299
1333
  case "3" /* TREE */:
1300
- SubFormFactoryClass = (await import("./TreeView-MHMEFMAT.mjs")).default;
1334
+ SubFormFactoryClass = (await import("./TreeView-FSF5ROFG.mjs")).default;
1301
1335
  break;
1302
1336
  case "2" /* EDIT */:
1303
1337
  case "99" /* FREE_FORM */:
1304
1338
  case "4" /* REPORT */:
1305
- SubFormFactoryClass = (await import("./FormEdit-NTNY3YFF.mjs")).default;
1339
+ SubFormFactoryClass = (await import("./FormEdit-GJPMZVBD.mjs")).default;
1306
1340
  break;
1307
1341
  default:
1308
1342
  throw new Error(`Unsupported form type ${formType}`);
@@ -1401,6 +1435,7 @@ export {
1401
1435
  NumberEditor,
1402
1436
  ControlClass,
1403
1437
  DX_CLEAR_BUTTON_AREA,
1438
+ withCustomTimeouts_default,
1404
1439
  editorFactory,
1405
1440
  createDocFilterTestId,
1406
1441
  createHeaderFilterTestId,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ListForm
3
- } from "./chunk-TUQMPYW7.mjs";
3
+ } from "./chunk-V6E4WPJM.mjs";
4
4
 
5
5
  // src/pageObjects/elements/Forms/TreeView.ts
6
6
  var TREELIST_HEADER_CSS_SELECTOR = ".dx-treelist-headers .dx-treelist-content .dx-treelist-table.dx-treelist-table-fixed";
@@ -17,8 +17,9 @@ import {
17
17
  safeWait,
18
18
  staleElementAction,
19
19
  waitElementIsClickable_default,
20
- waitElementIsVisible_default
21
- } from "./chunk-BVVGX5JV.mjs";
20
+ waitElementIsVisible_default,
21
+ withCustomTimeouts_default
22
+ } from "./chunk-CQXQ4R4T.mjs";
22
23
 
23
24
  // src/pageObjects/elements/Table/Table.ts
24
25
  import { By as By6 } from "selenium-webdriver";
@@ -82,7 +83,7 @@ var Cell = class extends AbstractElementWithParent {
82
83
  const [datePart, timePart] = value.split(", ");
83
84
  const [day, month, year] = datePart.split(".").map(Number);
84
85
  const [hours, minutes] = timePart.split(":").map(Number);
85
- return new Date(Date.UTC(year, month - 1, day, hours, minutes));
86
+ return new Date(year, month - 1, day, hours, minutes, 0, 0);
86
87
  } else {
87
88
  const [day, month, year] = value.split(".").map(Number);
88
89
  return new Date(Date.UTC(year, month - 1, day));
@@ -490,9 +491,18 @@ var Table = class extends AbstractElementWithParent {
490
491
  await this.selectRowByIndex(index, true);
491
492
  }
492
493
  }
493
- async getRows() {
494
+ getRowElements(timeout) {
494
495
  const rowsFullCssSelector = `${this.getFullCssSelector()} ${this.tableContentCssSelector} .dx-row.dx-data-row`;
495
- const rows = await this.driver.findElements(By6.css(rowsFullCssSelector));
496
+ return withCustomTimeouts_default({
497
+ driver: this.driver,
498
+ timeout,
499
+ callback: () => {
500
+ return this.driver.findElements(By6.css(rowsFullCssSelector));
501
+ }
502
+ });
503
+ }
504
+ async getRows() {
505
+ const rows = await this.getRowElements();
496
506
  const result = [];
497
507
  rows.forEach((_, index) => {
498
508
  const newRow = new Row(
@@ -600,11 +610,47 @@ var Table = class extends AbstractElementWithParent {
600
610
  const row = this.getRowByIndex(rowIndex);
601
611
  return row.getCell(cellName).getValue();
602
612
  }
613
+ /**
614
+ * Перевіряє, чи є таблиця порожньою (не містить жодного рядка з даними).
615
+ *
616
+ * @returns {Promise<boolean>} Повертає true, якщо таблиця порожня, false - якщо містить рядки
617
+ *
618
+ * @example
619
+ * const table = new Table(driver);
620
+ *
621
+ * // Перевірка чи порожня таблиця
622
+ * const empty = await table.isEmpty();
623
+ * expect(empty).toBe(true);
624
+ */
625
+ async isEmpty() {
626
+ try {
627
+ await this.waitRowsCount(0);
628
+ return true;
629
+ } catch {
630
+ return false;
631
+ }
632
+ }
633
+ /**
634
+ * Очікує, поки кількість рядків у таблиці не стане рівною заданому значенню.
635
+ * Використовується для синхронізації тестів з динамічним завантаженням даних.
636
+ *
637
+ * @param {number} count - Очікувана кількість рядків у таблиці
638
+ * @returns {Promise<void>} Повертає Promise, який виконується, коли кількість рядків відповідає очікуваній
639
+ * @throws {Error} Викидає помилку, якщо очікування перевищує тайм-аут
640
+ *
641
+ * @example
642
+ * const table = new Table(driver);
643
+ *
644
+ * // Очікування, поки таблиця не стане порожньою
645
+ * await table.waitRowsCount(0);
646
+ *
647
+ * // Очікування, поки в таблиці не з'явиться 5 рядків
648
+ * await table.waitRowsCount(5);
649
+ * console.log('Таблиця містить 5 рядків');
650
+ */
603
651
  async waitRowsCount(count) {
604
652
  await safeWait(async () => {
605
- if (count === 0) {
606
- }
607
- const rows = await this.getRows();
653
+ const rows = await this.getRowElements(1e3);
608
654
  return rows.length === count;
609
655
  }, this.driver, `Rows count not equal: ${count}`);
610
656
  }
@@ -1218,7 +1264,7 @@ var HeaderFilterField = class extends AbstractEditor {
1218
1264
  // src/pageObjects/elements/Filters/ColumnFilter.ts
1219
1265
  var APPLY_SELECTOR = ".apply-button";
1220
1266
  var CANCEL_SELECTOR = ".cancel-button";
1221
- var HEADER_FILTER_ICON = ".dx-column-indicators .dx-header-filter";
1267
+ var HEADER_FILTER_ICON = ".indicators .header-filter-indicator-icon";
1222
1268
  var HEADER_FILTER_CONTAINER = ".header-filter";
1223
1269
  var HEADER_FILTER_BUTTONS = ".header-filter-buttons";
1224
1270
  var ColumnFilter = class extends AbstractElement {
@@ -1252,24 +1298,15 @@ var ColumnFilter = class extends AbstractElement {
1252
1298
  const columnEl = await this._column.getElement();
1253
1299
  const actions = this.driver.actions({ async: true });
1254
1300
  await actions.move({ origin: columnEl }).perform();
1255
- const elements = await columnEl.findElements(By11.css(HEADER_FILTER_ICON));
1256
- let headerFilterIcon = null;
1301
+ const headerFilterIconBy = By11.css(HEADER_FILTER_ICON);
1302
+ let headerFilterIcon = await columnEl.findElement(headerFilterIconBy);
1257
1303
  await safeWait(
1258
- async () => {
1259
- let result = false;
1260
- for (let element of elements) {
1261
- if (await element.isDisplayed()) {
1262
- headerFilterIcon = element;
1263
- result = true;
1264
- break;
1265
- }
1266
- }
1267
- return result;
1304
+ () => {
1305
+ return headerFilterIcon.isDisplayed();
1268
1306
  },
1269
1307
  this.driver,
1270
1308
  `HeaderFilter "${this._name}" is not visible`
1271
1309
  );
1272
- if (!headerFilterIcon) throw new Error(`HeaderFilter "${this._name}" is not visible`);
1273
1310
  await click(headerFilterIcon, this.driver);
1274
1311
  const filter = new HeaderFilterField("", this._formName, this._name, this.driver);
1275
1312
  const filterEl = await filter.getElement();
@@ -3,7 +3,7 @@ import {
3
3
  FormField,
4
4
  click,
5
5
  safeWait
6
- } from "./chunk-BVVGX5JV.mjs";
6
+ } from "./chunk-CQXQ4R4T.mjs";
7
7
 
8
8
  // src/pageObjects/elements/Forms/FormEdit.ts
9
9
  import { By } from "selenium-webdriver";
@@ -512,6 +512,24 @@ var init_ClearButtonStrategy = __esm({
512
512
  }
513
513
  });
514
514
 
515
+ // src/utils/withCustomTimeouts.ts
516
+ async function withCustomTimeouts({ driver, timeout, callback }) {
517
+ const { implicit: defaultTimeout } = await driver.manage().getTimeouts();
518
+ try {
519
+ await driver.manage().setTimeouts({ implicit: timeout ?? defaultTimeout });
520
+ return await callback();
521
+ } finally {
522
+ await driver.manage().setTimeouts({ implicit: defaultTimeout });
523
+ }
524
+ }
525
+ var withCustomTimeouts_default;
526
+ var init_withCustomTimeouts = __esm({
527
+ "src/utils/withCustomTimeouts.ts"() {
528
+ "use strict";
529
+ withCustomTimeouts_default = withCustomTimeouts;
530
+ }
531
+ });
532
+
515
533
  // src/pageObjects/elements/Editors/SelectBoxEditor.ts
516
534
  var import_selenium_webdriver9, SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, combinedValueXpath, dropDownOptionClick, SelectBoxEditor;
517
535
  var init_SelectBoxEditor = __esm({
@@ -522,21 +540,22 @@ var init_SelectBoxEditor = __esm({
522
540
  init_xpathHelper();
523
541
  init_actions();
524
542
  init_ClearButtonStrategy();
543
+ init_withCustomTimeouts();
525
544
  SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS = "d5-multi-select-item";
526
545
  combinedValueXpath = (value) => `//body/div[@id="root"]/div[contains(@class, "dx-overlay-wrapper")]//${XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value)}`;
527
546
  dropDownOptionClick = async (optionValue, driver, delay = true) => {
528
- const { implicit } = await driver.manage().getTimeouts();
529
- let optElement = null;
530
- const timeout = delay ? implicit : 200;
531
547
  let err = null;
532
548
  try {
533
- await driver.manage().setTimeouts({ implicit: timeout });
534
- optElement = await driver.findElement(import_selenium_webdriver9.By.xpath(combinedValueXpath(optionValue)));
535
- await click(optElement, driver);
549
+ await withCustomTimeouts_default({
550
+ driver,
551
+ timeout: delay ? void 0 : 200,
552
+ callback: async () => {
553
+ let optElement = await driver.findElement(import_selenium_webdriver9.By.xpath(combinedValueXpath(optionValue)));
554
+ await click(optElement, driver);
555
+ }
556
+ });
536
557
  } catch (e) {
537
558
  err = new Error(`Item not found: "${optionValue}"`);
538
- } finally {
539
- await driver.manage().setTimeouts({ implicit });
540
559
  }
541
560
  if (err)
542
561
  throw err;
@@ -762,19 +781,30 @@ var init_BooleanSelector = __esm({
762
781
  });
763
782
 
764
783
  // src/pageObjects/elements/Editors/Date/utils.ts
765
- var formatDMYDate;
784
+ var formatDMYDate, formatToDateTime;
766
785
  var init_utils = __esm({
767
786
  "src/pageObjects/elements/Editors/Date/utils.ts"() {
768
787
  "use strict";
769
- formatDMYDate = (date) => {
770
- const [year, month, day] = date.toJSON().split("T")[0].split("-");
771
- return `${day}${month}${year}`;
788
+ formatDMYDate = (date, isTimeAllowed = false) => {
789
+ const [year, month, day] = date.toISOString().split("T")[0].split("-");
790
+ if (!isTimeAllowed) {
791
+ return `${day}${month}${year}`;
792
+ }
793
+ const hours = String(date.getHours()).padStart(2, "0");
794
+ const minutes = String(date.getMinutes()).padStart(2, "0");
795
+ return `${day}${month}${year}${hours}${minutes}`;
796
+ };
797
+ formatToDateTime = (dateString) => {
798
+ const [datePart, timePart] = dateString.split("T");
799
+ const [year, month, day] = datePart.split("-").map(Number);
800
+ const [hours, minutes] = timePart.split(":").map(Number);
801
+ return new Date(year, month - 1, day, hours, minutes, 0, 0);
772
802
  };
773
803
  }
774
804
  });
775
805
 
776
806
  // src/pageObjects/elements/Editors/Date/BaseDateEditor.ts
777
- var import_selenium_webdriver12, BTN_CALENDAR_POPOVER_OPEN_SELECTOR, BTN_CALENDAR_POPOVER_DATE_FROM_INPUT_SELECTOR, BTN_CALENDAR_POPOVER_DATE_TO_INPUT_SELECTOR, BTN_SAVE_SELECTOR, BaseDateEditor;
807
+ var import_selenium_webdriver12, BTN_CALENDAR_POPOVER_OPEN_SELECTOR, BTN_CALENDAR_POPOVER_DATE_FROM_INPUT_SELECTOR, BTN_CALENDAR_POPOVER_DATE_TO_INPUT_SELECTOR, BTN_SAVE_SELECTOR, DATETIME_ALLOWED_SELECTOR, BaseDateEditor;
778
808
  var init_BaseDateEditor = __esm({
779
809
  "src/pageObjects/elements/Editors/Date/BaseDateEditor.ts"() {
780
810
  "use strict";
@@ -788,11 +818,17 @@ var init_BaseDateEditor = __esm({
788
818
  BTN_CALENDAR_POPOVER_DATE_FROM_INPUT_SELECTOR = "DateRange__inputs-item--dateFrom";
789
819
  BTN_CALENDAR_POPOVER_DATE_TO_INPUT_SELECTOR = "DateRange__inputs-item--dateTo";
790
820
  BTN_SAVE_SELECTOR = "DateRange__button-save";
821
+ DATETIME_ALLOWED_SELECTOR = "dx-datebox-datetime";
791
822
  BaseDateEditor = class extends AbstractDXEditorWithInput {
792
823
  constructor(parentCssSelector, elementCssSelector, driver) {
793
824
  super(parentCssSelector, elementCssSelector, driver);
794
825
  this.setClearStrategy(new InputClearStrategy());
795
826
  }
827
+ async getIsAllowedTime() {
828
+ const dateField = await this.driver.findElement(import_selenium_webdriver12.By.css(`${this.getFullCssSelector()}`));
829
+ const classString = await dateField.getAttribute("class");
830
+ return classString.includes(DATETIME_ALLOWED_SELECTOR);
831
+ }
796
832
  async setArrayValue(value) {
797
833
  const dateField = await this.driver.findElement(import_selenium_webdriver12.By.css(`${this.getFullCssSelector()}`));
798
834
  const dateFieldDataTestID = await this.getDataTestId();
@@ -812,7 +848,8 @@ var init_BaseDateEditor = __esm({
812
848
  }
813
849
  async setSingleValue(value, inputEl) {
814
850
  const actions = this.driver.actions({ async: true });
815
- const formattedDate = formatDMYDate(value);
851
+ const isTimeAllowed = await this.getIsAllowedTime();
852
+ const formattedDate = formatDMYDate(value, isTimeAllowed);
816
853
  await click(inputEl, this.driver);
817
854
  await actions.move({ origin: inputEl }).sendKeys(import_selenium_webdriver12.Key.HOME).perform();
818
855
  await actions.move({ origin: inputEl }).sendKeys(formattedDate, import_selenium_webdriver12.Key.ENTER).perform();
@@ -836,6 +873,7 @@ var init_SingleDateEditor = __esm({
836
873
  import_selenium_webdriver13 = require("selenium-webdriver");
837
874
  init_InputClearStrategy();
838
875
  init_BaseDateEditor();
876
+ init_utils();
839
877
  SingleDateEditor = class extends BaseDateEditor {
840
878
  constructor(parentCssSelector, elementCssSelector, driver) {
841
879
  super(parentCssSelector, elementCssSelector, driver);
@@ -850,6 +888,10 @@ var init_SingleDateEditor = __esm({
850
888
  }
851
889
  async getValue() {
852
890
  const value = await this.getDateValue();
891
+ const isTimeAllowed = await this.getIsAllowedTime();
892
+ if (isTimeAllowed) {
893
+ return value == "" ? null : formatToDateTime(value);
894
+ }
853
895
  return value == "" ? null : new Date(value);
854
896
  }
855
897
  setValue(value) {
@@ -957,6 +999,7 @@ var init_HeaderFilterDictionary = __esm({
957
999
  init_locators();
958
1000
  init_ClearButtonStrategy();
959
1001
  init_fixElementStaleError();
1002
+ init_withCustomTimeouts();
960
1003
  TAGS_SELECTOR2 = ".dx-tag .tag-text";
961
1004
  DX_TAG_CONTAINER2 = "dx-tag-container";
962
1005
  DX_TEXTEDITOR_EMPTY3 = "dx-texteditor-empty";
@@ -965,21 +1008,21 @@ var init_HeaderFilterDictionary = __esm({
965
1008
  TAG_BOX_LIST_ITEM_SELECTOR = '.dx-overlay-wrapper .dx-list-item[aria-selected="true"]';
966
1009
  combinedOptionHeaderFilterDictValueXpath = (value) => `//div[contains(@class, '${SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS2}') and contains(text(), '${value}')]`;
967
1010
  dropDownHeaderFilterDictionaryOptionClick = async (optionValue, driver, dataTEST = "", delay = true) => {
968
- const { implicit } = await driver.manage().getTimeouts();
969
- let optElement = null;
970
- const timeout = delay ? implicit : 600;
971
1011
  let err = null;
972
1012
  try {
973
1013
  const calendarPopoverSelector = byTestIdCssSelector(`${dataTEST}`);
974
- await driver.manage().setTimeouts({ implicit: timeout });
975
- const calendarPopoverElement = await driver.findElement(import_selenium_webdriver15.By.css(calendarPopoverSelector));
976
- const customOptionList = calendarPopoverElement.findElement(import_selenium_webdriver15.By.css(`.${CUSTOM_OPTION_LIST_SELECTOR}`));
977
- optElement = await customOptionList.findElement(import_selenium_webdriver15.By.xpath(combinedOptionHeaderFilterDictValueXpath(optionValue)));
978
- await click(optElement, driver);
1014
+ await withCustomTimeouts_default({
1015
+ driver,
1016
+ timeout: delay ? void 0 : 600,
1017
+ callback: async () => {
1018
+ const calendarPopoverElement = await driver.findElement(import_selenium_webdriver15.By.css(calendarPopoverSelector));
1019
+ const customOptionList = calendarPopoverElement.findElement(import_selenium_webdriver15.By.css(`.${CUSTOM_OPTION_LIST_SELECTOR}`));
1020
+ const optElement = await customOptionList.findElement(import_selenium_webdriver15.By.xpath(combinedOptionHeaderFilterDictValueXpath(optionValue)));
1021
+ await click(optElement, driver);
1022
+ }
1023
+ });
979
1024
  } catch (e) {
980
1025
  err = new Error(`Item not found: "${optionValue}"`);
981
- } finally {
982
- await driver.manage().setTimeouts({ implicit });
983
1026
  }
984
1027
  if (err)
985
1028
  throw err;
@@ -1619,7 +1662,7 @@ var init_Cell = __esm({
1619
1662
  const [datePart, timePart] = value.split(", ");
1620
1663
  const [day, month, year] = datePart.split(".").map(Number);
1621
1664
  const [hours, minutes] = timePart.split(":").map(Number);
1622
- return new Date(Date.UTC(year, month - 1, day, hours, minutes));
1665
+ return new Date(year, month - 1, day, hours, minutes, 0, 0);
1623
1666
  } else {
1624
1667
  const [day, month, year] = value.split(".").map(Number);
1625
1668
  return new Date(Date.UTC(year, month - 1, day));
@@ -2179,6 +2222,7 @@ var init_Table = __esm({
2179
2222
  init_ContextMenu();
2180
2223
  init_actions();
2181
2224
  init_wait();
2225
+ init_withCustomTimeouts();
2182
2226
  Table = class extends AbstractElementWithParent {
2183
2227
  formName;
2184
2228
  headerCssSelector;
@@ -2258,9 +2302,18 @@ var init_Table = __esm({
2258
2302
  await this.selectRowByIndex(index, true);
2259
2303
  }
2260
2304
  }
2261
- async getRows() {
2305
+ getRowElements(timeout) {
2262
2306
  const rowsFullCssSelector = `${this.getFullCssSelector()} ${this.tableContentCssSelector} .dx-row.dx-data-row`;
2263
- const rows = await this.driver.findElements(import_selenium_webdriver25.By.css(rowsFullCssSelector));
2307
+ return withCustomTimeouts_default({
2308
+ driver: this.driver,
2309
+ timeout,
2310
+ callback: () => {
2311
+ return this.driver.findElements(import_selenium_webdriver25.By.css(rowsFullCssSelector));
2312
+ }
2313
+ });
2314
+ }
2315
+ async getRows() {
2316
+ const rows = await this.getRowElements();
2264
2317
  const result = [];
2265
2318
  rows.forEach((_, index) => {
2266
2319
  const newRow = new Row(
@@ -2368,11 +2421,47 @@ var init_Table = __esm({
2368
2421
  const row = this.getRowByIndex(rowIndex);
2369
2422
  return row.getCell(cellName).getValue();
2370
2423
  }
2424
+ /**
2425
+ * Перевіряє, чи є таблиця порожньою (не містить жодного рядка з даними).
2426
+ *
2427
+ * @returns {Promise<boolean>} Повертає true, якщо таблиця порожня, false - якщо містить рядки
2428
+ *
2429
+ * @example
2430
+ * const table = new Table(driver);
2431
+ *
2432
+ * // Перевірка чи порожня таблиця
2433
+ * const empty = await table.isEmpty();
2434
+ * expect(empty).toBe(true);
2435
+ */
2436
+ async isEmpty() {
2437
+ try {
2438
+ await this.waitRowsCount(0);
2439
+ return true;
2440
+ } catch {
2441
+ return false;
2442
+ }
2443
+ }
2444
+ /**
2445
+ * Очікує, поки кількість рядків у таблиці не стане рівною заданому значенню.
2446
+ * Використовується для синхронізації тестів з динамічним завантаженням даних.
2447
+ *
2448
+ * @param {number} count - Очікувана кількість рядків у таблиці
2449
+ * @returns {Promise<void>} Повертає Promise, який виконується, коли кількість рядків відповідає очікуваній
2450
+ * @throws {Error} Викидає помилку, якщо очікування перевищує тайм-аут
2451
+ *
2452
+ * @example
2453
+ * const table = new Table(driver);
2454
+ *
2455
+ * // Очікування, поки таблиця не стане порожньою
2456
+ * await table.waitRowsCount(0);
2457
+ *
2458
+ * // Очікування, поки в таблиці не з'явиться 5 рядків
2459
+ * await table.waitRowsCount(5);
2460
+ * console.log('Таблиця містить 5 рядків');
2461
+ */
2371
2462
  async waitRowsCount(count) {
2372
2463
  await safeWait(async () => {
2373
- if (count === 0) {
2374
- }
2375
- const rows = await this.getRows();
2464
+ const rows = await this.getRowElements(1e3);
2376
2465
  return rows.length === count;
2377
2466
  }, this.driver, `Rows count not equal: ${count}`);
2378
2467
  }
@@ -3103,7 +3192,7 @@ var init_ColumnFilter = __esm({
3103
3192
  init_wait();
3104
3193
  APPLY_SELECTOR = ".apply-button";
3105
3194
  CANCEL_SELECTOR = ".cancel-button";
3106
- HEADER_FILTER_ICON = ".dx-column-indicators .dx-header-filter";
3195
+ HEADER_FILTER_ICON = ".indicators .header-filter-indicator-icon";
3107
3196
  HEADER_FILTER_CONTAINER = ".header-filter";
3108
3197
  HEADER_FILTER_BUTTONS = ".header-filter-buttons";
3109
3198
  ColumnFilter = class extends AbstractElement {
@@ -3137,24 +3226,15 @@ var init_ColumnFilter = __esm({
3137
3226
  const columnEl = await this._column.getElement();
3138
3227
  const actions = this.driver.actions({ async: true });
3139
3228
  await actions.move({ origin: columnEl }).perform();
3140
- const elements = await columnEl.findElements(import_selenium_webdriver30.By.css(HEADER_FILTER_ICON));
3141
- let headerFilterIcon = null;
3229
+ const headerFilterIconBy = import_selenium_webdriver30.By.css(HEADER_FILTER_ICON);
3230
+ let headerFilterIcon = await columnEl.findElement(headerFilterIconBy);
3142
3231
  await safeWait(
3143
- async () => {
3144
- let result = false;
3145
- for (let element of elements) {
3146
- if (await element.isDisplayed()) {
3147
- headerFilterIcon = element;
3148
- result = true;
3149
- break;
3150
- }
3151
- }
3152
- return result;
3232
+ () => {
3233
+ return headerFilterIcon.isDisplayed();
3153
3234
  },
3154
3235
  this.driver,
3155
3236
  `HeaderFilter "${this._name}" is not visible`
3156
3237
  );
3157
- if (!headerFilterIcon) throw new Error(`HeaderFilter "${this._name}" is not visible`);
3158
3238
  await click(headerFilterIcon, this.driver);
3159
3239
  const filter = new HeaderFilterField("", this._formName, this._name, this.driver);
3160
3240
  const filterEl = await filter.getElement();
@@ -3695,6 +3775,7 @@ function chromeOptions(builder, options) {
3695
3775
  ChromeOptions.addArguments(`--headless=new`);
3696
3776
  ChromeOptions.addArguments(`--disable-gpu`);
3697
3777
  ChromeOptions.addArguments(`--disable-dev-shm-usage`);
3778
+ ChromeOptions.addArguments(`--window-size=1920,1080`);
3698
3779
  }
3699
3780
  const userDataDir = import_node_path.default.join(import_node_os.default.tmpdir(), ".chrome-cache");
3700
3781
  if (!import_node_fs.default.existsSync(userDataDir)) {
@@ -3728,7 +3809,9 @@ var createDriver = async (browser) => {
3728
3809
  const driver = await builder.build();
3729
3810
  const manage = driver.manage();
3730
3811
  await manage.setTimeouts({ implicit: config().timeout });
3731
- await manage.window().maximize();
3812
+ if (!headless) {
3813
+ await manage.window().maximize();
3814
+ }
3732
3815
  return driver;
3733
3816
  };
3734
3817
 
@@ -655,6 +655,7 @@ declare class Table extends AbstractElementWithParent {
655
655
  * @param indexes починається з 0
656
656
  */
657
657
  selectRowsByIndexes(indexes: number[]): Promise<void>;
658
+ protected getRowElements(timeout?: number): Promise<selenium_webdriver.WebElement[]>;
658
659
  getRows(): Promise<Row[]>;
659
660
  getColumns(): Promise<Column[]>;
660
661
  element(): Promise<selenium_webdriver.WebElement>;
@@ -704,6 +705,37 @@ declare class Table extends AbstractElementWithParent {
704
705
  * expect(cellValue).toBe('Очікуване значення');
705
706
  */
706
707
  getCellValueByCellName(cellName: string, rowIndex: number): Promise<string | number | string[] | Date>;
708
+ /**
709
+ * Перевіряє, чи є таблиця порожньою (не містить жодного рядка з даними).
710
+ *
711
+ * @returns {Promise<boolean>} Повертає true, якщо таблиця порожня, false - якщо містить рядки
712
+ *
713
+ * @example
714
+ * const table = new Table(driver);
715
+ *
716
+ * // Перевірка чи порожня таблиця
717
+ * const empty = await table.isEmpty();
718
+ * expect(empty).toBe(true);
719
+ */
720
+ isEmpty(): Promise<boolean>;
721
+ /**
722
+ * Очікує, поки кількість рядків у таблиці не стане рівною заданому значенню.
723
+ * Використовується для синхронізації тестів з динамічним завантаженням даних.
724
+ *
725
+ * @param {number} count - Очікувана кількість рядків у таблиці
726
+ * @returns {Promise<void>} Повертає Promise, який виконується, коли кількість рядків відповідає очікуваній
727
+ * @throws {Error} Викидає помилку, якщо очікування перевищує тайм-аут
728
+ *
729
+ * @example
730
+ * const table = new Table(driver);
731
+ *
732
+ * // Очікування, поки таблиця не стане порожньою
733
+ * await table.waitRowsCount(0);
734
+ *
735
+ * // Очікування, поки в таблиці не з'явиться 5 рядків
736
+ * await table.waitRowsCount(5);
737
+ * console.log('Таблиця містить 5 рядків');
738
+ */
707
739
  waitRowsCount(count: number): Promise<void>;
708
740
  }
709
741
 
@@ -655,6 +655,7 @@ declare class Table extends AbstractElementWithParent {
655
655
  * @param indexes починається з 0
656
656
  */
657
657
  selectRowsByIndexes(indexes: number[]): Promise<void>;
658
+ protected getRowElements(timeout?: number): Promise<selenium_webdriver.WebElement[]>;
658
659
  getRows(): Promise<Row[]>;
659
660
  getColumns(): Promise<Column[]>;
660
661
  element(): Promise<selenium_webdriver.WebElement>;
@@ -704,6 +705,37 @@ declare class Table extends AbstractElementWithParent {
704
705
  * expect(cellValue).toBe('Очікуване значення');
705
706
  */
706
707
  getCellValueByCellName(cellName: string, rowIndex: number): Promise<string | number | string[] | Date>;
708
+ /**
709
+ * Перевіряє, чи є таблиця порожньою (не містить жодного рядка з даними).
710
+ *
711
+ * @returns {Promise<boolean>} Повертає true, якщо таблиця порожня, false - якщо містить рядки
712
+ *
713
+ * @example
714
+ * const table = new Table(driver);
715
+ *
716
+ * // Перевірка чи порожня таблиця
717
+ * const empty = await table.isEmpty();
718
+ * expect(empty).toBe(true);
719
+ */
720
+ isEmpty(): Promise<boolean>;
721
+ /**
722
+ * Очікує, поки кількість рядків у таблиці не стане рівною заданому значенню.
723
+ * Використовується для синхронізації тестів з динамічним завантаженням даних.
724
+ *
725
+ * @param {number} count - Очікувана кількість рядків у таблиці
726
+ * @returns {Promise<void>} Повертає Promise, який виконується, коли кількість рядків відповідає очікуваній
727
+ * @throws {Error} Викидає помилку, якщо очікування перевищує тайм-аут
728
+ *
729
+ * @example
730
+ * const table = new Table(driver);
731
+ *
732
+ * // Очікування, поки таблиця не стане порожньою
733
+ * await table.waitRowsCount(0);
734
+ *
735
+ * // Очікування, поки в таблиці не з'явиться 5 рядків
736
+ * await table.waitRowsCount(5);
737
+ * console.log('Таблиця містить 5 рядків');
738
+ */
707
739
  waitRowsCount(count: number): Promise<void>;
708
740
  }
709
741
 
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  TreeView
3
- } from "./chunk-EMZGYTYY.mjs";
3
+ } from "./chunk-D6IQ3ESA.mjs";
4
4
  import {
5
5
  FilterPanel,
6
6
  FormFilterField,
7
7
  ListForm,
8
8
  PanelFilterField
9
- } from "./chunk-TUQMPYW7.mjs";
9
+ } from "./chunk-V6E4WPJM.mjs";
10
10
  import {
11
11
  FormEdit
12
- } from "./chunk-IL7WDMOX.mjs";
12
+ } from "./chunk-V7GHM2NF.mjs";
13
13
  import {
14
14
  AbstractButton,
15
15
  AbstractElement,
@@ -32,7 +32,7 @@ import {
32
32
  safeWait,
33
33
  waitElementIsClickable_default,
34
34
  waitElementIsVisible_default
35
- } from "./chunk-BVVGX5JV.mjs";
35
+ } from "./chunk-CQXQ4R4T.mjs";
36
36
 
37
37
  // src/pageObjects/pages/LoginPage.ts
38
38
  import { By } from "selenium-webdriver";
@@ -89,6 +89,7 @@ function chromeOptions(builder, options) {
89
89
  ChromeOptions.addArguments(`--headless=new`);
90
90
  ChromeOptions.addArguments(`--disable-gpu`);
91
91
  ChromeOptions.addArguments(`--disable-dev-shm-usage`);
92
+ ChromeOptions.addArguments(`--window-size=1920,1080`);
92
93
  }
93
94
  const userDataDir = path.join(os.tmpdir(), ".chrome-cache");
94
95
  if (!fs.existsSync(userDataDir)) {
@@ -122,7 +123,9 @@ var createDriver = async (browser) => {
122
123
  const driver = await builder.build();
123
124
  const manage = driver.manage();
124
125
  await manage.setTimeouts({ implicit: config().timeout });
125
- await manage.window().maximize();
126
+ if (!headless) {
127
+ await manage.window().maximize();
128
+ }
126
129
  return driver;
127
130
  };
128
131
 
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  TreeView
3
- } from "./chunk-EMZGYTYY.mjs";
3
+ } from "./chunk-D6IQ3ESA.mjs";
4
4
  import {
5
5
  FilterPanel,
6
6
  FormFilterField,
7
7
  ListForm,
8
8
  PanelFilterField
9
- } from "./chunk-TUQMPYW7.mjs";
9
+ } from "./chunk-V6E4WPJM.mjs";
10
10
  import {
11
11
  FormEdit
12
- } from "./chunk-IL7WDMOX.mjs";
12
+ } from "./chunk-V7GHM2NF.mjs";
13
13
  import {
14
14
  AbstractButton,
15
15
  AbstractElement,
@@ -32,7 +32,7 @@ import {
32
32
  safeWait,
33
33
  waitElementIsClickable_default,
34
34
  waitElementIsVisible_default
35
- } from "./chunk-BVVGX5JV.mjs";
35
+ } from "./chunk-CQXQ4R4T.mjs";
36
36
 
37
37
  // src/pageObjects/pages/LoginPage.ts
38
38
  import { By } from "selenium-webdriver";
@@ -89,6 +89,7 @@ function chromeOptions(builder, options) {
89
89
  ChromeOptions.addArguments(`--headless=new`);
90
90
  ChromeOptions.addArguments(`--disable-gpu`);
91
91
  ChromeOptions.addArguments(`--disable-dev-shm-usage`);
92
+ ChromeOptions.addArguments(`--window-size=1920,1080`);
92
93
  }
93
94
  const userDataDir = path.join(os.tmpdir(), ".chrome-cache");
94
95
  if (!fs.existsSync(userDataDir)) {
@@ -122,7 +123,9 @@ var createDriver = async (browser) => {
122
123
  const driver = await builder.build();
123
124
  const manage = driver.manage();
124
125
  await manage.setTimeouts({ implicit: config().timeout });
125
- await manage.window().maximize();
126
+ if (!headless) {
127
+ await manage.window().maximize();
128
+ }
126
129
  return driver;
127
130
  };
128
131
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "d5-testing-library",
3
- "version": "1.9.0-alpha.12",
3
+ "version": "1.9.0-alpha.14",
4
4
  "description": "e2e testing D5 projects",
5
5
  "main": "dist/cjs/d5-testing-library.cjs",
6
6
  "module": "dist/d5-testing-library.legacy-esm.js",
@@ -38,23 +38,23 @@
38
38
  "author": "",
39
39
  "license": "ISC",
40
40
  "dependencies": {
41
- "selenium-webdriver": "4.29.0",
41
+ "selenium-webdriver": "4.33.0",
42
42
  "typescript": "5.8.2"
43
43
  },
44
44
  "devDependencies": {
45
- "@babel/core": "7.26.9",
45
+ "@babel/core": "7.27.4",
46
46
  "@types/node": "20.11.16",
47
- "@types/jest": "29.5.14",
47
+ "@types/jest": "30.0.0",
48
48
  "@types/selenium-webdriver": "4.1.28",
49
49
  "commander": "12.1.0",
50
50
  "esbuild-extra": "0.4.0",
51
51
  "rimraf": "5.0.10",
52
- "jest": "29.7.0",
53
- "ts-jest": "29.2.6",
52
+ "jest": "30.0.0",
53
+ "ts-jest": "29.4.0",
54
54
  "tsup": "8.4.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "selenium-webdriver": "4.29.0"
57
+ "selenium-webdriver": "4.33.0"
58
58
  },
59
59
  "jest": {
60
60
  "preset": "ts-jest",
@@ -1,7 +0,0 @@
1
- import {
2
- FormEdit
3
- } from "./chunk-IL7WDMOX.mjs";
4
- import "./chunk-BVVGX5JV.mjs";
5
- export {
6
- FormEdit as default
7
- };
@@ -1,7 +0,0 @@
1
- import {
2
- ListForm
3
- } from "./chunk-TUQMPYW7.mjs";
4
- import "./chunk-BVVGX5JV.mjs";
5
- export {
6
- ListForm as default
7
- };
@@ -1,8 +0,0 @@
1
- import {
2
- TreeView
3
- } from "./chunk-EMZGYTYY.mjs";
4
- import "./chunk-TUQMPYW7.mjs";
5
- import "./chunk-BVVGX5JV.mjs";
6
- export {
7
- TreeView as default
8
- };