d5-testing-library 1.0.5 → 1.1.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.
@@ -44,7 +44,8 @@ __export(src_exports, {
44
44
  createDriver: () => createDriver,
45
45
  editorFactory: () => editorFactory,
46
46
  elementIsNotPresent: () => elementIsNotPresent,
47
- signIn: () => signIn
47
+ signIn: () => signIn,
48
+ waitElementIsVisible: () => waitElementIsVisible
48
49
  });
49
50
  module.exports = __toCommonJS(src_exports);
50
51
 
@@ -128,7 +129,7 @@ var AbstractPage = class extends AbstractElement {
128
129
  // src/utils/locators.ts
129
130
  var import_selenium_webdriver = require("selenium-webdriver");
130
131
  var byTestId = (testId, element = "div") => {
131
- return import_selenium_webdriver.By.css(`${element}[data-testid=${testId}]`);
132
+ return import_selenium_webdriver.By.css(`${element}[data-testid="${testId}"]`);
132
133
  };
133
134
 
134
135
  // src/utils/createDriver.ts
@@ -152,6 +153,11 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
152
153
 
153
154
  // src/utils/waitElementIsVisible.ts
154
155
  var import_selenium_webdriver4 = require("selenium-webdriver");
156
+ async function waitElementIsVisible({ element, timeout, errorMessage, driver }) {
157
+ driver = driver ?? config().driver;
158
+ const condition = import_selenium_webdriver4.until.elementIsVisible(element);
159
+ await driver.wait(condition.fn, timeout ?? 1e4, errorMessage ?? condition.description());
160
+ }
155
161
 
156
162
  // src/pageObjects/AbstractElementWithParent.ts
157
163
  var AbstractElementWithParent = class extends AbstractElement {
@@ -163,7 +169,23 @@ var AbstractElementWithParent = class extends AbstractElement {
163
169
  }
164
170
  async getElement() {
165
171
  const parentEl = await this.getParentElement();
166
- return parentEl.findElement(this.elementBy);
172
+ await waitElementIsVisible({
173
+ element: parentEl,
174
+ driver: this.driver
175
+ });
176
+ const el = await parentEl.findElement(this.elementBy);
177
+ await waitElementIsVisible({
178
+ element: el,
179
+ driver: this.driver
180
+ });
181
+ return el;
182
+ }
183
+ async getAttribute(attr) {
184
+ const el = await this.getElement();
185
+ return await el.getAttribute(attr);
186
+ }
187
+ async getClasses() {
188
+ return await this.getAttribute("class");
167
189
  }
168
190
  };
169
191
 
@@ -249,7 +271,7 @@ var AbstractForm = class extends AbstractPage {
249
271
  };
250
272
 
251
273
  // src/pageObjects/elements/Forms/FormEdit.ts
252
- var import_selenium_webdriver9 = require("selenium-webdriver");
274
+ var import_selenium_webdriver13 = require("selenium-webdriver");
253
275
 
254
276
  // src/pageObjects/elements/Editors/AbstractEditor.ts
255
277
  var import_selenium_webdriver7 = require("selenium-webdriver");
@@ -262,8 +284,20 @@ var AbstractFormElement = class extends AbstractElementWithParent {
262
284
  }
263
285
  };
264
286
 
287
+ // src/pageObjects/elements/Editors/ClearStrategy/InputClearStrategy.ts
288
+ var InputClearStrategy = class {
289
+ async clear(editor) {
290
+ const inputEl = await editor.getInputElement();
291
+ await inputEl.clear();
292
+ }
293
+ };
294
+
265
295
  // src/pageObjects/elements/Editors/AbstractEditor.ts
266
296
  var AbstractDXEditorWithInput = class extends AbstractFormElement {
297
+ clearStrategy = new InputClearStrategy();
298
+ setClearStrategy(strategy) {
299
+ this.clearStrategy = strategy;
300
+ }
267
301
  async getInputElement() {
268
302
  const controlEl = await this.getElement();
269
303
  return controlEl.findElement(import_selenium_webdriver7.By.className("dx-texteditor-input"));
@@ -277,10 +311,17 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
277
311
  await click(inputEl, this.driver);
278
312
  await inputEl.sendKeys(value, import_selenium_webdriver7.Key.ENTER);
279
313
  }
314
+ async clear() {
315
+ await this.clearStrategy.clear(this);
316
+ }
280
317
  };
281
318
 
282
319
  // src/pageObjects/elements/Editors/TextEditor.ts
