d5-testing-library 1.2.0 → 1.3.1

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.
@@ -38,11 +38,61 @@ function config(cfg) {
38
38
  return configInstance.config(cfg);
39
39
  }
40
40
 
41
+ // src/pageObjects/AbstractElement.ts
42
+ import { By } from "selenium-webdriver";
43
+
44
+ // src/utils/waitElementIsVisible.ts
45
+ import { until } from "selenium-webdriver";
46
+
47
+ // src/utils/wait.ts
48
+ async function wait(condition, driver, errorMessage, timeout) {
49
+ driver = driver ?? config().driver;
50
+ await driver.wait(condition, timeout ?? config().timeout, errorMessage);
51
+ }
52
+
53
+ // src/utils/waitElementIsVisible.ts
54
+ async function waitElementIsVisible({
55
+ element,
56
+ timeout,
57
+ errorMessage,
58
+ driver
59
+ }) {
60
+ driver = driver ?? config().driver;
61
+ const condition = until.elementIsVisible(element);
62
+ await wait(condition.fn, driver, errorMessage ?? condition.description(), timeout ?? config().timeout);
63
+ }
64
+
41
65
  // src/pageObjects/AbstractElement.ts
42
66
  var AbstractElement = class {
43
67
  driver;
44
- constructor(driver) {
68
+ elementCssSelector;
69
+ constructor(driver, elementCssSelector) {
45
70
  this.driver = driver || config().driver;
71
+ this.elementCssSelector = elementCssSelector;
72
+ }
73
+ getFullCssSelector() {
74
+ return this.elementCssSelector;
75
+ }
76
+ joinRelativeCssSelectors(selectors) {
77
+ return selectors.join(" ");
78
+ }
79
+ async getElement() {
80
+ return this.driver.findElement(By.css(this.getFullCssSelector()));
81
+ }
82
+ async getAttribute(attr) {
83
+ const element = await this.getElement();
84
+ await waitElementIsVisible({
85
+ element,
86
+ driver: this.driver,
87
+ errorMessage: `Element not found: ${this.getFullCssSelector()}`
88
+ });
89
+ return await element.getAttribute(attr);
90
+ }
91
+ async getClasses() {
92
+ return await this.getAttribute("class");
93
+ }
94
+ async getDataTestId() {
95
+ return await this.getAttribute("data-testid");
46
96
  }
47
97
  };
48
98
 
@@ -75,13 +125,57 @@ var AbstractPage = class extends AbstractElement {
75
125
  }
76
126
  };
77
127
 
128
+ // src/utils/actions.ts
129
+ var click = async (webElement, driver) => {
130
+ driver = driver ?? config().driver;
131
+ const actions = driver.actions({ async: true });
132
+ await actions.move({ origin: webElement }).click().perform();
133
+ };
134
+
78
135
  // src/utils/locators.ts
79
- import { By } from "selenium-webdriver";
136
+ import { By as By2 } from "selenium-webdriver";
80
137
  var byTestIdCssSelector = (testId, element = "div") => {
81
138
  return `${element}[data-testid="${testId}"]`;
82
139
  };
83
140
  var byTestId = (testId, element = "div") => {
84
- return By.css(byTestIdCssSelector(testId, element));
141
+ return By2.css(byTestIdCssSelector(testId, element));
142
+ };
143
+ var readonlyLocator = "readonly";
144
+
145
+ // src/pageObjects/pages/LoginPage.ts
146
+ var LOGIN_PATH = "/login";
147
+ var LoginPage = class extends AbstractPage {
148
+ usernameField = byTestId("loginField", "input");
149
+ passwordField = byTestId("passwordField", "input");
150
+ loginButton = byTestId("loginButton");
151
+ async locate() {
152
+ await super.locate();
153
+ const login = await this.driver.findElement(this.usernameField);
154
+ await waitElementIsVisible({
155
+ element: login,
156
+ driver: this.driver
157
+ });
158
+ }
159
+ get path() {
160
+ return LOGIN_PATH;
161
+ }
162
+ async enterUsername(username) {
163
+ await this.driver.findElement(this.usernameField).sendKeys(username);
164
+ }
165
+ async enterPassword(password) {
166
+ await this.driver.findElement(this.passwordField).sendKeys(password);
167
+ }
168
+ async clickLoginButton() {
169
+ await click(await this.driver.findElement(this.loginButton), this.driver);
170
+ }
171
+ async loginWith(username, password) {
172
+ await this.enterUsername(username);
173
+ await this.enterPassword(password);
174
+ await this.clickLoginButton();
175
+ }
176
+ async authorize() {
177
+ await this.loginWith(config().auth.login, config().auth.password);
178
+ }
85
179
  };
86
180
 
87
181
  // src/utils/createDriver.ts
@@ -103,36 +197,22 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
103
197
  });
104
198
  };
105
199
 