283
320
  var TextEditor = class extends AbstractDXEditorWithInput {
321
+ constructor(getParentElement, elementBy, driver) {
322
+ super(getParentElement, elementBy, driver);
323
+ this.setClearStrategy(new InputClearStrategy());
324
+ }
284
325
  getValue() {
285
326
  return this.getInputValue();
286
327
  }
@@ -291,6 +332,10 @@ var TextEditor = class extends AbstractDXEditorWithInput {
291
332
 
292
333
  // src/pageObjects/elements/Editors/NumberEditor.ts
293
334
  var NumberEditor = class extends AbstractDXEditorWithInput {
335
+ constructor(getParentElement, elementBy, driver) {
336
+ super(getParentElement, elementBy, driver);
337
+ this.setClearStrategy(new InputClearStrategy());
338
+ }
294
339
  async getValue() {
295
340
  const value = await super.getInputValue();
296
341
  return value == "" ? null : Number.parseFloat(value);
@@ -306,10 +351,10 @@ var CheckBox = class extends AbstractFormElement {
306
351
  const inputEl = await this.getElement();
307
352
  const result = await inputEl.getAttribute("aria-checked");
308
353
  if (result === "true")
309
- return true;
354
+ return 1;
310
355
  if (result === "false")
311
- return false;
312
- return void 0;
356
+ return 0;
357
+ return null;
313
358
  }
314
359
  async setValue(value) {
315
360
  const inputEl = await this.getElement();
@@ -321,7 +366,7 @@ var CheckBox = class extends AbstractFormElement {
321
366
  };
322
367
 
323
368
  // src/pageObjects/elements/Editors/SelectBoxEditor.ts
324
- var import_selenium_webdriver8 = require("selenium-webdriver");
369
+ var import_selenium_webdriver9 = require("selenium-webdriver");
325
370
 
326
371
  // src/utils/xpathHelper.ts
327
372
  var XPathHelper = class {
@@ -333,18 +378,52 @@ var XPathHelper = class {
333
378
  }
334
379
  };
335
380
 
381
+ // src/pageObjects/elements/Editors/ClearStrategy/ClearButtonStrategy.ts
382
+ var import_selenium_webdriver8 = require("selenium-webdriver");
383
+ var DX_TEXTEDITOR_EMPTY = "dx-texteditor-empty";
384
+ var DX_CLEAR_BUTTON_AREA = "dx-clear-button-area";
385
+ var ClearButtonStrategy = class {
386
+ editorContainerClass;
387
+ constructor(editorContainerClass) {
388
+ this.editorContainerClass = editorContainerClass;
389
+ }
390
+ async isEmptyEditorField(editor) {
391
+ const parentEl = await editor.getParentElement();
392
+ const editorContainer = await parentEl.findElement(import_selenium_webdriver8.By.className(this.editorContainerClass));
393
+ const classAttribute = await editorContainer.getAttribute("class");
394
+ return classAttribute.includes(DX_TEXTEDITOR_EMPTY);
395
+ }
396
+ async clear(editor) {
397
+ if (await this.isEmptyEditorField(editor)) {
398
+ throw new Error("This field is already empty");
399
+ }
400
+ const clearBtnSelector = `.${this.editorContainerClass} .${DX_CLEAR_BUTTON_AREA}`;
401
+ const parentEl = await editor.getParentElement();
402
+ const clearBtn = await parentEl.findElement(import_selenium_webdriver8.By.css(clearBtnSelector));
403
+ await click(clearBtn, editor.driver);
404
+ }
405
+ };
406
+
336
407
  // src/pageObjects/elements/Editors/SelectBoxEditor.ts
337
408
  var SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS = "d5-multi-select-item";
338
409
  var SELECT_BOX_ELEMENT_ROLE = "option";
410
+ var combinedValueXpath = (value) => `${XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)}${XPathHelper.getClassAndValueXpath(
411
+ SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS,
412
+ value
413
+ )}`;
414
+ var DX_SELECTBOX = "dx-selectbox";
339
415
  var SelectBoxEditor = class extends AbstractDXEditorWithInput {
416
+ constructor(getParentElement, elementBy, driver) {
417
+ super(getParentElement, elementBy, driver);
418
+ this.setClearStrategy(new ClearButtonStrategy(DX_SELECTBOX));
419
+ }
340
420
  async setSelectInputValue(value) {
341
421
  const inputEl = await this.getInputElement();
342
422
  await click(inputEl, this.driver);
343
- await inputEl.sendKeys(value, import_selenium_webdriver8.Key.ENTER);
344
- const combinedValueXpath = XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE) + XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value);
423
+ await inputEl.sendKeys(value, import_selenium_webdriver9.Key.ENTER);
345
424
  await this.driver.wait(async () => {
346
425
  try {
347
- const optElement = await inputEl.findElement(import_selenium_webdriver8.By.xpath(combinedValueXpath));
426
+ const optElement = await inputEl.findElement(import_selenium_webdriver9.By.xpath(combinedValueXpath(value)));
348
427
  await click(optElement, this.driver);
349
428
  return true;
350
429
  } catch (e) {
@@ -370,7 +449,7 @@ var SwitchEditor = class extends AbstractFormElement {
370
449
  return 1;
371
450
  if (result === "OFF")
372
451
  return 0;
373
- return void 0;
452
+ return null;
374
453
  }
375
454
  async setValue(value) {
376
455
  if (value !== 0 && value !== 1) {
@@ -388,21 +467,205 @@ var SwitchEditor = class extends AbstractFormElement {
388
467
  }
389
468
  };
390
469
 
470
+ // src/pageObjects/elements/Editors/TagBox.ts
471
+ var import_selenium_webdriver10 = require("selenium-webdriver");
472
+ var TAGS_SELECTOR = ".dx-tag .tag-text";
473
+ var DX_TAG_CONTAINER = "dx-tag-container";
474
+ var DX_TAGBOX = "dx-tagbox";
475
+ var DX_TEXTEDITOR_EMPTY2 = "dx-texteditor-empty";
476
+ var BTN_OK_SELECTOR = ".dx-tagbox-popup-wrapper .dx-popup-bottom .dx-button.dx-popup-done";
477
+ var TagBox = class extends AbstractDXEditorWithInput {
478
+ constructor(getParentElement, elementBy, driver) {
479
+ super(getParentElement, elementBy, driver);
480
+ this.setClearStrategy(new ClearButtonStrategy(DX_TAGBOX));
481
+ }
482
+ async setTagBoxInputValue(values) {
483
+ const lastElement = values[values.length - 1];
484
+ const inputEl = await this.getInputElement();
485
+ await inputEl.click();
486
+ for (const value of values) {
487
+ await this.selectOption(inputEl, value, lastElement);
488
+ }
489
+ await this.confirmSelection();
490
+ }
491
+ async selectOption(inputEl, value, lastElement) {
492
+ await inputEl.sendKeys(value);
493
+ await this.driver.wait(async () => {
494
+ try {
495
+ const optElement = await inputEl.findElement(import_selenium_webdriver10.By.xpath(combinedValueXpath(value)));
496
+ await click(optElement, this.driver);
497
+ return true;
498
+ } catch (e) {
499
+ return false;
500
+ }
501
+ });
502
+ if (value !== lastElement) {
503
+ await inputEl.clear();
504
+ }
505
+ }
506
+ async confirmSelection() {
507
+ const inputEl = await this.getInputElement();
508
+ const option = await inputEl.findElement(import_selenium_webdriver10.By.xpath(XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)));
509
+ const btnOk = await this.driver.findElement(import_selenium_webdriver10.By.css(BTN_OK_SELECTOR));
510
+ await this.driver.wait(async () => {
511
+ return await option.getAttribute("aria-selected") === "true";
512
+ });
513
+ await click(btnOk, this.driver);
514
+ }
515
+ async getTagBoxInputValue() {
516
+ if (await this.isTagBoxEmpty()) {
517
+ return [];
518
+ }
519
+ const parentEl = await this.getParentElement();
520
+ const inputEl = await parentEl.findElement(import_selenium_webdriver10.By.className(DX_TAG_CONTAINER));
521
+ const tags = await inputEl.findElements(import_selenium_webdriver10.By.css(TAGS_SELECTOR));
522
+ const values = [];
523
+ for (const tag of tags) {
524
+ const text = await tag.getText();
525
+ values.push(text);
526
+ }
527
+ return values;
528
+ }
529
+ async isTagBoxEmpty() {
530
+ const parentEl = await this.getParentElement();
531
+ const tagboxContainer = await parentEl.findElement(import_selenium_webdriver10.By.className(DX_TAGBOX));
532
+ const classAttribute = await tagboxContainer.getAttribute("class");
533
+ return classAttribute.includes(DX_TEXTEDITOR_EMPTY2);
534
+ }
535
+ async getValue() {
536
+ const value = await this.getTagBoxInputValue();
537
+ return value.length ? value : null;
538
+ }
539
+ async setValue(values) {
540
+ if (!Array.isArray(values)) {
541
+ throw new Error("The provided value is not an array");
542
+ }
543
+ await this.setTagBoxInputValue(values);
544
+ }
545
+ async remove(itemText) {
546
+ const tagValues = await this.getValue();
547
+ const tagExists = tagValues.includes(itemText);
548
+ if (!tagExists) {
549
+ throw new Error(`The tag with the text: ${itemText} was not found`);
550
+ }
551
+ const parentEl = await this.getParentElement();
552
+ const inputEl = await parentEl.findElement(import_selenium_webdriver10.By.className(DX_TAG_CONTAINER));
553
+ const clearBtnTestId = byTestId(`clear-button-${itemText}`);
554
+ const clearBtn = await inputEl.findElement(clearBtnTestId);
555
+ await click(clearBtn, this.driver);
556
+ }
557
+ };
558
+
559
+ // src/pageObjects/elements/Editors/ButtonGroup.ts
560
+ var import_selenium_webdriver11 = require("selenium-webdriver");
561
+ var ITEM_CLASS = "dx-buttongroup-item";
562
+ var SELECTED_CLASS = "dx-state-selected";
563
+ var ButtonGroup = class extends AbstractFormElement {
564
+ async getItems() {
565
+ return (await this.getElement()).findElements(import_selenium_webdriver11.By.className(ITEM_CLASS));
566
+ }
567
+ getDataValue(el) {
568
+ return el.getAttribute("data-value");
569
+ }
570
+ async getValue() {
571
+ const inputEl = await this.getElement();
572
+ const selectedEl = await inputEl.findElement(import_selenium_webdriver11.By.className(`${ITEM_CLASS} ${SELECTED_CLASS}`));
573
+ return this.getDataValue(selectedEl);
574
+ }
575
+ async setValue(value) {
576
+ const items = await this.getItems();
577
+ let buttonEl = void 0;
578
+ for (const item of items) {
579
+ const text = await this.getDataValue(item);
580
+ if (text == value) {
581
+ buttonEl = item;
582
+ break;
583
+ }
584
+ }
585
+ if (!buttonEl)
586
+ throw new Error(`Cannot find item in button group with text: ${value}`);
587
+ await click(buttonEl, this.driver);
588
+ }
589
+ };
590
+
591
+ // src/pageObjects/elements/Editors/BooleanSelector.ts
592
+ var BooleanSelector = class extends ButtonGroup {
593
+ // @ts-ignore
594
+ async getValue() {
595
+ const value = await super.getValue();
596
+ return value === "null" ? null : value === "1" ? 1 : 0;
597
+ }
598
+ // @ts-ignore
599
+ async setValue(value) {
600
+ const val = value == null ? "null" : value ? "1" : "0";
601
+ await super.setValue(val);
602
+ }
603
+ };
604
+
605
+ // src/pageObjects/elements/Editors/DateEditor.ts
606
+ var import_selenium_webdriver12 = require("selenium-webdriver");
607
+ var DateEditor = class extends AbstractDXEditorWithInput {
608
+ constructor(getParentElement, elementBy, driver) {
609
+ super(getParentElement, elementBy, driver);
610
+ this.setClearStrategy(new InputClearStrategy());
611
+ }
612
+ async getControlElement() {
613
+ const controlEl = await this.getElement();
614
+ return controlEl.findElement(import_selenium_webdriver12.By.className("dx-dropdowneditor-input-wrapper"));
615
+ }
616
+ async getDateElement() {
617
+ const controlEl = await this.getControlElement();
618
+ return controlEl.findElement(import_selenium_webdriver12.By.css("input[type=hidden]"));
619
+ }
620
+ async setDateValue(value) {
621
+ const dateEl = await this.getInputElement();
622
+ const stringDate = value.toJSON().split("T")[0];
623
+ const dateArr = stringDate.split("-");
624
+ const [year, month, day] = dateArr;
625
+ const keys = day + month + year;
626
+ await click(dateEl, this.driver);
627
+ const actions = this.driver.actions({ async: true });
628
+ await actions.move({ origin: dateEl }).sendKeys(import_selenium_webdriver12.Key.HOME).perform();
629
+ await actions.move({ origin: dateEl }).sendKeys(keys, import_selenium_webdriver12.Key.ENTER).perform();
630
+ }
631
+ async getDateValue() {
632
+ const inputEl = await this.getDateElement();
633
+ return inputEl.getAttribute("value");
634
+ }
635
+ async getValue() {
636
+ const value = await this.getDateValue();
637
+ return value == "" ? null : new Date(value);
638
+ }
639
+ setValue(value) {
640
+ if (typeof value === "object") {
641
+ return this.setDateValue(value);
642
+ }
643
+ throw new Error(`Value is incorrect. It should be Object`);
644
+ }
645
+ };
646
+
391
647
  // src/pageObjects/elements/Editors/editorFactory.ts
392
648
  var editorFactory = async (getParentElement, elementBy, driver) => {
393
649
  const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
394
- const element = await elementInstance.getElement();
395
- const classSting = await element.getAttribute("class");
650
+ const classSting = await elementInstance.getClasses();
396
651
  if (classSting.includes("text-control"))
397
652
  return new TextEditor(getParentElement, elementBy, driver);
398
653
  if (classSting.includes("number-control"))
399
654
  return new NumberEditor(getParentElement, elementBy, driver);
400
655
  if (classSting.includes("check-box"))
401
656
  return new CheckBox(getParentElement, elementBy, driver);
657
+ if (classSting.includes("multi-select-control"))
658
+ return new TagBox(getParentElement, elementBy, driver);
402
659
  if (classSting.includes("select-control"))
403
660
  return new SelectBoxEditor(getParentElement, elementBy, driver);
404
661
  if (classSting.includes("switch-control"))
405
662
  return new SwitchEditor(getParentElement, elementBy, driver);
663
+ if (classSting.includes("date-control"))
664
+ return new DateEditor(getParentElement, elementBy, driver);
665
+ if (classSting.includes("buttons-group"))
666
+ return new BooleanSelector(getParentElement, elementBy, driver);
667
+ if (classSting.includes("button-group-field"))
668
+ return new ButtonGroup(getParentElement, elementBy, driver);
406
669
  throw new Error("Unknown type of editor. Please write ticket to the support");
407
670
  };
408
671
 
@@ -413,6 +676,9 @@ function createDataTestId(formName, itemType, itemName) {
413
676
  function createFieldTestId(formName, itemName) {
414
677
  return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
415
678
  }
679
+ function createGroupTestId(formName, itemName) {
680
+ return createDataTestId(formName, "group" /* GROUP */, itemName);
681
+ }
416
682
  function createTableId(formName) {
417
683
  return `${"table" /* TABLE */}-${formName}`;
418
684
  }
@@ -449,14 +715,82 @@ var FormField = class extends AbstractElementWithParent {
449
715
  await this.initEditor();
450
716
  return this.editor.setValue(value);
451
717
  }
718
+ /**
719
+ * Очищает значение в поле
720
+ * @example
721
+ * await formEdit.field('NumberFld').clear();
722
+ */
723
+ async clear() {
724
+ await this.initEditor();
725
+ if (!this.editor.clear) {
726
+ throw new Error("The clear method is not available for this field type.");
727
+ }
728
+ return this.editor.clear();
729
+ }
730
+ /**
731
+ * Удаляет тег по переданному тексту
732
+ * @example
733
+ * await formEdit.field('TagBox').remove('test');
734
+ */
735
+ async remove(itemText) {
736
+ await this.initEditor();
737
+ if (!this.editor.remove) {
738
+ throw new Error("This method is only available for the TagBox field.");
739
+ }
740
+ return this.editor.remove(itemText);
741
+ }
742
+ };
743
+
744
+ // src/pageObjects/elements/Groups/AbstractGroup.ts
745
+ var AbstractDXGroup = class extends AbstractFormElement {
746
+ };
747
+
748
+ // src/pageObjects/elements/Groups/Panel.ts
749
+ var Panel = class extends AbstractDXGroup {
750
+ async isDisplayed() {
751
+ const groupElement = await this.getElement();
752
+ return await groupElement.isDisplayed();
753
+ }
754
+ };
755
+
756
+ // src/pageObjects/elements/Groups/groupFactory.ts
757
+ var groupFactory = async (getParentElement, elementBy, driver) => {
758
+ const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
759
+ const classSting = await elementInstance.getClasses();
760
+ if (classSting.includes("panel-group"))
761
+ return new Panel(getParentElement, elementBy, driver);
762
+ throw new Error("Unknown type of group. Please write ticket to the support");
763
+ };
764
+
765
+ // src/pageObjects/elements/FormGroup.ts
766
+ var FormGroup = class extends AbstractElementWithParent {
767
+ editor;
768
+ constructor(getParentElement, formName, name, driver) {
769
+ super(getParentElement, driver);
770
+ this.elementBy = byTestId(createGroupTestId(formName, name));
771
+ }
772
+ async initEditor() {
773
+ if (!this.editor) {
774
+ this.editor = await groupFactory(this.getParentElement, this.elementBy, this.driver);
775
+ }
776
+ }
777
+ /**
778
+ * Возвращает булевое значение доступна ли группа
779
+ * @example
780
+ * expect(await tableList.group('MainSuperPanel').isDisplayed();
781
+ */
782
+ async isDisplayed() {
783
+ await this.initEditor();
784
+ return this.editor.isDisplayed();
785
+ }
452
786
  };
453
787
 
454
788
  // src/pageObjects/elements/Forms/FormEdit.ts
455
789
  var FormEdit = class extends AbstractForm {
456
- saveButtonBy = import_selenium_webdriver9.By.id("button-save");
790
+ saveButtonBy = import_selenium_webdriver13.By.id("button-save");
457
791
  constructor(driver) {
458
792
  super(driver);
459
- this.popupContainerBy = import_selenium_webdriver9.By.className(`popup form-edit-${this.formName}`);
793
+ this.popupContainerBy = import_selenium_webdriver13.By.className(`popup form-edit-${this.formName}`);
460
794
  }
461
795
  /**
462
796
  * Находит поле формы редактирования по имени
@@ -468,6 +802,28 @@ var FormEdit = class extends AbstractForm {
468
802
  field(name) {
469
803
  return new FormField(this.getContainerElement, this.formName, name, this.driver);
470
804
  }
805
+ /**
806
+ * Проверяет не отключена ли кнопка Сохранить
807
+ * @example
808
+ * const formEdit = new MyForm();
809
+ * //...
810
+ * await formEdit.isSaveButtonDisabled();
811
+ */
812
+ async isSaveButtonDisabled() {
813
+ const saveButton = await this.driver.findElement(this.saveButtonBy);
814
+ const result = await saveButton.getAttribute("aria-disabled");
815
+ return result === "true";
816
+ }
817
+ /**
818
+ * Находит группу формы редактирования по имени
819
+ * @example
820
+ * const formEdit = new MyForm();
821
+ * //...
822
+ * expect(await formEdit.group('Name');
823
+ */
824
+ group(name) {
825
+ return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
826
+ }
471
827
  /**
472
828
  * Нажатие на кнопку Сохранить
473
829
  * @example
@@ -476,35 +832,36 @@ var FormEdit = class extends AbstractForm {
476
832
  * await formEdit.saveButtonClick();
477
833
  */
478
834
  async saveButtonClick() {
479
- await click(await this.driver.findElement(this.saveButtonBy), this.driver);
835
+ const saveButton = await this.driver.findElement(this.saveButtonBy);
836
+ await this.driver.wait(async () => !await this.isSaveButtonDisabled(), void 0, "Button is disabled");
837
+ await click(saveButton, this.driver);
480
838
  }
481
839
  };
482
840
 
483
841
  // src/pageObjects/elements/Forms/ListForm.ts
484
- var import_selenium_webdriver15 = require("selenium-webdriver");
842
+ var import_selenium_webdriver19 = require("selenium-webdriver");
485
843
 
486
844
  // src/pageObjects/elements/Table/Table.ts
487
- var import_selenium_webdriver12 = require("selenium-webdriver");
845
+ var import_selenium_webdriver16 = require("selenium-webdriver");
488
846
 
489
847
  // src/pageObjects/elements/Table/utils.ts
490
- var import_selenium_webdriver10 = require("selenium-webdriver");
848
+ var import_selenium_webdriver14 = require("selenium-webdriver");
491
849
  var getRowPathByIndex = (index) => {
492
- return import_selenium_webdriver10.By.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
850
+ return import_selenium_webdriver14.By.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
493
851
  };
852
+ var getColumnByIndexCssSelector = (columnIndex) => `td[aria-colindex="${transformInputIndex(columnIndex)}"]`;
494
853
  var getColumnPathByIndex = (index) => {
495
- return import_selenium_webdriver10.By.css(`td[aria-colindex="${transformInputIndex(index)}"]`);
496
- };
497
- var getColumnPathByCaption = (caption) => {
498
- return import_selenium_webdriver10.By.css(`td[role="columnheader"][aria-label="Column ${caption}"]`);
854
+ return import_selenium_webdriver14.By.css(getColumnByIndexCssSelector(index));
499
855
  };
856
+ var getColumnByCaptionCssSelector = (caption) => `td[role="columnheader"][aria-label="Column ${caption}"]`;
500
857
  var getCellPathByIndex = (index) => {
501
- return import_selenium_webdriver10.By.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
858
+ return import_selenium_webdriver14.By.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
502
859
  };
503
860
  var transformInputIndex = (index) => index + 1;
504
861
  var transformOutputIndex = (index) => +index - 1;
505
862
 
506
863
  // src/pageObjects/elements/Table/elements/Row.ts
507
- var import_selenium_webdriver11 = require("selenium-webdriver");
864
+ var import_selenium_webdriver15 = require("selenium-webdriver");
508
865
 
509
866
  // src/pageObjects/elements/Table/elements/Cell.ts
510
867
  var Cell = class extends AbstractElementWithParent {
@@ -526,6 +883,7 @@ var Cell = class extends AbstractElementWithParent {
526
883
  // src/pageObjects/elements/Table/elements/Row.ts
527
884
  var DX_SELECTION_CLASS = "dx-selection";
528
885
  var DX_ROW_EDIT_CLASS = "dx-edit-row";
886
+ var DX_DATA_ROW_CLASS = "dx-data-row";
529
887
  var Row = class extends AbstractElementWithParent {
530
888
  index;
531
889
  getColumnByCaption;
@@ -556,10 +914,8 @@ var Row = class extends AbstractElementWithParent {
556
914
  await click(rowEl, this.driver);
557
915
  await this.driver.wait(async () => {
558
916
  const classes = await rowEl.getAttribute("class");
559
- if (!classes.includes(DX_SELECTION_CLASS))
560
- throw new Error("Cannot select row");
561
- return true;
562
- }, 500);
917
+ return classes.includes(DX_SELECTION_CLASS);
918
+ }, 500, "Cannot select row");
563
919
  }
564
920
  async isSelected() {
565
921
  const rowEl = await this.getElement();
@@ -571,7 +927,7 @@ var Row = class extends AbstractElementWithParent {
571
927
  }
572
928
  async getCells() {
573
929
  const rowEl = await this.getElement();
574
- const cells = await rowEl.findElements(import_selenium_webdriver11.By.css(`td[role="gridcell"]`));
930
+ const cells = await rowEl.findElements(import_selenium_webdriver15.By.css(`td[role="gridcell"]`));
575
931
  const result = [];
576
932
  cells.forEach((_, index) => {
577
933
  const newCell = new Cell(rowEl, index, this.driver);
@@ -579,26 +935,30 @@ var Row = class extends AbstractElementWithParent {
579
935
  });
580
936
  return result;
581
937
  }
582
- async clickInlineButton(rowClass, buttonClass) {
583
- const fixedTable = (await this.getParentElement()).findElement(
584
- import_selenium_webdriver11.By.css(".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed")
938
+ async clickInlineButton(buttonClass) {
939
+ const FIXED_TABLE_CSS_SELECTOR = ".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed";
940
+ const buttonCssSelector = `.${DX_DATA_ROW_CLASS}[aria-rowindex="${transformInputIndex(this.index)}"] .${buttonClass}`;
941
+ const button = (await this.getParentElement()).findElement(
942
+ import_selenium_webdriver15.By.css(`${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`)
585
943
  );
586
- const rowEl = await fixedTable.findElement(import_selenium_webdriver11.By.className(rowClass));
587
- const button = await rowEl.findElement(import_selenium_webdriver11.By.className(buttonClass));
588
- if (button) {
589
- return click(button, this.driver);
590
- }
591
- throw new Error(`Cannot find ${buttonClass} button`);
944
+ return click(button, this.driver);
945
+ }
946
+ async checkEditingMode(isEditing, msg) {
947
+ await this.driver.wait(async () => {
948
+ return (await this.getClasses()).includes(DX_ROW_EDIT_CLASS) === isEditing;
949
+ }, 2e3, msg);
592
950
  }
593
951
  async edit() {
594
- await this.select();
595
- return this.clickInlineButton(DX_SELECTION_CLASS, "edit");
952
+ await this.clickInlineButton("edit");
953
+ await this.checkEditingMode(true, "Row did not switch to edit mode");
596
954
  }
597
955
  async save() {
598
- return this.clickInlineButton(DX_ROW_EDIT_CLASS, "save");
956
+ await this.clickInlineButton("save");
957
+ await this.checkEditingMode(false, "Row did not saved");
599
958
  }
600
959
  async cancel() {
601
- return this.clickInlineButton(DX_ROW_EDIT_CLASS, "cancel");
960
+ await this.clickInlineButton("cancel");
961
+ await this.checkEditingMode(false, "Row did not switch to normal mode");
602
962
  }
603
963
  };
604
964
 
@@ -624,19 +984,18 @@ var Table = class extends AbstractElementWithParent {
624
984
  formName;
625
985
  constructor(getParentElement, formName, driver) {
626
986
  super(getParentElement, driver);
627
- this.elementBy = import_selenium_webdriver12.By.id(createTableId(formName));
987
+ this.elementBy = import_selenium_webdriver16.By.id(createTableId(formName));
628
988
  this.formName = formName;
629
989
  }
630
- async getHeaderElement() {
631
- const parentEl = await this.getElement();
632
- return parentEl.findElement(import_selenium_webdriver12.By.className("dx-header-row"));
990
+ getHeaderCssSelector() {
991
+ return ".dx-datagrid-headers .dx-datagrid-content:not(.dx-datagrid-content-fixed)";
633
992
  }
634
993
  async getDataGrid() {
635
994
  const parentEl = await this.getElement();
636
- return parentEl.findElement(import_selenium_webdriver12.By.css(`div[role="grid"]`));
995
+ return parentEl.findElement(import_selenium_webdriver16.By.css(`div[role="grid"]`));
637
996
  }
638
997
  getTableElement = () => {
639
- return this.driver.findElement(this.elementBy);
998
+ return this.getElement();
640
999
  };
641
1000
  async getRowByIndex(index) {
642
1001
  const gridContainer = await this.getDataGrid();
@@ -647,16 +1006,14 @@ var Table = class extends AbstractElementWithParent {
647
1006
  throw new Error(`Cannot find row by index: ${index}`);
648
1007
  }
649
1008
  async getColumnByIndex(index) {
650
- const headerContainer = await this.getHeaderElement();
651
- const column = await headerContainer.findElement(getColumnPathByIndex(index));
1009
+ const column = await (await this.getElement()).findElement(import_selenium_webdriver16.By.css(`${this.getHeaderCssSelector()} ${getColumnByIndexCssSelector(index)}`));
652
1010
  if (column) {
653
1011
  return new Column(this.getTableElement, index, this.driver);
654
1012
  }
655
1013
  throw new Error(`Cannot find column by index: ${index}`);
656
1014
  }
657
1015
  async getColumnByCaption(caption) {
658
- const headerContainer = await this.getHeaderElement();
659
- const column = await headerContainer.findElement(getColumnPathByCaption(caption));
1016
+ const column = await (await this.getElement()).findElement(import_selenium_webdriver16.By.css(`${this.getHeaderCssSelector()} ${getColumnByCaptionCssSelector(caption)}`));
660
1017
  if (column) {
661
1018
  const index = await column.getAttribute("aria-colindex");
662
1019
  return new Column(this.getTableElement, transformOutputIndex(index), this.driver);
@@ -673,7 +1030,7 @@ var Table = class extends AbstractElementWithParent {
673
1030
  }
674
1031
  async getRows() {
675
1032
  const gridContainer = await this.getDataGrid();
676
- const rows = await gridContainer.findElements(import_selenium_webdriver12.By.className("dx-row dx-data-row"));
1033
+ const rows = await gridContainer.findElements(import_selenium_webdriver16.By.className("dx-row dx-data-row"));
677
1034
  const result = [];
678
1035
  rows.forEach((_, index) => {
679
1036
  const newRow = new Row(this.getTableElement, index, this.driver, this.getColumnByCaption.bind(this));
@@ -682,8 +1039,7 @@ var Table = class extends AbstractElementWithParent {
682
1039
  return result;
683
1040
  }
684
1041
  async getColumns() {
685
- const headerContainer = await this.getHeaderElement();
686
- const columns = await headerContainer.findElements(import_selenium_webdriver12.By.css(`td[role="columnheader"]`));
1042
+ const columns = await (await this.getElement()).findElements(import_selenium_webdriver16.By.css(`${this.getHeaderCssSelector()} td[role="columnheader"]`));
687
1043
  const result = [];
688
1044
  columns.forEach((_, index) => {
689
1045
  const newCol = new Column(this.getTableElement, index, this.driver);
@@ -702,23 +1058,28 @@ var Table = class extends AbstractElementWithParent {
702
1058
  * expect(await form.field('Name').getValue()).toBe('test value');
703
1059
  */
704
1060
  field(name) {
705
- return new FormField(this.getElement, this.formName, name, this.driver);
1061
+ return new FormField(this.getTableElement, this.formName, name, this.driver);
706
1062
  }
707
1063
  };
708
1064
 
709
1065
  // src/pageObjects/elements/TableToolbar/TableToolbar.ts
710
- var import_selenium_webdriver14 = require("selenium-webdriver");
1066
+ var import_selenium_webdriver18 = require("selenium-webdriver");
711
1067
 
712
1068
  // src/pageObjects/elements/TableToolbar/TableToolbarButton.ts
713
- var import_selenium_webdriver13 = require("selenium-webdriver");
1069
+ var import_selenium_webdriver17 = require("selenium-webdriver");
714
1070
  var TOOLBAR_BUTTON_CLASS = "toolbar-button";
715
1071
  var TableToolbarButton = class extends AbstractElementWithParent {
1072
+ name;
716
1073
  constructor(getParentElement, name, driver) {
717
1074
  super(getParentElement, driver);
718
- this.elementBy = import_selenium_webdriver13.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
1075
+ this.name = name;
1076
+ this.elementBy = import_selenium_webdriver17.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
719
1077
  }
720
1078
  async click() {
721
1079
  const button = await this.getElement();
1080
+ await this.driver.wait(async () => {
1081
+ return await button.isDisplayed() && !await this.isDisabled();
1082
+ }, 1e3, `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`);
722
1083
  return click(button, this.driver);
723
1084
  }
724
1085
  async isDisabled() {
@@ -733,14 +1094,14 @@ var TABLE_TOOLBAR_CLASS = "d5-table-toolbar";
733
1094
  var TableToolbar = class extends AbstractElementWithParent {
734
1095
  constructor(getParentElement, formName, driver) {
735
1096
  super(getParentElement, driver);
736
- this.elementBy = import_selenium_webdriver14.By.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
1097
+ this.elementBy = import_selenium_webdriver18.By.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
737
1098
  }
738
1099
  getTableToolbarElement = () => {
739
1100
  return this.driver.findElement(this.elementBy);
740
1101
  };
741
1102
  async button(name) {
742
1103
  const toolbar = await this.getTableToolbarElement();
743
- const button = await toolbar.findElement(import_selenium_webdriver14.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
1104
+ const button = await toolbar.findElement(import_selenium_webdriver18.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
744
1105
  if (button) {
745
1106
  return new TableToolbarButton(this.getTableToolbarElement, name, this.driver);
746
1107
  }
@@ -752,7 +1113,7 @@ var TableToolbar = class extends AbstractElementWithParent {
752
1113
  var ListForm = class extends AbstractForm {
753
1114
  constructor(driver) {
754
1115
  super(driver);
755
- this.popupContainerBy = import_selenium_webdriver15.By.className(`popup form-inline-${this.formName}`);
1116
+ this.popupContainerBy = import_selenium_webdriver19.By.className(`popup form-inline-${this.formName}`);
756
1117
  }
757
1118
  /**
758
1119
  * Находит таблицу
@@ -764,6 +1125,16 @@ var ListForm = class extends AbstractForm {
764
1125
  table() {
765
1126
  return new Table(this.getContainerElement, this.formName, this.driver);
766
1127
  }
1128
+ /**
1129
+ * Находит группу на лист форме по имени
1130
+ * @example
1131
+ * const formEdit = new MyForm();
1132
+ * //...
1133
+ * expect(await formEdit.group('Name');
1134
+ */
1135
+ group(name) {
1136
+ return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
1137
+ }
767
1138
  /**
768
1139
  * Находит таблицу
769
1140
  * @example
@@ -800,6 +1171,14 @@ var LoginPage = class extends AbstractPage {
800
1171
  usernameField = byTestId("loginField", "input");
801
1172
  passwordField = byTestId("passwordField", "input");
802
1173
  loginButton = byTestId("loginButton");
1174
+ async locate() {
1175
+ await super.locate();
1176
+ const login = await this.driver.findElement(this.usernameField);
1177
+ await waitElementIsVisible({
1178
+ element: login,
1179
+ driver: this.driver
1180
+ });
1181
+ }
803
1182
  get path() {
804
1183
  return LOGIN_PATH;
805
1184
  }
@@ -837,5 +1216,6 @@ var LoginPage = class extends AbstractPage {
837
1216
  createDriver,
838
1217
  editorFactory,
839
1218
  elementIsNotPresent,
840
- signIn
1219
+ signIn,
1220
+ waitElementIsVisible
841
1221
  });