106
- // src/utils/waitElementIsVisible.ts
107
- import { until } from "selenium-webdriver";
108
-
109
- // src/utils/wait.ts
110
- async function wait(condition, driver, errorMessage, timeout) {
111
- driver = driver ?? config().driver;
112
- await driver.wait(condition, timeout ?? config().timeout, errorMessage);
113
- }
114
-
115
- // src/utils/waitElementIsVisible.ts
116
- async function waitElementIsVisible({
117
- element,
118
- timeout,
119
- errorMessage,
120
- driver
121
- }) {
122
- driver = driver ?? config().driver;
123
- const condition = until.elementIsVisible(element);
124
- await wait(condition.fn, driver, errorMessage ?? condition.description(), timeout ?? config().timeout);
200
+ // src/utils/signIn.ts
201
+ async function signIn(driver) {
202
+ const webDriver = driver ?? await createDriver();
203
+ config().driver = webDriver;
204
+ const loginPage = new LoginPage(webDriver);
205
+ await loginPage.locate();
206
+ await loginPage.authorize();
207
+ return webDriver;
125
208
  }
126
209
 
127
210
  // src/pageObjects/AbstractElementWithParent.ts
128
- import { By as By3 } from "selenium-webdriver";
129
211
  var AbstractElementWithParent = class extends AbstractElement {
130
- elementCssSelector;
131
212
  parentCssSelector;
132
213
  constructor(parentCssSelector, elementCssSelector, driver) {
133
- super(driver);
214
+ super(driver, elementCssSelector);
134
215
  this.parentCssSelector = parentCssSelector;
135
- this.elementCssSelector = elementCssSelector;
136
216
  }
137
217
  getFullCssSelector() {
138
218
  if (!this.elementCssSelector) {
@@ -143,20 +223,10 @@ var AbstractElementWithParent = class extends AbstractElement {
143
223
  }
144
224
  return `${this.parentCssSelector} ${this.elementCssSelector}`;
145
225
  }
146
- async getElement() {
147
- return this.driver.findElement(By3.css(this.getFullCssSelector()));
148
- }
149
- async getAttribute(attr) {
150
- const element = await this.getElement();
151
- await waitElementIsVisible({
152
- element,
153
- driver: this.driver,
154
- errorMessage: `Element not found: ${this.getFullCssSelector()}`
155
- });
156
- return await element.getAttribute(attr);
157
- }
158
- async getClasses() {
159
- return await this.getAttribute("class");
226
+ async isReadonly() {
227
+ const fieldEl = await this.getElement();
228
+ const classSting = await fieldEl.getAttribute("class");
229
+ return classSting.includes(readonlyLocator);
160
230
  }
161
231
  };
162
232
 
@@ -175,8 +245,10 @@ var SubsystemsPanel = class extends AbstractElement {
175
245
  super(driver);
176
246
  this.header = new SubsystemsPanelHeader("#aside", byTestIdCssSelector("subsystems-panel-title", "span"), this.driver);
177
247
  }
178
- headerTitle() {
179
- return this.header.title().then((el) => el.getText());
248
+ async headerTitle() {
249
+ const title = await this.header.title();
250
+ await wait(async () => await title.getText() != "", this.driver);
251
+ return title.getText();
180
252
  }
181
253
  };
182
254
 
@@ -213,10 +285,10 @@ var AbstractForm = class extends AbstractPage {
213
285
  */
214
286
  async exists() {
215
287
  try {
216
- await wait(elementIsNotPresent(this.containerBy), this.driver);
288
+ let elements = await this.driver.findElements(this.containerBy);
289
+ return elements.length > 0;
290
+ } catch (error) {
217
291
  return false;
218
- } catch {
219
- return true;
220
292
  }
221
293
  }
222
294
  /**
@@ -231,7 +303,7 @@ var AbstractForm = class extends AbstractPage {
231
303
  const titleEl2 = await this.driver.findElement(By5.css(`${this.popupContainerCssSelector} .popup-title`));
232
304
  return titleEl2.getText();
233
305
  }
234
- let titleEl = await this.driver.findElement(By5.css(`${this.containerCssSelector} .form-toolbar-name-container`));
306
+ let titleEl = await this.driver.findElement(By5.className("main-toolbar-form-title"));
235
307
  return titleEl.getText();
236
308
  }
237
309
  };
@@ -239,6 +311,29 @@ var AbstractForm = class extends AbstractPage {
239
311
  // src/pageObjects/elements/Forms/FormEdit.ts
240
312
  import { By as By12 } from "selenium-webdriver";
241
313
 
314
+ // src/utils/createDataTestId.ts
315
+ function createDataTestId(formName, itemType, itemName) {
316
+ return `${formName}-${itemType}-${itemName}`;
317
+ }
318
+ function createFieldTestId(formName, itemName) {
319
+ return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
320
+ }
321
+ function createGroupTestId(formName, itemName) {
322
+ return createDataTestId(formName, "group" /* GROUP */, itemName);
323
+ }
324
+ function createFilterTestId(formName, itemName, layout) {
325
+ return createDataTestId(formName, "filter" /* FILTER */, itemName) + `-${layout}`;
326
+ }
327
+ function createDocFilterTestId(formName, itemName) {
328
+ return createFilterTestId(formName, itemName, "dock-panel-filter" /* DOCK_PANEL */);
329
+ }
330
+ function createLayoutFilterTestId(formName, itemName) {
331
+ return createFilterTestId(formName, itemName, "layout-filter" /* LAYOUT */);
332
+ }
333
+ function createTableId(formName) {
334
+ return `${"table" /* TABLE */}-${formName}`;
335
+ }
336
+
242
337
  // src/pageObjects/elements/Editors/AbstractEditor.ts
243
338
  import { By as By6, Key } from "selenium-webdriver";
244
339
 
@@ -431,6 +526,7 @@ var TAGS_SELECTOR = ".dx-tag .tag-text";
431
526
  var DX_TAG_CONTAINER = "dx-tag-container";
432
527
  var DX_TEXTEDITOR_EMPTY2 = "dx-texteditor-empty";
433
528
  var BTN_OK_SELECTOR = ".dx-tagbox-popup-wrapper .dx-popup-bottom .dx-button.dx-popup-done";
529
+ var TAG_BOX_LIST_ITEM_SELECTOR = '.dx-tagbox-popup-wrapper .dx-list-item[aria-selected="true"]';
434
530
  var TagBox = class extends AbstractDXEditorWithInput {
435
531
  constructor(parentCssSelector, elementCssSelector, driver) {
436
532
  super(parentCssSelector, elementCssSelector, driver);
@@ -445,21 +541,21 @@ var TagBox = class extends AbstractDXEditorWithInput {
445
541
  }
446
542
  await this.confirmSelection();
447
543
  }
544
+ async waitOptionSelection() {
545
+ const option = await this.driver.findElement(By9.css(TAG_BOX_LIST_ITEM_SELECTOR));
546
+ await wait(() => option.isDisplayed(), this.driver);
547
+ }
448
548
  async selectOption(inputEl, value, lastElement) {
449
549
  await inputEl.sendKeys(value);
450
550
  const optElement = await inputEl.findElement(By9.xpath(combinedValueXpath(value)));
451
551
  await click(optElement, this.driver);
552
+ await this.waitOptionSelection();
452
553
  if (value !== lastElement) {
453
554
  await inputEl.clear();
454
555
  }
455
556
  }
456
557
  async confirmSelection() {
457
- const inputEl = await this.getInputElement();
458
- const option = await inputEl.findElement(By9.xpath(XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)));
459
558
  const btnOk = await this.driver.findElement(By9.css(BTN_OK_SELECTOR));
460
- await wait(async () => {
461
- return await option.getAttribute("aria-selected") === "true";
462
- }, this.driver);
463
559
  await click(btnOk, this.driver);
464
560
  }
465
561
  async getTagBoxInputValue() {
@@ -469,8 +565,7 @@ var TagBox = class extends AbstractDXEditorWithInput {
469
565
  const tags = await this.driver.findElements(By9.css(`${this.getFullCssSelector()} .${DX_TAG_CONTAINER} ${TAGS_SELECTOR}`));
470
566
  const values = [];
471
567
  for (const tag of tags) {
472
- const text = await tag.getText();
473
- values.push(text);
568
+ values.push(await tag.getAttribute("textContent"));
474
569
  }
475
570
  return values;
476
571
  }
@@ -607,25 +702,11 @@ var editorFactory = async (parentCssSelector, elementCssSelector, driver) => {
607
702
  throw new Error("Unknown type of editor. Please write ticket to the support");
608
703
  };
609
704
 
610
- // src/utils/createDataTestId.ts
611
- function createDataTestId(formName, itemType, itemName) {
612
- return `${formName}-${itemType}-${itemName}`;
613
- }
614
- function createFieldTestId(formName, itemName) {
615
- return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
616
- }
617
- function createGroupTestId(formName, itemName) {
618
- return createDataTestId(formName, "group" /* GROUP */, itemName);
619
- }
620
- function createTableId(formName) {
621
- return `${"table" /* TABLE */}-${formName}`;
622
- }
623
-
624
- // src/pageObjects/elements/FormField.ts
625
- var FormField = class extends AbstractElementWithParent {
705
+ // src/pageObjects/elements/AbstractEditor.ts
706
+ var AbstractEditor = class extends AbstractElementWithParent {
626
707
  editor;
627
- constructor(parentCssSelector, formName, name, driver) {
628
- super(parentCssSelector, byTestIdCssSelector(createFieldTestId(formName, name)), driver);
708
+ constructor(parentCssSelector, elementCssSelector, driver) {
709
+ super(parentCssSelector, elementCssSelector, driver);
629
710
  }
630
711
  async initEditor() {
631
712
  if (!this.editor) {
@@ -676,6 +757,23 @@ var FormField = class extends AbstractElementWithParent {
676
757
  }
677
758
  return this.editor.remove(itemText);
678
759
  }
760
+ /**
761
+ * Возвращает значение true|false в зависимости readOnly поле или нет
762
+ * @example
763
+ * expect(await formEdit.field('NumberFld').isReadonly()).toBe(true);
764
+ * expect(await formEdit.field('TextFld').isReadonly()).toBe(false);
765
+ */
766
+ async isReadonly() {
767
+ await this.initEditor();
768
+ return this.editor.isReadonly();
769
+ }
770
+ };
771
+
772
+ // src/pageObjects/elements/FormField.ts
773
+ var FormField = class extends AbstractEditor {
774
+ constructor(parentCssSelector, formName, name, driver) {
775
+ super(parentCssSelector, byTestIdCssSelector(createFieldTestId(formName, name)), driver);
776
+ }
679
777
  };
680
778
 
681
779
  // src/pageObjects/elements/Groups/AbstractGroup.ts
@@ -728,6 +826,7 @@ var FormGroup = class extends AbstractElementWithParent {
728
826
  // src/pageObjects/elements/Forms/FormEdit.ts
729
827
  var FormEdit = class extends AbstractForm {
730
828
  saveButtonBy = By12.id("button-save");
829
+ closeButtonBy = By12.id("button-cancel");
731
830
  constructor(driver) {
732
831
  super(driver);
733
832
  this.popupContainerCssSelector = `.popup .form-edit-${this.formName}`;
@@ -776,12 +875,26 @@ var FormEdit = class extends AbstractForm {
776
875
  await wait(async () => !await this.isSaveButtonDisabled(), this.driver, "Button is disabled");
777
876
  await click(saveButton, this.driver);
778
877
  }
878
+ /**
879
+ * Нажатие на кнопку Закрить
880
+ * @example
881
+ * const formEdit = new MyForm();
882
+ * //...
883
+ * await formEdit.closeButtonClick();
884
+ */
885
+ async closeButtonClick() {
886
+ const closeButton = await this.driver.findElement(this.closeButtonBy);
887
+ await click(closeButton, this.driver);
888
+ }
779
889
  };
780
890
 
781
891
  // src/pageObjects/elements/Table/Table.ts
782
- import { By as By16 } from "selenium-webdriver";
892
+ import { By as By17 } from "selenium-webdriver";
783
893
 
784
894
  // src/pageObjects/elements/Table/elements/Row.ts
895
+ import { By as By15 } from "selenium-webdriver";
896
+
897
+ // src/pageObjects/elements/Table/elements/Cell.ts
785
898
  import { By as By14 } from "selenium-webdriver";
786
899
 
787
900
  // src/pageObjects/elements/Table/utils.ts
@@ -791,6 +904,7 @@ function getCssRowByIndexSelector(index) {
791
904
  }
792
905
  var getColumnByIndexCssSelector = (columnIndex) => `td[aria-colindex="${transformInputIndex(columnIndex)}"]`;
793
906
  var getColumnByCaptionCssSelector = (caption) => `td[role="columnheader"][aria-label="Column ${caption}"]`;
907
+ var getColumnByNameCssSelector = (name) => `td[role="columnheader"][data-fieldname="${name}"]`;
794
908
  function getCssCellByIndexSelector(index) {
795
909
  return `td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`;
796
910
  }
@@ -810,6 +924,10 @@ var Cell = class extends AbstractElementWithParent {
810
924
  this._index = index;
811
925
  this.elementCssSelector = getCssCellByIndexSelector(index);
812
926
  }
927
+ async getBooleanValue(cellEl) {
928
+ const booleanEl = await cellEl.findElement(By14.className("boolean-widget"));
929
+ return await booleanEl.getAttribute("aria-checked") === "true" ? 1 : 0;
930
+ }
813
931
  async getElement() {
814
932
  if (this._index == null) {
815
933
  this.index = await this.getCellIndex();
@@ -818,6 +936,10 @@ var Cell = class extends AbstractElementWithParent {
818
936
  }
819
937
  async getValue() {
820
938
  const cellEl = await this.getElement();
939
+ const cellElClass = await cellEl.getAttribute("class");
940
+ if (cellElClass.includes("boolean-column")) {
941
+ return this.getBooleanValue(cellEl);
942
+ }
821
943
  return cellEl.getText();
822
944
  }
823
945
  getIndex() {
@@ -831,22 +953,25 @@ var DX_ROW_EDIT_CLASS = "dx-edit-row";
831
953
  var DX_DATA_ROW_CLASS = "dx-data-row";
832
954
  var Row = class extends AbstractElementWithParent {
833
955
  index;
834
- getColumnByCaption;
835
- constructor(parentCssSelector, index, driver, getColumnByCaption) {
956
+ getColumnBy;
957
+ constructor(parentCssSelector, index, driver, getColumnBy) {
836
958
  super(parentCssSelector, getCssRowByIndexSelector(index), driver);
837
959
  this.index = index;
838
- this.getColumnByCaption = getColumnByCaption;
960
+ this.getColumnBy = getColumnBy;
839
961
  }
840
- _getCell(index, caption) {
962
+ _getCell({ index, name, title }) {
841
963
  return new Cell(this.getFullCssSelector(), () => {
842
- return this.getColumnByCaption(caption).getIndex();
964
+ return this.getColumnBy({ title, name }).getIndex();
843
965
  }, index, this.driver);
844
966
  }
845
967
  getCellByIndex(index) {
846
- return this._getCell(index);
968
+ return this._getCell({ index });
847
969
  }
848
- getCell(caption) {
849
- return this._getCell(void 0, caption);
970
+ getCell(name) {
971
+ return this._getCell({ name });
972
+ }
973
+ getCellByTitle(title) {
974
+ return this._getCell({ title });
850
975
  }
851
976
  async select() {
852
977
  const rowEl = await this.getElement();
@@ -864,7 +989,7 @@ var Row = class extends AbstractElementWithParent {
864
989
  return this.index;
865
990
  }
866
991
  async getCells() {
867
- const cells = await this.driver.findElements(By14.css(`${this.getFullCssSelector()} td[role="gridcell"]`));
992
+ const cells = await this.driver.findElements(By15.css(`${this.getFullCssSelector()} td[role="gridcell"]`));
868
993
  const result = [];
869
994
  cells.forEach((_, index) => {
870
995
  const newCell = this.getCellByIndex(index);
@@ -875,7 +1000,7 @@ var Row = class extends AbstractElementWithParent {
875
1000
  async clickInlineButton(buttonClass) {
876
1001
  const FIXED_TABLE_CSS_SELECTOR = ".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed";
877
1002
  const buttonCssSelector = `.${DX_DATA_ROW_CLASS}[aria-rowindex="${transformInputIndex(this.index)}"] .${buttonClass}`;
878
- const button = await this.driver.findElement(By14.css(`${this.parentCssSelector} ${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`));
1003
+ const button = await this.driver.findElement(By15.css(`${this.parentCssSelector} ${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`));
879
1004
  return click(button, this.driver);
880
1005
  }
881
1006
  async checkEditingMode(isEditing, msg) {
@@ -898,15 +1023,17 @@ var Row = class extends AbstractElementWithParent {
898
1023
  };
899
1024
 
900
1025
  // src/pageObjects/elements/Table/elements/Column.ts
901
- import { By as By15 } from "selenium-webdriver";
1026
+ import { By as By16 } from "selenium-webdriver";
902
1027
  var getHeaderCssSelector = () => {
903
1028
  return ".dx-datagrid-headers .dx-datagrid-content:not(.dx-datagrid-content-fixed)";
904
1029
  };
905
1030
  var Column = class extends AbstractElementWithParent {
906
1031
  _index;
907
1032
  _caption;
908
- constructor(parentCssSelector, caption, index, driver) {
1033
+ _name;
1034
+ constructor({ parentCssSelector, name, caption, index, driver }) {
909
1035
  super(parentCssSelector, "", driver);
1036
+ this._name = name;
910
1037
  this.index = index;
911
1038
  this._caption = caption;
912
1039
  }
@@ -921,19 +1048,33 @@ var Column = class extends AbstractElementWithParent {
921
1048
  await this.getIndex();
922
1049
  return super.getElement();
923
1050
  }
924
- async getIndexByCaption() {
925
- const column = await this.driver.findElement(By15.css(`${this.parentCssSelector} ${getHeaderCssSelector()} ${getColumnByCaptionCssSelector(this._caption)}`));
1051
+ async getColumnHeaderIndexBy(cssSelector) {
1052
+ const column = await this.driver.findElement(By16.css(`${this.parentCssSelector} ${getHeaderCssSelector()} ${cssSelector}`));
926
1053
  return transformOutputIndex(await column.getAttribute("aria-colindex"));
927
1054
  }
1055
+ async getIndexByCaption() {
1056
+ return this.getColumnHeaderIndexBy(getColumnByCaptionCssSelector(this._caption));
1057
+ }
1058
+ async getIndexByName() {
1059
+ return this.getColumnHeaderIndexBy(getColumnByNameCssSelector(this._name));
1060
+ }
928
1061
  async caption() {
929
1062
  const el = await this.getElement();
930
1063
  return el.getText();
931
1064
  }
932
1065
  async getIndex() {
933
- if (this.index == null) {
1066
+ if (this.index != null) {
1067
+ return this.index;
1068
+ }
1069
+ if (this._caption != null) {
934
1070
  this.index = await this.getIndexByCaption();
1071
+ return this.index;
935
1072
  }
936
- return this.index;
1073
+ if (this._name != null) {
1074
+ this.index = await this.getIndexByName();
1075
+ return this.index;
1076
+ }
1077
+ throw new Error("Cant get the index in the column");
937
1078
  }
938
1079
  };
939
1080
 
@@ -944,32 +1085,57 @@ var Table = class extends AbstractElementWithParent {
944
1085
  super(parentCssSelector, `#${createTableId(formName)}`, driver);
945
1086
  this.formName = formName;
946
1087
  }
1088
+ getColumnBy = (args) => {
1089
+ if (args.title) {
1090
+ return this.getColumnByTitle(args.title);
1091
+ }
1092
+ return this.getColumnByName(args.name);
1093
+ };
947
1094
  getRowByIndex(index) {
948
- return new Row(this.getFullCssSelector(), index, this.driver, this.getColumnByCaption.bind(this));
1095
+ return new Row(this.getFullCssSelector(), index, this.driver, this.getColumnBy);
949
1096
  }
950
1097
  getColumnByIndex(index) {
951
- return new Column(this.getFullCssSelector(), void 0, index, this.driver);
1098
+ return new Column({
1099
+ parentCssSelector: this.getFullCssSelector(),
1100
+ driver: this.driver,
1101
+ index
1102
+ });
952
1103
  }
953
- getColumnByCaption = (caption) => {
954
- return new Column(this.getFullCssSelector(), caption, void 0, this.driver);
1104
+ getColumnByTitle = (title) => {
1105
+ return new Column({
1106
+ parentCssSelector: this.getFullCssSelector(),
1107
+ caption: title,
1108
+ driver: this.driver
1109
+ });
1110
+ };
1111
+ getColumnByName = (name) => {
1112
+ return new Column({
1113
+ parentCssSelector: this.getFullCssSelector(),
1114
+ name,
1115
+ driver: this.driver
1116
+ });
955
1117
  };
956
1118
  selectRowByIndex(index) {
957
1119
  return this.getRowByIndex(index).select();
958
1120
  }
959
1121
  async getRows() {
960
- const rows = await this.driver.findElements(By16.css(`${this.getFullCssSelector()} .dx-row.dx-data-row`));
1122
+ const rows = await this.driver.findElements(By17.css(`${this.getFullCssSelector()} .dx-row.dx-data-row`));
961
1123
  const result = [];
962
1124
  rows.forEach((_, index) => {
963
- const newRow = new Row(this.getFullCssSelector(), index, this.driver, this.getColumnByCaption);
1125
+ const newRow = new Row(this.getFullCssSelector(), index, this.driver, this.getColumnBy);
964
1126
  result.push(newRow);
965
1127
  });
966
1128
  return result;
967
1129
  }
968
1130
  async getColumns() {
969
- const columns = await this.driver.findElements(By16.css(`${this.getFullCssSelector()} ${getHeaderCssSelector()} td[role="columnheader"]`));
1131
+ const columns = await this.driver.findElements(By17.css(`${this.getFullCssSelector()} ${getHeaderCssSelector()} td[role="columnheader"]`));
970
1132
  const result = [];
971
1133
  columns.forEach((_, index) => {
972
- const newCol = new Column(this.getFullCssSelector(), void 0, index, this.driver);
1134
+ const newCol = new Column({
1135
+ parentCssSelector: this.getFullCssSelector(),
1136
+ index,
1137
+ driver: this.driver
1138
+ });
973
1139
  result.push(newCol);
974
1140
  });
975
1141
  return result;
@@ -989,19 +1155,16 @@ var Table = class extends AbstractElementWithParent {
989
1155
  }
990
1156
  };
991
1157
 
992
- // src/pageObjects/elements/TableToolbar/TableToolbarButton.ts
993
- var TOOLBAR_BUTTON_CLASS = "toolbar-button";
994
- var TableToolbarButton = class extends AbstractElementWithParent {
995
- name;
996
- constructor(parentCssSelector, name, driver) {
997
- super(parentCssSelector, `#${TOOLBAR_BUTTON_CLASS}-${name}`, driver);
998
- this.name = name;
1158
+ // src/pageObjects/elements/TableToolbar/AbstractButton.ts
1159
+ var AbstractButton = class extends AbstractElementWithParent {
1160
+ constructor(parentCssSelector, elementCssSelector, driver) {
1161
+ super(parentCssSelector, elementCssSelector, driver);
999
1162
  }
1000
1163
  async click() {
1001
1164
  const button = await this.getElement();
1002
1165
  await wait(async () => {
1003
1166
  return await button.isDisplayed() && !await this.isDisabled();
1004
- }, this.driver, `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`);
1167
+ }, this.driver, this.buttonNotDisplayedError());
1005
1168
  await click(button, this.driver);
1006
1169
  }
1007
1170
  async isDisabled() {
@@ -1010,14 +1173,289 @@ var TableToolbarButton = class extends AbstractElementWithParent {
1010
1173
  }
1011
1174
  };
1012
1175
 
1013
- // src/pageObjects/elements/TableToolbar/TableToolbar.ts
1176
+ // src/pageObjects/elements/TableToolbar/ToolbarGroupButton.ts
1177
+ var ToolbarGroupButton = class extends AbstractButton {
1178
+ name;
1179
+ constructor(parentCssSelector, name, driver) {
1180
+ super(parentCssSelector, ``, driver);
1181
+ this.name = name;
1182
+ }
1183
+ buttonNotDisplayedError() {
1184
+ return `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`;
1185
+ }
1186
+ };
1187
+
1188
+ // src/pageObjects/elements/TableToolbar/ToolbarButton.ts
1189
+ var TOOLBAR_BUTTON_CLASS = "toolbar-button";
1190
+ var ToolbarButton = class extends AbstractButton {
1191
+ name;
1192
+ constructor(parentCssSelector, name, driver) {
1193
+ super(parentCssSelector, `#${TOOLBAR_BUTTON_CLASS}-${name}`, driver);
1194
+ this.name = name;
1195
+ }
1196
+ buttonNotDisplayedError() {
1197
+ return `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`;
1198
+ }
1199
+ };
1200
+
1201
+ // src/pageObjects/elements/TableToolbar/ToolbarMenu.ts
1202
+ import { By as By18 } from "selenium-webdriver";
1203
+
1204
+ // src/utils/typesUtil.ts
1205
+ var types = {
1206
+ "[object Array]": "array",
1207
+ "[object Date]": "date",
1208
+ "[object Object]": "object",
1209
+ "[object String]": "string",
1210
+ "[object Null]": "null"
1211
+ };
1212
+ var type = function(object) {
1213
+ const typeOfObject = Object.prototype.toString.call(object);
1214
+ return typeof object === "object" ? types[typeOfObject] || "object" : typeof object;
1215
+ };
1216
+ var isArray = function(value) {
1217
+ return type(value) === "array";
1218
+ };
1219
+ var isString = function(object) {
1220
+ return typeof object === "string";
1221
+ };
1222
+
1223
+ // src/pageObjects/elements/TableToolbar/ToolbarMenu.ts
1224
+ var SPINDOWN_CLASS = ".dx-icon-spindown";
1225
+ var buttonGroupItemSelector = (formName, name) => byTestIdCssSelector(`ftb-${formName}-${name}`);
1226
+ var getFullCssSelector = (formName, name) => `${buttonGroupItemSelector(formName, name)} ${SPINDOWN_CLASS}`;
1227
+ var buttonByTextXpath = (text) => `.//span[contains(@class, "dx-menu-item-text") and contains(text(), "${text}")]`;
1228
+ var ToolbarMenu = class extends AbstractElementWithParent {
1229
+ _formName;
1230
+ constructor(parentCssSelector, formName, name, driver) {
1231
+ super(parentCssSelector, getFullCssSelector(formName, name), driver);
1232
+ this._formName = formName;
1233
+ }
1234
+ async toggle() {
1235
+ const dropdown = await this.getElement();
1236
+ await dropdown.click();
1237
+ }
1238
+ getCssSelectorToButton(name) {
1239
+ return byTestId(`ftb-${this._formName}-${name}`);
1240
+ }
1241
+ buttonNotDisplayedError(name) {
1242
+ return `Toolbar menu button ${name} cannot be clicked. It is not displayed or it is disabled`;
1243
+ }
1244
+ async goToButton(name, selector) {
1245
+ const toolbarMenuItem = this.driver.findElement(selector);
1246
+ await wait(async () => {
1247
+ return await toolbarMenuItem.isDisplayed();
1248
+ }, this.driver, this.buttonNotDisplayedError(name));
1249
+ await click(toolbarMenuItem, this.driver);
1250
+ }
1251
+ async clickButton(name) {
1252
+ await this.toggle();
1253
+ if (isString(name)) {
1254
+ const selector = this.getCssSelectorToButton(name);
1255
+ await this.goToButton(name, selector);
1256
+ }
1257
+ if (isArray(name)) {
1258
+ for (let n of name) {
1259
+ const selector = this.getCssSelectorToButton(n);
1260
+ await this.goToButton(n, selector);
1261
+ }
1262
+ }
1263
+ }
1264
+ async clickButtonByTitle(title) {
1265
+ await this.toggle();
1266
+ if (isString(title)) {
1267
+ const selector = By18.xpath(buttonByTextXpath(title));
1268
+ await this.goToButton(title, selector);
1269
+ }
1270
+ if (isArray(title)) {
1271
+ for (let t of title) {
1272
+ const selector = By18.xpath(buttonByTextXpath(t));
1273
+ await this.goToButton(t, selector);
1274
+ }
1275
+ }
1276
+ }
1277
+ };
1278
+
1279
+ // src/pageObjects/elements/TableToolbar/ToolbarItem.ts
1280
+ var GROUP_BUTTON_CLASS = "toolbar-group-button";
1281
+ var toolbarItemSelector = (form, name) => byTestIdCssSelector(`ftb-${form}-${name}`);
1282
+ var ToolbarItem = class extends AbstractElementWithParent {
1283
+ _button;
1284
+ _formName;
1285
+ _itemName;
1286
+ constructor(parentCssSelector, formName, itemName, driver) {
1287
+ super(parentCssSelector, toolbarItemSelector(formName, itemName), driver);
1288
+ this._itemName = itemName;
1289
+ this._formName = formName;
1290
+ }
1291
+ async init() {
1292
+ if (this._button)
1293
+ return this._button;
1294
+ const classNames = await this.getClasses();
1295
+ if (classNames.includes(GROUP_BUTTON_CLASS)) {
1296
+ this._button = new ToolbarGroupButton(this.getFullCssSelector(), this._itemName, this.driver);
1297
+ return;
1298
+ }
1299
+ this._button = new ToolbarButton(this.parentCssSelector, this._itemName, this.driver);
1300
+ }
1301
+ async click() {
1302
+ await this.init();
1303
+ await this._button.click();
1304
+ }
1305
+ async isDisabled() {
1306
+ await this.init();
1307
+ return await this._button.isDisabled();
1308
+ }
1309
+ get menu() {
1310
+ return new ToolbarMenu(this.parentCssSelector, this._formName, this._itemName, this.driver);
1311
+ }
1312
+ };
1313
+
1314
+ // src/pageObjects/elements/TableToolbar/FormToolbar.ts
1014
1315
  var TABLE_TOOLBAR_CLASS = "d5-table-toolbar";
1015
- var TableToolbar = class extends AbstractElementWithParent {
1316
+ var FormToolbar = class extends AbstractElementWithParent {
1317
+ formName;
1016
1318
  constructor(parentCssSelector, formName, driver) {
1017
1319
  super(parentCssSelector, `#${TABLE_TOOLBAR_CLASS}-${formName}`, driver);
1320
+ this.formName = formName;
1018
1321
  }
1019
1322
  button(name) {
1020
- return new TableToolbarButton(this.getFullCssSelector(), name, this.driver);
1323
+ return new ToolbarItem(this.getFullCssSelector(), this.formName, name, this.driver);
1324
+ }
1325
+ };
1326
+
1327
+ // src/pageObjects/elements/Filters/FormFilterField.ts
1328
+ var FormFilterField = class extends AbstractEditor {
1329
+ constructor(parentCssSelector, formName, name, driver) {
1330
+ super(parentCssSelector, byTestIdCssSelector(createLayoutFilterTestId(formName, name)), driver);
1331
+ }
1332
+ /**
1333
+ * Возвращает значение в поле
1334
+ * @example
1335
+ * expect(await form.formFilter('NumberFld').getValue()).toBe(10);
1336
+ * expect(await form.formFilter('TextFld').getValue()).toBe('TestValue');
1337
+ */
1338
+ async getValue() {
1339
+ return super.getValue();
1340
+ }
1341
+ /**
1342
+ * Устанавливает значение в поле
1343
+ * @example
1344
+ * await form.formFilter('NumberFld').setValue(123);
1345
+ * await form.formFilter('TextFld').setValue('TestValue');
1346
+ */
1347
+ async setValue(value) {
1348
+ return super.setValue(value);
1349
+ }
1350
+ /**
1351
+ * Очищает значение в поле
1352
+ * @example
1353
+ * await form.formFilter('NumberFld').clear();
1354
+ */
1355
+ async clear() {
1356
+ return super.clear();
1357
+ }
1358
+ /**
1359
+ * Удаляет тег по переданному тексту
1360
+ * @example
1361
+ * await form.formFilter('TagBox').remove('test');
1362
+ */
1363
+ async remove(itemText) {
1364
+ return super.remove(itemText);
1365
+ }
1366
+ };
1367
+
1368
+ // src/pageObjects/elements/Filters/FilterPanel.ts
1369
+ import { By as By19 } from "selenium-webdriver";
1370
+
1371
+ // src/pageObjects/elements/Filters/PanelFilterField.ts
1372
+ var PanelFilterField = class extends AbstractEditor {
1373
+ constructor(parentCssSelector, formName, name, driver) {
1374
+ super(parentCssSelector, byTestIdCssSelector(createDocFilterTestId(formName, name)), driver);
1375
+ }
1376
+ /**
1377
+ * Возвращает значение в поле
1378
+ * @example
1379
+ * expect(await form.filterPanel.filterField('NumberFld').getValue()).toBe(10);
1380
+ * expect(await form.filterPanel.filterField('TextFld').getValue()).toBe('TestValue');
1381
+ */
1382
+ async getValue() {
1383
+ return super.getValue();
1384
+ }
1385
+ /**
1386
+ * Устанавливает значение в поле
1387
+ * @example
1388
+ * await form.filterPanel.filterField('NumberFld').setValue(123);
1389
+ * await form.filterPanel.filterField('TextFld').setValue('TestValue');
1390
+ */
1391
+ async setValue(value) {
1392
+ return super.setValue(value);
1393
+ }
1394
+ /**
1395
+ * Очищает значение в поле
1396
+ * @example
1397
+ * await form.filterPanel.filterField('NumberFld').clear();
1398
+ */
1399
+ async clear() {
1400
+ return super.clear();
1401
+ }
1402
+ /**
1403
+ * Удаляет тег по переданному тексту
1404
+ * @example
1405
+ * await form.filterPanel.filterField('TagBox').remove('test');
1406
+ */
1407
+ async remove(itemText) {
1408
+ return super.remove(itemText);
1409
+ }
1410
+ };
1411
+
1412
+ // src/pageObjects/elements/Filters/FilterPanel.ts
1413
+ var drawerSelector = (formName) => `.secondary-drawer-side-panel.form-${formName}`;
1414
+ var FILTER_PANEL_SELECTOR = ".filter-panel";
1415
+ var CLOSE_SELECTOR = ".button-close";
1416
+ var FilterPanel = class extends AbstractElement {
1417
+ _formName;
1418
+ get filterPanelSelector() {
1419
+ return `${this.elementCssSelector} ${FILTER_PANEL_SELECTOR}`;
1420
+ }
1421
+ async filterPanelButtons() {
1422
+ const selector = `${this.elementCssSelector} ${FILTER_PANEL_SELECTOR} .filter-panel__buttons-panel .dx-button-text`;
1423
+ const el = await this.getElement();
1424
+ return el.findElements(By19.css(selector));
1425
+ }
1426
+ constructor(formName, driver) {
1427
+ super(driver, drawerSelector(formName));
1428
+ this._formName = formName;
1429
+ }
1430
+ /**
1431
+ * Возвращает фильтр на панели фильтрации
1432
+ * @returns {PanelFilterField}
1433
+ * @example
1434
+ * await form.filterPanel.filterField('NumberFld');
1435
+ */
1436
+ filterField(name) {
1437
+ return new PanelFilterField(this.filterPanelSelector, this._formName, name, this.driver);
1438
+ }
1439
+ async apply() {
1440
+ const btn = await this.findButtonByTitle("\u0417\u0430\u0441\u0442\u043E\u0441\u0443\u0432\u0430\u0442\u0438");
1441
+ await click(btn, this.driver);
1442
+ }
1443
+ async findButtonByTitle(title) {
1444
+ const buttons = await this.filterPanelButtons();
1445
+ for (const btn of buttons) {
1446
+ if (await btn.getText() === title) {
1447
+ return btn;
1448
+ }
1449
+ }
1450
+ }
1451
+ async clearAll() {
1452
+ const btn = await this.findButtonByTitle("\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438");
1453
+ await click(btn, this.driver);
1454
+ await this.driver.sleep(300);
1455
+ }
1456
+ async close() {
1457
+ const btn = await this.driver.findElement(By19.css(`${this.elementCssSelector} ${CLOSE_SELECTOR}`));
1458
+ await click(btn, this.driver);
1021
1459
  }
1022
1460
  };
1023
1461
 
@@ -1055,70 +1493,89 @@ var ListForm = class extends AbstractForm {
1055
1493
  * expect(listForm.toolbarButton());
1056
1494
  */
1057
1495
  toolbarButton(name) {
1058
- const toolbar = new TableToolbar(this.containerCssSelector, this.formName, this.driver);
1496
+ const toolbar = new FormToolbar(this.containerCssSelector, this.formName, this.driver);
1059
1497
  return toolbar.button(name);
1060
1498
  }
1499
+ /**
1500
+ * Фильтр который расположен на форме
1501
+ * @example
1502
+ * const listForm = new MyForm();
1503
+ * //...
1504
+ * expect(listForm.formFilter());
1505
+ */
1506
+ formFilter(name) {
1507
+ return new FormFilterField(this.containerCssSelector, this.formName, name, this.driver);
1508
+ }
1509
+ /**
1510
+ * Модель панели фильтрации
1511
+ * @returns {FilterPanel}
1512
+ * @example
1513
+ * const listForm = new MyForm();
1514
+ * //...
1515
+ * expect(listForm.filterPanel());
1516
+ */
1517
+ get filterPanel() {
1518
+ return new FilterPanel(this.formName, this.driver);
1519
+ }
1061
1520
  };
1062
1521
 
1063
- // src/utils/signIn.ts
1064
- async function signIn(driver) {
1065
- const webDriver = driver ?? await createDriver();
1066
- config().driver = webDriver;
1067
- const loginPage = new LoginPage(webDriver);
1068
- await loginPage.locate();
1069
- await loginPage.authorize();
1070
- return webDriver;
1071
- }
1072
-
1073
- // src/utils/actions.ts
1074
- var click = async (webElement, driver) => {
1075
- driver = driver ?? config().driver;
1076
- const actions = driver.actions({ async: true });
1077
- await actions.move({ origin: webElement }).click().perform();
1522
+ // src/pageObjects/elements/Dialog.ts
1523
+ import { By as By20 } from "selenium-webdriver";
1524
+ var DIALOG_CLASS = ".d5-dialog";
1525
+ var DIALOG_TITLE_CLASS = ".dialog__title";
1526
+ var DIALOG_TEXT_CLASS = ".dialog__text";
1527
+ var DIALOG_BUTTONS_PANEL_CLASS = ".dialog__buttons-panel";
1528
+ var buttonByTextXpath2 = (text) => `.//span[contains(@class, "dx-button-text") and contains(text(), "${text}")]`;
1529
+ var DialogButton = class extends AbstractButton {
1530
+ text;
1531
+ constructor(parentCssSelector, text, driver) {
1532
+ super(parentCssSelector, "", driver);
1533
+ this.text = text;
1534
+ }
1535
+ async getElement() {
1536
+ const panel = await super.getElement();
1537
+ return panel.findElement(By20.xpath(buttonByTextXpath2(this.text)));
1538
+ }
1539
+ buttonNotDisplayedError() {
1540
+ return `Dialog button ${this.text} cannot be clicked. It is not displayed or it is disabled`;
1541
+ }
1078
1542
  };
1079
-
1080
- // src/pageObjects/pages/LoginPage.ts
1081
- var LOGIN_PATH = "/login";
1082
- var LoginPage = class extends AbstractPage {
1083
- usernameField = byTestId("loginField", "input");
1084
- passwordField = byTestId("passwordField", "input");
1085
- loginButton = byTestId("loginButton");
1086
- async locate() {
1087
- await super.locate();
1088
- const login = await this.driver.findElement(this.usernameField);
1089
- await waitElementIsVisible({
1090
- element: login,
1091
- driver: this.driver
1092
- });
1543
+ var Dialog = class extends AbstractElement {
1544
+ constructor(driver) {
1545
+ super(driver, DIALOG_CLASS);
1093
1546
  }
1094
- get path() {
1095
- return LOGIN_PATH;
1547
+ get titleSelector() {
1548
+ return this.joinRelativeCssSelectors([DIALOG_CLASS, DIALOG_TITLE_CLASS]);
1096
1549
  }
1097
- async enterUsername(username) {
1098
- await this.driver.findElement(this.usernameField).sendKeys(username);
1550
+ get textSelector() {
1551
+ return this.joinRelativeCssSelectors([DIALOG_CLASS, DIALOG_TEXT_CLASS]);
1099
1552
  }
1100
- async enterPassword(password) {
1101
- await this.driver.findElement(this.passwordField).sendKeys(password);
1553
+ get buttonsSelector() {
1554
+ return this.joinRelativeCssSelectors([DIALOG_CLASS, DIALOG_BUTTONS_PANEL_CLASS]);
1102
1555
  }
1103
- async clickLoginButton() {
1104
- await click(await this.driver.findElement(this.loginButton), this.driver);
1556
+ async title() {
1557
+ const el = await this.driver.findElement(By20.css(this.titleSelector));
1558
+ return await el.getText();
1105
1559
  }
1106
- async loginWith(username, password) {
1107
- await this.enterUsername(username);
1108
- await this.enterPassword(password);
1109
- await this.clickLoginButton();
1560
+ async text() {
1561
+ const el = await this.driver.findElement(By20.css(this.textSelector));
1562
+ return await el.getText();
1110
1563
  }
1111
- async authorize() {
1112
- await this.loginWith(config().auth.login, config().auth.password);
1564
+ button(text) {
1565
+ return new DialogButton(this.buttonsSelector, text, this.driver);
1113
1566
  }
1114
1567
  };
1115
1568
  export {
1116
1569
  AbstractPage,
1570
+ Dialog,
1571
+ FilterPanel,
1117
1572
  FormEdit,
1118
1573
  FormField,
1574
+ FormFilterField,
1119
1575
  ListForm,
1120
1576
  LoginPage,
1121
1577
  NumberEditor,
1578
+ PanelFilterField,
1122
1579
  SubsystemsPanel,
1123
1580
  TextEditor,
1124
1581
  byTestId,
@@ -1128,6 +1585,7 @@ export {
1128
1585
  createDriver,
1129
1586
  editorFactory,
1130
1587
  elementIsNotPresent,
1588
+ readonlyLocator,
1131
1589
  signIn,
1132
1590
  wait,
1133
1591
  waitElementIsVisible