d5-testing-library 1.1.0 → 1.3.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.
@@ -38,11 +38,58 @@ 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
+ async getElement() {
77
+ return this.driver.findElement(By.css(this.getFullCssSelector()));
78
+ }
79
+ async getAttribute(attr) {
80
+ const element = await this.getElement();
81
+ await waitElementIsVisible({
82
+ element,
83
+ driver: this.driver,
84
+ errorMessage: `Element not found: ${this.getFullCssSelector()}`
85
+ });
86
+ return await element.getAttribute(attr);
87
+ }
88
+ async getClasses() {
89
+ return await this.getAttribute("class");
90
+ }
91
+ async getDataTestId() {
92
+ return await this.getAttribute("data-testid");
46
93
  }
47
94
  };
48
95
 
@@ -75,10 +122,56 @@ var AbstractPage = class extends AbstractElement {
75
122
  }
76
123
  };
77
124
 
125
+ // src/utils/actions.ts
126
+ var click = async (webElement, driver) => {
127
+ driver = driver ?? config().driver;
128
+ const actions = driver.actions({ async: true });
129
+ await actions.move({ origin: webElement }).click().perform();
130
+ };
131
+
78
132
  // src/utils/locators.ts
79
- import { By } from "selenium-webdriver";
133
+ import { By as By2 } from "selenium-webdriver";
134
+ var byTestIdCssSelector = (testId, element = "div") => {
135
+ return `${element}[data-testid="${testId}"]`;
136
+ };
80
137
  var byTestId = (testId, element = "div") => {
81
- return By.css(`${element}[data-testid="${testId}"]`);
138
+ return By2.css(byTestIdCssSelector(testId, element));
139
+ };
140
+
141
+ // src/pageObjects/pages/LoginPage.ts
142
+ var LOGIN_PATH = "/login";
143
+ var LoginPage = class extends AbstractPage {
144
+ usernameField = byTestId("loginField", "input");
145
+ passwordField = byTestId("passwordField", "input");
146
+ loginButton = byTestId("loginButton");
147
+ async locate() {
148
+ await super.locate();
149
+ const login = await this.driver.findElement(this.usernameField);
150
+ await waitElementIsVisible({
151
+ element: login,
152
+ driver: this.driver
153
+ });
154
+ }
155
+ get path() {
156
+ return LOGIN_PATH;
157
+ }
158
+ async enterUsername(username) {
159
+ await this.driver.findElement(this.usernameField).sendKeys(username);
160
+ }
161
+ async enterPassword(password) {
162
+ await this.driver.findElement(this.passwordField).sendKeys(password);
163
+ }
164
+ async clickLoginButton() {
165
+ await click(await this.driver.findElement(this.loginButton), this.driver);
166
+ }
167
+ async loginWith(username, password) {
168
+ await this.enterUsername(username);
169
+ await this.enterPassword(password);
170
+ await this.clickLoginButton();
171
+ }
172
+ async authorize() {
173
+ await this.loginWith(config().auth.login, config().auth.password);
174
+ }
82
175
  };
83
176
 
84
177
  // src/utils/createDriver.ts
@@ -100,78 +193,67 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
100
193
  });
101
194
  };
102
195
 
103
- // src/utils/waitElementIsVisible.ts
104
- import { until } from "selenium-webdriver";
105
- async function waitElementIsVisible({ element, timeout, errorMessage, driver }) {
106
- driver = driver ?? config().driver;
107
- const condition = until.elementIsVisible(element);
108
- await driver.wait(condition.fn, timeout ?? 1e4, errorMessage ?? condition.description());
196
+ // src/utils/signIn.ts
197
+ async function signIn(driver) {
198
+ const webDriver = driver ?? await createDriver();
199
+ config().driver = webDriver;
200
+ const loginPage = new LoginPage(webDriver);
201
+ await loginPage.locate();
202
+ await loginPage.authorize();
203
+ return webDriver;
109
204
  }
110
205
 
111
206
  // src/pageObjects/AbstractElementWithParent.ts
112
207
  var AbstractElementWithParent = class extends AbstractElement {
113
- getParentElement;
114
- elementBy;
115
- constructor(getParentElement, driver) {
116
- super(driver);
117
- this.getParentElement = getParentElement;
118
- }
119
- async getElement() {
120
- const parentEl = await this.getParentElement();
121
- await waitElementIsVisible({
122
- element: parentEl,
123
- driver: this.driver
124
- });
125
- const el = await parentEl.findElement(this.elementBy);
126
- await waitElementIsVisible({
127
- element: el,
128
- driver: this.driver
129
- });
130
- return el;
131
- }
132
- async getAttribute(attr) {
133
- const el = await this.getElement();
134
- return await el.getAttribute(attr);
135
- }
136
- async getClasses() {
137
- return await this.getAttribute("class");
208
+ parentCssSelector;
209
+ constructor(parentCssSelector, elementCssSelector, driver) {
210
+ super(driver, elementCssSelector);
211
+ this.parentCssSelector = parentCssSelector;
212
+ }
213
+ getFullCssSelector() {
214
+ if (!this.elementCssSelector) {
215
+ return this.parentCssSelector;
216
+ }
217
+ if (!this.parentCssSelector) {
218
+ return this.elementCssSelector;
219
+ }
220
+ return `${this.parentCssSelector} ${this.elementCssSelector}`;
138
221
  }
139
222
  };
140
223
 
141
224
  // src/pageObjects/elements/SubsystemsPanel/SubsystemsPanelHeader.ts
225
+ import { By as By4 } from "selenium-webdriver";
142
226
  var SubsystemsPanelHeader = class extends AbstractElementWithParent {
143
- titleBy = byTestId("subsystems-panel-title", "span");
144
227
  async title() {
145
- const panel = await this.getParentElement();
146
- return panel.findElement(this.titleBy);
228
+ return this.driver.findElement(By4.css(this.getFullCssSelector()));
147
229
  }
148
230
  };
149
231
 
150
232
  // src/pageObjects/elements/SubsystemsPanel/SubsystemsPanel.ts
151
- import { By as By3 } from "selenium-webdriver";
152
233
  var SubsystemsPanel = class extends AbstractElement {
153
- panelBy = By3.id("aside");
154
234
  header;
155
235
  constructor(driver) {
156
236
  super(driver);
157
- this.header = new SubsystemsPanelHeader(this.panelElement, this.driver);
237
+ this.header = new SubsystemsPanelHeader("#aside", byTestIdCssSelector("subsystems-panel-title", "span"), this.driver);
158
238
  }
159
- panelElement = () => {
160
- return this.driver.findElement(this.panelBy);
161
- };
162
- headerTitle() {
163
- return this.header.title().then((el) => el.getText());
239
+ async headerTitle() {
240
+ const title = await this.header.title();
241
+ await wait(async () => await title.getText() != "", this.driver);
242
+ return title.getText();
164
243
  }
165
244
  };
166
245
 
167
246
  // src/pageObjects/elements/Forms/AbstractForm.ts
168
- import { By as By4 } from "selenium-webdriver";
247
+ import { By as By5 } from "selenium-webdriver";
169
248
  var AbstractForm = class extends AbstractPage {
249
+ containerCssSelector = "";
170
250
  containerBy;
171
- popupContainerBy;
251
+ popupContainerCssSelector;
172
252
  constructor(driver) {
173
253
  super(driver);
174
- this.containerBy = byTestId(`form-content-wrapper-${this.formName}`);
254
+ const testId = `form-content-wrapper-${this.formName}`;
255
+ this.containerBy = byTestId(testId);
256
+ this.containerCssSelector = byTestIdCssSelector(testId);
175
257
  }
176
258
  async isModal() {
177
259
  const el = await this.getContainerElement();
@@ -194,10 +276,10 @@ var AbstractForm = class extends AbstractPage {
194
276
  */
195
277
  async exists() {
196
278
  try {
197
- await this.driver.wait(elementIsNotPresent(this.containerBy), 1e3);
279
+ let elements = await this.driver.findElements(this.containerBy);
280
+ return elements.length > 0;
281
+ } catch (error) {
198
282
  return false;
199
- } catch {
200
- return true;
201
283
  }
202
284
  }
203
285
  /**
@@ -209,29 +291,42 @@ var AbstractForm = class extends AbstractPage {
209
291
  */
210
292
  async getTitleText() {
211
293
  if (await this.isModal()) {
212
- const popupEl = await this.driver.findElement(this.popupContainerBy);
213
- const titleEl2 = await popupEl.findElement(By4.className("popup-title"));
294
+ const titleEl2 = await this.driver.findElement(By5.css(`${this.popupContainerCssSelector} .popup-title`));
214
295
  return titleEl2.getText();
215
296
  }
216
- let container = await this.getContainerElement();
217
- let titleEl = await container.findElement(By4.className("form-toolbar-name-container"));
297
+ let titleEl = await this.driver.findElement(By5.className("main-toolbar-form-title"));
218
298
  return titleEl.getText();
219
299
  }
220
300
  };
221
301
 
222
302
  // src/pageObjects/elements/Forms/FormEdit.ts
223
- import { By as By11 } from "selenium-webdriver";
303
+ import { By as By12 } from "selenium-webdriver";
224
304
 
225
- // src/pageObjects/elements/Editors/AbstractEditor.ts
226
- import { By as By5, Key } from "selenium-webdriver";
305
+ // src/utils/createDataTestId.ts
306
+ function createDataTestId(formName, itemType, itemName) {
307
+ return `${formName}-${itemType}-${itemName}`;
308
+ }
309
+ function createFieldTestId(formName, itemName) {
310
+ return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
311
+ }
312
+ function createGroupTestId(formName, itemName) {
313
+ return createDataTestId(formName, "group" /* GROUP */, itemName);
314
+ }
315
+ function createFilterTestId(formName, itemName, layout) {
316
+ return createDataTestId(formName, "filter" /* FILTER */, itemName) + `-${layout}`;
317
+ }
318
+ function createDocFilterTestId(formName, itemName) {
319
+ return createFilterTestId(formName, itemName, "dock-panel-filter" /* DOCK_PANEL */);
320
+ }
321
+ function createLayoutFilterTestId(formName, itemName) {
322
+ return createFilterTestId(formName, itemName, "layout-filter" /* LAYOUT */);
323
+ }
324
+ function createTableId(formName) {
325
+ return `${"table" /* TABLE */}-${formName}`;
326
+ }
227
327
 
228
- // src/pageObjects/AbstractFormElement.ts
229
- var AbstractFormElement = class extends AbstractElementWithParent {
230
- constructor(getParentElement, elementBy, driver) {
231
- super(getParentElement, driver);
232
- this.elementBy = elementBy;
233
- }
234
- };
328
+ // src/pageObjects/elements/Editors/AbstractEditor.ts
329
+ import { By as By6, Key } from "selenium-webdriver";
235
330
 
236
331
  // src/pageObjects/elements/Editors/ClearStrategy/InputClearStrategy.ts
237
332
  var InputClearStrategy = class {
@@ -242,14 +337,16 @@ var InputClearStrategy = class {
242
337
  };
243
338
 
244
339
  // src/pageObjects/elements/Editors/AbstractEditor.ts
245
- var AbstractDXEditorWithInput = class extends AbstractFormElement {
340
+ var AbstractDXEditorWithInput = class extends AbstractElementWithParent {
246
341
  clearStrategy = new InputClearStrategy();
247
342
  setClearStrategy(strategy) {
248
343
  this.clearStrategy = strategy;
249
344
  }
345
+ getInputCssSelector() {
346
+ return `${this.getFullCssSelector()} .dx-texteditor-input`;
347
+ }
250
348
  async getInputElement() {
251
- const controlEl = await this.getElement();
252
- return controlEl.findElement(By5.className("dx-texteditor-input"));
349
+ return this.driver.findElement(By6.css(this.getInputCssSelector()));
253
350
  }
254
351
  async getInputValue() {
255
352
  const inputEl = await this.getInputElement();
@@ -267,8 +364,8 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
267
364
 
268
365
  // src/pageObjects/elements/Editors/TextEditor.ts
269
366
  var TextEditor = class extends AbstractDXEditorWithInput {
270
- constructor(getParentElement, elementBy, driver) {
271
- super(getParentElement, elementBy, driver);
367
+ constructor(parentCssSelector, elementCssSelector, driver) {
368
+ super(parentCssSelector, elementCssSelector, driver);
272
369
  this.setClearStrategy(new InputClearStrategy());
273
370
  }
274
371
  getValue() {
@@ -281,8 +378,8 @@ var TextEditor = class extends AbstractDXEditorWithInput {
281
378
 
282
379
  // src/pageObjects/elements/Editors/NumberEditor.ts
283
380
  var NumberEditor = class extends AbstractDXEditorWithInput {
284
- constructor(getParentElement, elementBy, driver) {
285
- super(getParentElement, elementBy, driver);
381
+ constructor(parentCssSelector, elementCssSelector, driver) {
382
+ super(parentCssSelector, elementCssSelector, driver);
286
383
  this.setClearStrategy(new InputClearStrategy());
287
384
  }
288
385
  async getValue() {
@@ -294,11 +391,17 @@ var NumberEditor = class extends AbstractDXEditorWithInput {
294
391
  }
295
392
  };
296
393
 
394
+ // src/pageObjects/AbstractFormElement.ts
395
+ var AbstractFormElement = class extends AbstractElementWithParent {
396
+ constructor(parentCssSelector, elementCssSelector, driver) {
397
+ super(parentCssSelector, elementCssSelector, driver);
398
+ }
399
+ };
400
+
297
401
  // src/pageObjects/elements/Editors/CheckBox.ts
298
- var CheckBox = class extends AbstractFormElement {
402
+ var CheckBox = class extends AbstractElementWithParent {
299
403
  async getValue() {
300
- const inputEl = await this.getElement();
301
- const result = await inputEl.getAttribute("aria-checked");
404
+ const result = await this.getAttribute("aria-checked");
302
405
  if (result === "true")
303
406
  return 1;
304
407
  if (result === "false")
@@ -315,7 +418,7 @@ var CheckBox = class extends AbstractFormElement {
315
418
  };
316
419
 
317
420
  // src/pageObjects/elements/Editors/SelectBoxEditor.ts
318
- import { By as By7, Key as Key2 } from "selenium-webdriver";
421
+ import { By as By8, Key as Key2 } from "selenium-webdriver";
319
422
 
320
423
  // src/utils/xpathHelper.ts
321
424
  var XPathHelper = class {
@@ -328,28 +431,28 @@ var XPathHelper = class {
328
431
  };
329
432
 
330
433
  // src/pageObjects/elements/Editors/ClearStrategy/ClearButtonStrategy.ts
331
- import { By as By6 } from "selenium-webdriver";
434
+ import { By as By7 } from "selenium-webdriver";
332
435
  var DX_TEXTEDITOR_EMPTY = "dx-texteditor-empty";
333
436
  var DX_CLEAR_BUTTON_AREA = "dx-clear-button-area";
334
437
  var ClearButtonStrategy = class {
335
438
  editorContainerClass;
336
- constructor(editorContainerClass) {
439
+ _driver;
440
+ constructor(editorContainerClass, driver) {
337
441
  this.editorContainerClass = editorContainerClass;
442
+ this._driver = driver;
338
443
  }
339
- async isEmptyEditorField(editor) {
340
- const parentEl = await editor.getParentElement();
341
- const editorContainer = await parentEl.findElement(By6.className(this.editorContainerClass));
444
+ async isEmptyEditorField() {
445
+ const editorContainer = await this._driver.findElement(By7.css(this.editorContainerClass));
342
446
  const classAttribute = await editorContainer.getAttribute("class");
343
447
  return classAttribute.includes(DX_TEXTEDITOR_EMPTY);
344
448
  }
345
- async clear(editor) {
346
- if (await this.isEmptyEditorField(editor)) {
449
+ async clear() {
450
+ if (await this.isEmptyEditorField()) {
347
451
  throw new Error("This field is already empty");
348
452
  }
349
- const clearBtnSelector = `.${this.editorContainerClass} .${DX_CLEAR_BUTTON_AREA}`;
350
- const parentEl = await editor.getParentElement();
351
- const clearBtn = await parentEl.findElement(By6.css(clearBtnSelector));
352
- await click(clearBtn, editor.driver);
453
+ const clearBtnSelector = `${this.editorContainerClass} .${DX_CLEAR_BUTTON_AREA}`;
454
+ const clearBtn = await this._driver.findElement(By7.css(clearBtnSelector));
455
+ await click(clearBtn, this._driver);
353
456
  }
354
457
  };
355
458
 
@@ -360,25 +463,17 @@ var combinedValueXpath = (value) => `${XPathHelper.getRoleXpath(SELECT_BOX_ELEME
360
463
  SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS,
361
464
  value
362
465
  )}`;
363
- var DX_SELECTBOX = "dx-selectbox";
364
466
  var SelectBoxEditor = class extends AbstractDXEditorWithInput {
365
- constructor(getParentElement, elementBy, driver) {
366
- super(getParentElement, elementBy, driver);
367
- this.setClearStrategy(new ClearButtonStrategy(DX_SELECTBOX));
467
+ constructor(parentCssSelector, elementCssSelector, driver) {
468
+ super(parentCssSelector, elementCssSelector, driver);
469
+ this.setClearStrategy(new ClearButtonStrategy(this.getFullCssSelector(), this.driver));
368
470
  }
369
471
  async setSelectInputValue(value) {
370
472
  const inputEl = await this.getInputElement();
371
473
  await click(inputEl, this.driver);
372
474
  await inputEl.sendKeys(value, Key2.ENTER);
373
- await this.driver.wait(async () => {
374
- try {
375
- const optElement = await inputEl.findElement(By7.xpath(combinedValueXpath(value)));
376
- await click(optElement, this.driver);
377
- return true;
378
- } catch (e) {
379
- return false;
380
- }
381
- }, 2e3);
475
+ const optElement = await inputEl.findElement(By8.xpath(combinedValueXpath(value)));
476
+ await click(optElement, this.driver);
382
477
  }
383
478
  async getValue() {
384
479
  const value = await super.getInputValue();
@@ -390,10 +485,9 @@ var SelectBoxEditor = class extends AbstractDXEditorWithInput {
390
485
  };
391
486
 
392
487
  // src/pageObjects/elements/Editors/SwitchEditor.ts
393
- var SwitchEditor = class extends AbstractFormElement {
488
+ var SwitchEditor = class extends AbstractElementWithParent {
394
489
  async getValue() {
395
- const inputEl = await this.getElement();
396
- const result = await inputEl.getAttribute("aria-label");
490
+ const result = await this.getAttribute("aria-label");
397
491
  if (result === "ON")
398
492
  return 1;
399
493
  if (result === "OFF")
@@ -406,27 +500,28 @@ var SwitchEditor = class extends AbstractFormElement {
406
500
  }
407
501
  const inputEl = await this.getElement();
408
502
  const currentValue = await this.getValue();
409
- if (currentValue !== value) {
410
- await click(inputEl, this.driver);
411
- await this.driver.wait(async () => {
412
- const updatedValue = await this.getValue();
413
- return updatedValue !== currentValue;
414
- });
503
+ if (currentValue === value) {
504
+ return;
415
505
  }
506
+ await click(inputEl, this.driver);
507
+ await wait(async () => {
508
+ const updatedValue = await this.getValue();
509
+ return updatedValue !== currentValue;
510
+ }, this.driver);
416
511
  }
417
512
  };
418
513
 
419
514
  // src/pageObjects/elements/Editors/TagBox.ts
420
- import { By as By8 } from "selenium-webdriver";
515
+ import { By as By9 } from "selenium-webdriver";
421
516
  var TAGS_SELECTOR = ".dx-tag .tag-text";
422
517
  var DX_TAG_CONTAINER = "dx-tag-container";
423
- var DX_TAGBOX = "dx-tagbox";
424
518
  var DX_TEXTEDITOR_EMPTY2 = "dx-texteditor-empty";
425
519
  var BTN_OK_SELECTOR = ".dx-tagbox-popup-wrapper .dx-popup-bottom .dx-button.dx-popup-done";
520
+ var TAG_BOX_LIST_ITEM_SELECTOR = '.dx-tagbox-popup-wrapper .dx-list-item[aria-selected="true"]';
426
521
  var TagBox = class extends AbstractDXEditorWithInput {
427
- constructor(getParentElement, elementBy, driver) {
428
- super(getParentElement, elementBy, driver);
429
- this.setClearStrategy(new ClearButtonStrategy(DX_TAGBOX));
522
+ constructor(parentCssSelector, elementCssSelector, driver) {
523
+ super(parentCssSelector, elementCssSelector, driver);
524
+ this.setClearStrategy(new ClearButtonStrategy(this.getFullCssSelector(), this.driver));
430
525
  }
431
526
  async setTagBoxInputValue(values) {
432
527
  const lastElement = values[values.length - 1];
@@ -437,37 +532,28 @@ var TagBox = class extends AbstractDXEditorWithInput {
437
532
  }
438
533
  await this.confirmSelection();
439
534
  }
535
+ async waitOptionSelection() {
536
+ const option = await this.driver.findElement(By9.css(TAG_BOX_LIST_ITEM_SELECTOR));
537
+ await wait(() => option.isDisplayed(), this.driver);
538
+ }
440
539
  async selectOption(inputEl, value, lastElement) {
441
540
  await inputEl.sendKeys(value);
442
- await this.driver.wait(async () => {
443
- try {
444
- const optElement = await inputEl.findElement(By8.xpath(combinedValueXpath(value)));
445
- await click(optElement, this.driver);
446
- return true;
447
- } catch (e) {
448
- return false;
449
- }
450
- });
541
+ const optElement = await inputEl.findElement(By9.xpath(combinedValueXpath(value)));
542
+ await click(optElement, this.driver);
543
+ await this.waitOptionSelection();
451
544
  if (value !== lastElement) {
452
545
  await inputEl.clear();
453
546
  }
454
547
  }
455
548
  async confirmSelection() {
456
- const inputEl = await this.getInputElement();
457
- const option = await inputEl.findElement(By8.xpath(XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)));
458
- const btnOk = await this.driver.findElement(By8.css(BTN_OK_SELECTOR));
459
- await this.driver.wait(async () => {
460
- return await option.getAttribute("aria-selected") === "true";
461
- });
549
+ const btnOk = await this.driver.findElement(By9.css(BTN_OK_SELECTOR));
462
550
  await click(btnOk, this.driver);
463
551
  }
464
552
  async getTagBoxInputValue() {
465
553
  if (await this.isTagBoxEmpty()) {
466
554
  return [];
467
555
  }
468
- const parentEl = await this.getParentElement();
469
- const inputEl = await parentEl.findElement(By8.className(DX_TAG_CONTAINER));
470
- const tags = await inputEl.findElements(By8.css(TAGS_SELECTOR));
556
+ const tags = await this.driver.findElements(By9.css(`${this.getFullCssSelector()} .${DX_TAG_CONTAINER} ${TAGS_SELECTOR}`));
471
557
  const values = [];
472
558
  for (const tag of tags) {
473
559
  const text = await tag.getText();
@@ -476,9 +562,7 @@ var TagBox = class extends AbstractDXEditorWithInput {
476
562
  return values;
477
563
  }
478
564
  async isTagBoxEmpty() {
479
- const parentEl = await this.getParentElement();
480
- const tagboxContainer = await parentEl.findElement(By8.className(DX_TAGBOX));
481
- const classAttribute = await tagboxContainer.getAttribute("class");
565
+ const classAttribute = await this.getClasses();
482
566
  return classAttribute.includes(DX_TEXTEDITOR_EMPTY2);
483
567
  }
484
568
  async getValue() {
@@ -497,28 +581,25 @@ var TagBox = class extends AbstractDXEditorWithInput {
497
581
  if (!tagExists) {
498
582
  throw new Error(`The tag with the text: ${itemText} was not found`);
499
583
  }
500
- const parentEl = await this.getParentElement();
501
- const inputEl = await parentEl.findElement(By8.className(DX_TAG_CONTAINER));
502
- const clearBtnTestId = byTestId(`clear-button-${itemText}`);
503
- const clearBtn = await inputEl.findElement(clearBtnTestId);
584
+ const clearBtnTestId = byTestIdCssSelector(`clear-button-${itemText}`);
585
+ const clearBtn = await this.driver.findElement(By9.css(`${this.getFullCssSelector()} .${DX_TAG_CONTAINER} ${clearBtnTestId}`));
504
586
  await click(clearBtn, this.driver);
505
587
  }
506
588
  };
507
589
 
508
590
  // src/pageObjects/elements/Editors/ButtonGroup.ts
509
- import { By as By9 } from "selenium-webdriver";
591
+ import { By as By10 } from "selenium-webdriver";
510
592
  var ITEM_CLASS = "dx-buttongroup-item";
511
593
  var SELECTED_CLASS = "dx-state-selected";
512
- var ButtonGroup = class extends AbstractFormElement {
513
- async getItems() {
514
- return (await this.getElement()).findElements(By9.className(ITEM_CLASS));
594
+ var ButtonGroup = class extends AbstractElementWithParent {
595
+ getItems() {
596
+ return this.driver.findElements(By10.css(`${this.getFullCssSelector()} .${ITEM_CLASS}`));
515
597
  }
516
598
  getDataValue(el) {
517
599
  return el.getAttribute("data-value");
518
600
  }
519
601
  async getValue() {
520
- const inputEl = await this.getElement();
521
- const selectedEl = await inputEl.findElement(By9.className(`${ITEM_CLASS} ${SELECTED_CLASS}`));
602
+ const selectedEl = await this.driver.findElement(By10.css(`${this.getFullCssSelector()} .${ITEM_CLASS}.${SELECTED_CLASS}`));
522
603
  return this.getDataValue(selectedEl);
523
604
  }
524
605
  async setValue(value) {
@@ -552,19 +633,14 @@ var BooleanSelector = class extends ButtonGroup {
552
633
  };
553
634
 
554
635
  // src/pageObjects/elements/Editors/DateEditor.ts
555
- import { By as By10, Key as Key3 } from "selenium-webdriver";
636
+ import { By as By11, Key as Key3 } from "selenium-webdriver";
556
637
  var DateEditor = class extends AbstractDXEditorWithInput {
557
- constructor(getParentElement, elementBy, driver) {
558
- super(getParentElement, elementBy, driver);
638
+ constructor(parentCssSelector, elementCssSelector, driver) {
639
+ super(parentCssSelector, elementCssSelector, driver);
559
640
  this.setClearStrategy(new InputClearStrategy());
560
641
  }
561
- async getControlElement() {
562
- const controlEl = await this.getElement();
563
- return controlEl.findElement(By10.className("dx-dropdowneditor-input-wrapper"));
564
- }
565
642
  async getDateElement() {
566
- const controlEl = await this.getControlElement();
567
- return controlEl.findElement(By10.css("input[type=hidden]"));
643
+ return this.driver.findElement(By11.css(this.getFullCssSelector() + " .dx-dropdowneditor-input-wrapper input[type=hidden]"));
568
644
  }
569
645
  async setDateValue(value) {
570
646
  const dateEl = await this.getInputElement();
@@ -594,54 +670,39 @@ var DateEditor = class extends AbstractDXEditorWithInput {
594
670
  };
595
671
 
596
672
  // src/pageObjects/elements/Editors/editorFactory.ts
597
- var editorFactory = async (getParentElement, elementBy, driver) => {
598
- const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
673
+ var editorFactory = async (parentCssSelector, elementCssSelector, driver) => {
674
+ const elementInstance = new AbstractFormElement(parentCssSelector, elementCssSelector, driver);
599
675
  const classSting = await elementInstance.getClasses();
600
676
  if (classSting.includes("text-control"))
601
- return new TextEditor(getParentElement, elementBy, driver);
677
+ return new TextEditor(parentCssSelector, elementCssSelector, driver);
602
678
  if (classSting.includes("number-control"))
603
- return new NumberEditor(getParentElement, elementBy, driver);
679
+ return new NumberEditor(parentCssSelector, elementCssSelector, driver);
604
680
  if (classSting.includes("check-box"))
605
- return new CheckBox(getParentElement, elementBy, driver);
681
+ return new CheckBox(parentCssSelector, elementCssSelector, driver);
606
682
  if (classSting.includes("multi-select-control"))
607
- return new TagBox(getParentElement, elementBy, driver);
683
+ return new TagBox(parentCssSelector, elementCssSelector, driver);
608
684
  if (classSting.includes("select-control"))
609
- return new SelectBoxEditor(getParentElement, elementBy, driver);
685
+ return new SelectBoxEditor(parentCssSelector, elementCssSelector, driver);
610
686
  if (classSting.includes("switch-control"))
611
- return new SwitchEditor(getParentElement, elementBy, driver);
687
+ return new SwitchEditor(parentCssSelector, elementCssSelector, driver);
612
688
  if (classSting.includes("date-control"))
613
- return new DateEditor(getParentElement, elementBy, driver);
689
+ return new DateEditor(parentCssSelector, elementCssSelector, driver);
614
690
  if (classSting.includes("buttons-group"))
615
- return new BooleanSelector(getParentElement, elementBy, driver);
691
+ return new BooleanSelector(parentCssSelector, elementCssSelector, driver);
616
692
  if (classSting.includes("button-group-field"))
617
- return new ButtonGroup(getParentElement, elementBy, driver);
693
+ return new ButtonGroup(parentCssSelector, elementCssSelector, driver);
618
694
  throw new Error("Unknown type of editor. Please write ticket to the support");
619
695
  };
620
696
 
621
- // src/utils/createDataTestId.ts
622
- function createDataTestId(formName, itemType, itemName) {
623
- return `${formName}-${itemType}-${itemName}`;
624
- }
625
- function createFieldTestId(formName, itemName) {
626
- return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
627
- }
628
- function createGroupTestId(formName, itemName) {
629
- return createDataTestId(formName, "group" /* GROUP */, itemName);
630
- }
631
- function createTableId(formName) {
632
- return `${"table" /* TABLE */}-${formName}`;
633
- }
634
-
635
- // src/pageObjects/elements/FormField.ts
636
- var FormField = class extends AbstractElementWithParent {
697
+ // src/pageObjects/elements/AbstractEditor.ts
698
+ var AbstractEditor = class extends AbstractElementWithParent {
637
699
  editor;
638
- constructor(getParentElement, formName, name, driver) {
639
- super(getParentElement, driver);
640
- this.elementBy = byTestId(createFieldTestId(formName, name));
700
+ constructor(parentCssSelector, elementCssSelector, driver) {
701
+ super(parentCssSelector, elementCssSelector, driver);
641
702
  }
642
703
  async initEditor() {
643
704
  if (!this.editor) {
644
- this.editor = await editorFactory(this.getParentElement, this.elementBy, this.driver);
705
+ this.editor = await editorFactory(this.parentCssSelector, this.elementCssSelector, this.driver);
645
706
  }
646
707
  }
647
708
  /**
@@ -690,37 +751,43 @@ var FormField = class extends AbstractElementWithParent {
690
751
  }
691
752
  };
692
753
 
693
- // src/pageObjects/elements/Groups/AbstractGroup.ts
694
- var AbstractDXGroup = class extends AbstractFormElement {
754
+ // src/pageObjects/elements/FormField.ts
755
+ var FormField = class extends AbstractEditor {
756
+ constructor(parentCssSelector, formName, name, driver) {
757
+ super(parentCssSelector, byTestIdCssSelector(createFieldTestId(formName, name)), driver);
758
+ }
695
759
  };
696
760
 
697
- // src/pageObjects/elements/Groups/Panel.ts
698
- var Panel = class extends AbstractDXGroup {
761
+ // src/pageObjects/elements/Groups/AbstractGroup.ts
762
+ var AbstractGroup = class extends AbstractElementWithParent {
699
763
  async isDisplayed() {
700
764
  const groupElement = await this.getElement();
701
765
  return await groupElement.isDisplayed();
702
766
  }
703
767
  };
704
768
 
769
+ // src/pageObjects/elements/Groups/Panel.ts
770
+ var Panel = class extends AbstractGroup {
771
+ };
772
+
705
773
  // src/pageObjects/elements/Groups/groupFactory.ts
706
- var groupFactory = async (getParentElement, elementBy, driver) => {
707
- const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
774
+ var groupFactory = async (parentCssSelector, elementCssSelector, driver) => {
775
+ const elementInstance = new AbstractFormElement(parentCssSelector, elementCssSelector, driver);
708
776
  const classSting = await elementInstance.getClasses();
709
777
  if (classSting.includes("panel-group"))
710
- return new Panel(getParentElement, elementBy, driver);
778
+ return new Panel(parentCssSelector, elementCssSelector, driver);
711
779
  throw new Error("Unknown type of group. Please write ticket to the support");
712
780
  };
713
781
 
714
782
  // src/pageObjects/elements/FormGroup.ts
715
783
  var FormGroup = class extends AbstractElementWithParent {
716
784
  editor;
717
- constructor(getParentElement, formName, name, driver) {
718
- super(getParentElement, driver);
719
- this.elementBy = byTestId(createGroupTestId(formName, name));
785
+ constructor(parentCssSelector, formName, name, driver) {
786
+ super(parentCssSelector, byTestIdCssSelector(createGroupTestId(formName, name)), driver);
720
787
  }
721
788
  async initEditor() {
722
789
  if (!this.editor) {
723
- this.editor = await groupFactory(this.getParentElement, this.elementBy, this.driver);
790
+ this.editor = await groupFactory(this.parentCssSelector, this.elementCssSelector, this.driver);
724
791
  }
725
792
  }
726
793
  /**
@@ -729,17 +796,21 @@ var FormGroup = class extends AbstractElementWithParent {
729
796
  * expect(await tableList.group('MainSuperPanel').isDisplayed();
730
797
  */
731
798
  async isDisplayed() {
732
- await this.initEditor();
733
- return this.editor.isDisplayed();
799
+ try {
800
+ await this.initEditor();
801
+ return this.editor.isDisplayed();
802
+ } catch {
803
+ return false;
804
+ }
734
805
  }
735
806
  };
736
807
 
737
808
  // src/pageObjects/elements/Forms/FormEdit.ts
738
809
  var FormEdit = class extends AbstractForm {
739
- saveButtonBy = By11.id("button-save");
810
+ saveButtonBy = By12.id("button-save");
740
811
  constructor(driver) {
741
812
  super(driver);
742
- this.popupContainerBy = By11.className(`popup form-edit-${this.formName}`);
813
+ this.popupContainerCssSelector = `.popup .form-edit-${this.formName}`;
743
814
  }
744
815
  /**
745
816
  * Находит поле формы редактирования по имени
@@ -749,7 +820,7 @@ var FormEdit = class extends AbstractForm {
749
820
  * expect(await formEdit.field('Name').getValue()).toBe('test value');
750
821
  */
751
822
  field(name) {
752
- return new FormField(this.getContainerElement, this.formName, name, this.driver);
823
+ return new FormField(this.containerCssSelector, this.formName, name, this.driver);
753
824
  }
754
825
  /**
755
826
  * Проверяет не отключена ли кнопка Сохранить
@@ -771,7 +842,7 @@ var FormEdit = class extends AbstractForm {
771
842
  * expect(await formEdit.group('Name');
772
843
  */
773
844
  group(name) {
774
- return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
845
+ return new FormGroup(this.containerCssSelector, this.formName, name, this.driver);
775
846
  }
776
847
  /**
777
848
  * Нажатие на кнопку Сохранить
@@ -782,50 +853,67 @@ var FormEdit = class extends AbstractForm {
782
853
  */
783
854
  async saveButtonClick() {
784
855
  const saveButton = await this.driver.findElement(this.saveButtonBy);
785
- await this.driver.wait(async () => !await this.isSaveButtonDisabled(), void 0, "Button is disabled");
856
+ await wait(async () => !await this.isSaveButtonDisabled(), this.driver, "Button is disabled");
786
857
  await click(saveButton, this.driver);
787
858
  }
788
859
  };
789
860
 
790
- // src/pageObjects/elements/Forms/ListForm.ts
861
+ // src/pageObjects/elements/Table/Table.ts
791
862
  import { By as By17 } from "selenium-webdriver";
792
863
 
793
- // src/pageObjects/elements/Table/Table.ts
864
+ // src/pageObjects/elements/Table/elements/Row.ts
865
+ import { By as By15 } from "selenium-webdriver";
866
+
867
+ // src/pageObjects/elements/Table/elements/Cell.ts
794
868
  import { By as By14 } from "selenium-webdriver";
795
869
 
796
870
  // src/pageObjects/elements/Table/utils.ts
797
- import { By as By12 } from "selenium-webdriver";
798
- var getRowPathByIndex = (index) => {
799
- return By12.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
800
- };
871
+ import { By as By13 } from "selenium-webdriver";
872
+ function getCssRowByIndexSelector(index) {
873
+ return `tr[aria-rowindex="${transformInputIndex(index)}"]`;
874
+ }
801
875
  var getColumnByIndexCssSelector = (columnIndex) => `td[aria-colindex="${transformInputIndex(columnIndex)}"]`;
802
- var getColumnPathByIndex = (index) => {
803
- return By12.css(getColumnByIndexCssSelector(index));
804
- };
805
876
  var getColumnByCaptionCssSelector = (caption) => `td[role="columnheader"][aria-label="Column ${caption}"]`;
806
- var getCellPathByIndex = (index) => {
807
- return By12.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
808
- };
877
+ var getColumnByNameCssSelector = (name) => `td[role="columnheader"][data-fieldname="${name}"]`;
878
+ function getCssCellByIndexSelector(index) {
879
+ return `td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`;
880
+ }
809
881
  var transformInputIndex = (index) => index + 1;
810
882
  var transformOutputIndex = (index) => +index - 1;
811
883
 
812
- // src/pageObjects/elements/Table/elements/Row.ts
813
- import { By as By13 } from "selenium-webdriver";
814
-
815
884
  // src/pageObjects/elements/Table/elements/Cell.ts
816
885
  var Cell = class extends AbstractElementWithParent {
817
- index;
818
- constructor(rowEl, index, driver) {
819
- super(() => Promise.resolve(rowEl), driver);
820
- this.index = index;
821
- this.elementBy = getCellPathByIndex(index);
886
+ _index;
887
+ getCellIndex;
888
+ constructor(parentCssSelector, getCellIndex, index, driver) {
889
+ super(parentCssSelector, getCssCellByIndexSelector(index), driver);
890
+ this.getCellIndex = getCellIndex;
891
+ this._index = index;
892
+ }
893
+ set index(index) {
894
+ this._index = index;
895
+ this.elementCssSelector = getCssCellByIndexSelector(index);
896
+ }
897
+ async getBooleanValue(cellEl) {
898
+ const booleanEl = await cellEl.findElement(By14.className("boolean-widget"));
899
+ return await booleanEl.getAttribute("aria-checked") === "true" ? 1 : 0;
900
+ }
901
+ async getElement() {
902
+ if (this._index == null) {
903
+ this.index = await this.getCellIndex();
904
+ }
905
+ return super.getElement();
822
906
  }
823
907
  async getValue() {
824
908
  const cellEl = await this.getElement();
909
+ const cellElClass = await cellEl.getAttribute("class");
910
+ if (cellElClass.includes("boolean-column")) {
911
+ return this.getBooleanValue(cellEl);
912
+ }
825
913
  return cellEl.getText();
826
914
  }
827
915
  getIndex() {
828
- return this.index;
916
+ return this._index;
829
917
  }
830
918
  };
831
919
 
@@ -835,51 +923,46 @@ var DX_ROW_EDIT_CLASS = "dx-edit-row";
835
923
  var DX_DATA_ROW_CLASS = "dx-data-row";
836
924
  var Row = class extends AbstractElementWithParent {
837
925
  index;
838
- getColumnByCaption;
839
- constructor(getParentElement, index, driver, getColumnByCaption) {
840
- super(getParentElement, driver);
926
+ getColumnBy;
927
+ constructor(parentCssSelector, index, driver, getColumnBy) {
928
+ super(parentCssSelector, getCssRowByIndexSelector(index), driver);
841
929
  this.index = index;
842
- this.elementBy = getRowPathByIndex(index);
843
- this.getColumnByCaption = getColumnByCaption;
930
+ this.getColumnBy = getColumnBy;
844
931
  }
845
- async getCellByIndex(index) {
846
- const rowEl = await this.getElement();
847
- const cell = rowEl.findElement(getCellPathByIndex(index));
848
- if (cell) {
849
- return new Cell(rowEl, index, this.driver);
850
- }
851
- throw new Error(`Cannot find cell by index: ${index}`);
932
+ _getCell({ index, name, title }) {
933
+ return new Cell(this.getFullCssSelector(), () => {
934
+ return this.getColumnBy({ title, name }).getIndex();
935
+ }, index, this.driver);
852
936
  }
853
- async getCell(caption) {
854
- const column = await this.getColumnByCaption(caption);
855
- if (column) {
856
- const index = column.getIndex();
857
- return this.getCellByIndex(index);
858
- }
859
- throw new Error("Unknown caption of cell");
937
+ getCellByIndex(index) {
938
+ return this._getCell({ index });
939
+ }
940
+ getCell(name) {
941
+ return this._getCell({ name });
942
+ }
943
+ getCellByTitle(title) {
944
+ return this._getCell({ title });
860
945
  }
861
946
  async select() {
862
947
  const rowEl = await this.getElement();
863
948
  await click(rowEl, this.driver);
864
- await this.driver.wait(async () => {
865
- const classes = await rowEl.getAttribute("class");
949
+ await wait(async () => {
950
+ const classes = await this.getClasses();
866
951
  return classes.includes(DX_SELECTION_CLASS);
867
- }, 500, "Cannot select row");
952
+ }, this.driver, "Cannot select row");
868
953
  }
869
954
  async isSelected() {
870
- const rowEl = await this.getElement();
871
- const result = await rowEl.getAttribute("aria-selected");
955
+ const result = await this.getAttribute("aria-selected");
872
956
  return result === "true";
873
957
  }
874
958
  getIndex() {
875
959
  return this.index;
876
960
  }
877
961
  async getCells() {
878
- const rowEl = await this.getElement();
879
- const cells = await rowEl.findElements(By13.css(`td[role="gridcell"]`));
962
+ const cells = await this.driver.findElements(By15.css(`${this.getFullCssSelector()} td[role="gridcell"]`));
880
963
  const result = [];
881
964
  cells.forEach((_, index) => {
882
- const newCell = new Cell(rowEl, index, this.driver);
965
+ const newCell = this.getCellByIndex(index);
883
966
  result.push(newCell);
884
967
  });
885
968
  return result;
@@ -887,15 +970,13 @@ var Row = class extends AbstractElementWithParent {
887
970
  async clickInlineButton(buttonClass) {
888
971
  const FIXED_TABLE_CSS_SELECTOR = ".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed";
889
972
  const buttonCssSelector = `.${DX_DATA_ROW_CLASS}[aria-rowindex="${transformInputIndex(this.index)}"] .${buttonClass}`;
890
- const button = (await this.getParentElement()).findElement(
891
- By13.css(`${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`)
892
- );
973
+ const button = await this.driver.findElement(By15.css(`${this.parentCssSelector} ${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`));
893
974
  return click(button, this.driver);
894
975
  }
895
976
  async checkEditingMode(isEditing, msg) {
896
- await this.driver.wait(async () => {
977
+ await wait(async () => {
897
978
  return (await this.getClasses()).includes(DX_ROW_EDIT_CLASS) === isEditing;
898
- }, 2e3, msg);
979
+ }, this.driver, msg);
899
980
  }
900
981
  async edit() {
901
982
  await this.clickInlineButton("edit");
@@ -912,86 +993,119 @@ var Row = class extends AbstractElementWithParent {
912
993
  };
913
994
 
914
995
  // src/pageObjects/elements/Table/elements/Column.ts
996
+ import { By as By16 } from "selenium-webdriver";
997
+ var getHeaderCssSelector = () => {
998
+ return ".dx-datagrid-headers .dx-datagrid-content:not(.dx-datagrid-content-fixed)";
999
+ };
915
1000
  var Column = class extends AbstractElementWithParent {
916
- index;
917
- constructor(getParentElement, index, driver) {
918
- super(getParentElement, driver);
1001
+ _index;
1002
+ _caption;
1003
+ _name;
1004
+ constructor({ parentCssSelector, name, caption, index, driver }) {
1005
+ super(parentCssSelector, "", driver);
1006
+ this._name = name;
919
1007
  this.index = index;
920
- this.elementBy = getColumnPathByIndex(index);
1008
+ this._caption = caption;
1009
+ }
1010
+ set index(index) {
1011
+ this._index = index;
1012
+ this.elementCssSelector = getColumnByIndexCssSelector(index);
1013
+ }
1014
+ get index() {
1015
+ return this._index;
1016
+ }
1017
+ async getElement() {
1018
+ await this.getIndex();
1019
+ return super.getElement();
1020
+ }
1021
+ async getColumnHeaderIndexBy(cssSelector) {
1022
+ const column = await this.driver.findElement(By16.css(`${this.parentCssSelector} ${getHeaderCssSelector()} ${cssSelector}`));
1023
+ return transformOutputIndex(await column.getAttribute("aria-colindex"));
1024
+ }
1025
+ async getIndexByCaption() {
1026
+ return this.getColumnHeaderIndexBy(getColumnByCaptionCssSelector(this._caption));
1027
+ }
1028
+ async getIndexByName() {
1029
+ return this.getColumnHeaderIndexBy(getColumnByNameCssSelector(this._name));
921
1030
  }
922
1031
  async caption() {
923
1032
  const el = await this.getElement();
924
1033
  return el.getText();
925
1034
  }
926
- getIndex() {
927
- return this.index;
1035
+ async getIndex() {
1036
+ if (this.index != null) {
1037
+ return this.index;
1038
+ }
1039
+ if (this._caption != null) {
1040
+ this.index = await this.getIndexByCaption();
1041
+ return this.index;
1042
+ }
1043
+ if (this._name != null) {
1044
+ this.index = await this.getIndexByName();
1045
+ return this.index;
1046
+ }
1047
+ throw new Error("Cant get the index in the column");
928
1048
  }
929
1049
  };
930
1050
 
931
1051
  // src/pageObjects/elements/Table/Table.ts
932
1052
  var Table = class extends AbstractElementWithParent {
933
1053
  formName;
934
- constructor(getParentElement, formName, driver) {
935
- super(getParentElement, driver);
936
- this.elementBy = By14.id(createTableId(formName));
1054
+ constructor(parentCssSelector, formName, driver) {
1055
+ super(parentCssSelector, `#${createTableId(formName)}`, driver);
937
1056
  this.formName = formName;
938
1057
  }
939
- getHeaderCssSelector() {
940
- return ".dx-datagrid-headers .dx-datagrid-content:not(.dx-datagrid-content-fixed)";
941
- }
942
- async getDataGrid() {
943
- const parentEl = await this.getElement();
944
- return parentEl.findElement(By14.css(`div[role="grid"]`));
945
- }
946
- getTableElement = () => {
947
- return this.getElement();
948
- };
949
- async getRowByIndex(index) {
950
- const gridContainer = await this.getDataGrid();
951
- const row = await gridContainer.findElement(getRowPathByIndex(index));
952
- if (row) {
953
- return new Row(this.getTableElement, index, this.driver, this.getColumnByCaption.bind(this));
954
- }
955
- throw new Error(`Cannot find row by index: ${index}`);
956
- }
957
- async getColumnByIndex(index) {
958
- const column = await (await this.getElement()).findElement(By14.css(`${this.getHeaderCssSelector()} ${getColumnByIndexCssSelector(index)}`));
959
- if (column) {
960
- return new Column(this.getTableElement, index, this.driver);
1058
+ getColumnBy = (args) => {
1059
+ if (args.title) {
1060
+ return this.getColumnByTitle(args.title);
961
1061
  }
962
- throw new Error(`Cannot find column by index: ${index}`);
1062
+ return this.getColumnByName(args.name);
1063
+ };
1064
+ getRowByIndex(index) {
1065
+ return new Row(this.getFullCssSelector(), index, this.driver, this.getColumnBy);
1066
+ }
1067
+ getColumnByIndex(index) {
1068
+ return new Column({
1069
+ parentCssSelector: this.getFullCssSelector(),
1070
+ driver: this.driver,
1071
+ index
1072
+ });
963
1073
  }
964
- async getColumnByCaption(caption) {
965
- const column = await (await this.getElement()).findElement(By14.css(`${this.getHeaderCssSelector()} ${getColumnByCaptionCssSelector(caption)}`));
966
- if (column) {
967
- const index = await column.getAttribute("aria-colindex");
968
- return new Column(this.getTableElement, transformOutputIndex(index), this.driver);
969
- }
970
- throw new Error(`Cannot find column by caption: ${caption}`);
971
- }
972
- async selectRowByIndex(index) {
973
- const row = await this.getRowByIndex(index);
974
- if (row) {
975
- await row.select();
976
- } else {
977
- throw new Error(`Cannot find row by index: ${index}`);
978
- }
1074
+ getColumnByTitle = (title) => {
1075
+ return new Column({
1076
+ parentCssSelector: this.getFullCssSelector(),
1077
+ caption: title,
1078
+ driver: this.driver
1079
+ });
1080
+ };
1081
+ getColumnByName = (name) => {
1082
+ return new Column({
1083
+ parentCssSelector: this.getFullCssSelector(),
1084
+ name,
1085
+ driver: this.driver
1086
+ });
1087
+ };
1088
+ selectRowByIndex(index) {
1089
+ return this.getRowByIndex(index).select();
979
1090
  }
980
1091
  async getRows() {
981
- const gridContainer = await this.getDataGrid();
982
- const rows = await gridContainer.findElements(By14.className("dx-row dx-data-row"));
1092
+ const rows = await this.driver.findElements(By17.css(`${this.getFullCssSelector()} .dx-row.dx-data-row`));
983
1093
  const result = [];
984
1094
  rows.forEach((_, index) => {
985
- const newRow = new Row(this.getTableElement, index, this.driver, this.getColumnByCaption.bind(this));
1095
+ const newRow = new Row(this.getFullCssSelector(), index, this.driver, this.getColumnBy);
986
1096
  result.push(newRow);
987
1097
  });
988
1098
  return result;
989
1099
  }
990
1100
  async getColumns() {
991
- const columns = await (await this.getElement()).findElements(By14.css(`${this.getHeaderCssSelector()} td[role="columnheader"]`));
1101
+ const columns = await this.driver.findElements(By17.css(`${this.getFullCssSelector()} ${getHeaderCssSelector()} td[role="columnheader"]`));
992
1102
  const result = [];
993
1103
  columns.forEach((_, index) => {
994
- const newCol = new Column(this.getTableElement, index, this.driver);
1104
+ const newCol = new Column({
1105
+ parentCssSelector: this.getFullCssSelector(),
1106
+ index,
1107
+ driver: this.driver
1108
+ });
995
1109
  result.push(newCol);
996
1110
  });
997
1111
  return result;
@@ -1007,54 +1121,229 @@ var Table = class extends AbstractElementWithParent {
1007
1121
  * expect(await form.field('Name').getValue()).toBe('test value');
1008
1122
  */
1009
1123
  field(name) {
1010
- return new FormField(this.getTableElement, this.formName, name, this.driver);
1124
+ return new FormField(this.getFullCssSelector(), this.formName, name, this.driver);
1011
1125
  }
1012
1126
  };
1013
1127
 
1014
- // src/pageObjects/elements/TableToolbar/TableToolbar.ts
1015
- import { By as By16 } from "selenium-webdriver";
1128
+ // src/pageObjects/elements/TableToolbar/AbstractButton.ts
1129
+ var AbstractButton = class extends AbstractElementWithParent {
1130
+ constructor(parentCssSelector, elementCssSelector, driver) {
1131
+ super(parentCssSelector, elementCssSelector, driver);
1132
+ }
1133
+ async click() {
1134
+ const button = await this.getElement();
1135
+ await wait(async () => {
1136
+ return await button.isDisplayed() && !await this.isDisabled();
1137
+ }, this.driver, this.buttonNotDisplayedError());
1138
+ await click(button, this.driver);
1139
+ }
1140
+ async isDisabled() {
1141
+ const button = await this.getElement();
1142
+ return await button.getCssValue("pointer-events") === "none";
1143
+ }
1144
+ };
1016
1145
 
1017
- // src/pageObjects/elements/TableToolbar/TableToolbarButton.ts
1018
- import { By as By15 } from "selenium-webdriver";
1146
+ // src/pageObjects/elements/TableToolbar/ToolbarGroupButton.ts
1147
+ var ToolbarGroupButton = class extends AbstractButton {
1148
+ name;
1149
+ constructor(parentCssSelector, name, driver) {
1150
+ super(parentCssSelector, ``, driver);
1151
+ this.name = name;
1152
+ }
1153
+ buttonNotDisplayedError() {
1154
+ return `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`;
1155
+ }
1156
+ };
1157
+
1158
+ // src/pageObjects/elements/TableToolbar/ToolbarButton.ts
1019
1159
  var TOOLBAR_BUTTON_CLASS = "toolbar-button";
1020
- var TableToolbarButton = class extends AbstractElementWithParent {
1160
+ var ToolbarButton = class extends AbstractButton {
1021
1161
  name;
1022
- constructor(getParentElement, name, driver) {
1023
- super(getParentElement, driver);
1162
+ constructor(parentCssSelector, name, driver) {
1163
+ super(parentCssSelector, `#${TOOLBAR_BUTTON_CLASS}-${name}`, driver);
1024
1164
  this.name = name;
1025
- this.elementBy = By15.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
1165
+ }
1166
+ buttonNotDisplayedError() {
1167
+ return `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`;
1168
+ }
1169
+ };
1170
+
1171
+ // src/pageObjects/elements/TableToolbar/ToolbarItem.ts
1172
+ var GROUP_BUTTON_CLASS = "toolbar-group-button";
1173
+ var toolbarItemSelector = (form, name) => byTestIdCssSelector(`ftb-${form}-${name}`);
1174
+ var ToolbarItem = class extends AbstractElementWithParent {
1175
+ _button;
1176
+ // private _formName: string;
1177
+ _itemName;
1178
+ constructor(parentCssSelector, formName, itemName, driver) {
1179
+ super(parentCssSelector, toolbarItemSelector(formName, itemName), driver);
1180
+ this._itemName = itemName;
1181
+ }
1182
+ async init() {
1183
+ if (this._button)
1184
+ return this._button;
1185
+ const classNames = await this.getClasses();
1186
+ if (classNames.includes(GROUP_BUTTON_CLASS)) {
1187
+ this._button = new ToolbarGroupButton(this.getFullCssSelector(), this._itemName, this.driver);
1188
+ return;
1189
+ }
1190
+ this._button = new ToolbarButton(this.parentCssSelector, this._itemName, this.driver);
1026
1191
  }
1027
1192
  async click() {
1028
- const button = await this.getElement();
1029
- await this.driver.wait(async () => {
1030
- return await button.isDisplayed() && !await this.isDisabled();
1031
- }, 1e3, `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`);
1032
- return click(button, this.driver);
1193
+ await this.init();
1194
+ await this._button.click();
1033
1195
  }
1034
1196
  async isDisabled() {
1035
- const button = await this.getElement();
1036
- const result = await button.getAttribute("aria-disabled");
1037
- return result === "true";
1197
+ await this.init();
1198
+ return await this._button.isDisabled();
1038
1199
  }
1039
1200
  };
1040
1201
 
1041
- // src/pageObjects/elements/TableToolbar/TableToolbar.ts
1202
+ // src/pageObjects/elements/TableToolbar/FormToolbar.ts
1042
1203
  var TABLE_TOOLBAR_CLASS = "d5-table-toolbar";
1043
- var TableToolbar = class extends AbstractElementWithParent {
1044
- constructor(getParentElement, formName, driver) {
1045
- super(getParentElement, driver);
1046
- this.elementBy = By16.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
1204
+ var FormToolbar = class extends AbstractElementWithParent {
1205
+ formName;
1206
+ constructor(parentCssSelector, formName, driver) {
1207
+ super(parentCssSelector, `#${TABLE_TOOLBAR_CLASS}-${formName}`, driver);
1208
+ this.formName = formName;
1047
1209
  }
1048
- getTableToolbarElement = () => {
1049
- return this.driver.findElement(this.elementBy);
1050
- };
1051
- async button(name) {
1052
- const toolbar = await this.getTableToolbarElement();
1053
- const button = await toolbar.findElement(By16.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
1054
- if (button) {
1055
- return new TableToolbarButton(this.getTableToolbarElement, name, this.driver);
1210
+ button(name) {
1211
+ return new ToolbarItem(this.getFullCssSelector(), this.formName, name, this.driver);
1212
+ }
1213
+ };
1214
+
1215
+ // src/pageObjects/elements/Filters/FormFilterField.ts
1216
+ var FormFilterField = class extends AbstractEditor {
1217
+ constructor(parentCssSelector, formName, name, driver) {
1218
+ super(parentCssSelector, byTestIdCssSelector(createLayoutFilterTestId(formName, name)), driver);
1219
+ }
1220
+ /**
1221
+ * Возвращает значение в поле
1222
+ * @example
1223
+ * expect(await form.formFilter('NumberFld').getValue()).toBe(10);
1224
+ * expect(await form.formFilter('TextFld').getValue()).toBe('TestValue');
1225
+ */
1226
+ async getValue() {
1227
+ return super.getValue();
1228
+ }
1229
+ /**
1230
+ * Устанавливает значение в поле
1231
+ * @example
1232
+ * await form.formFilter('NumberFld').setValue(123);
1233
+ * await form.formFilter('TextFld').setValue('TestValue');
1234
+ */
1235
+ async setValue(value) {
1236
+ return super.setValue(value);
1237
+ }
1238
+ /**
1239
+ * Очищает значение в поле
1240
+ * @example
1241
+ * await form.formFilter('NumberFld').clear();
1242
+ */
1243
+ async clear() {
1244
+ return super.clear();
1245
+ }
1246
+ /**
1247
+ * Удаляет тег по переданному тексту
1248
+ * @example
1249
+ * await form.formFilter('TagBox').remove('test');
1250
+ */
1251
+ async remove(itemText) {
1252
+ return super.remove(itemText);
1253
+ }
1254
+ };
1255
+
1256
+ // src/pageObjects/elements/Filters/FilterPanel.ts
1257
+ import { By as By18 } from "selenium-webdriver";
1258
+
1259
+ // src/pageObjects/elements/Filters/PanelFilterField.ts
1260
+ var PanelFilterField = class extends AbstractEditor {
1261
+ constructor(parentCssSelector, formName, name, driver) {
1262
+ super(parentCssSelector, byTestIdCssSelector(createDocFilterTestId(formName, name)), driver);
1263
+ }
1264
+ /**
1265
+ * Возвращает значение в поле
1266
+ * @example
1267
+ * expect(await form.filterPanel.filterField('NumberFld').getValue()).toBe(10);
1268
+ * expect(await form.filterPanel.filterField('TextFld').getValue()).toBe('TestValue');
1269
+ */
1270
+ async getValue() {
1271
+ return super.getValue();
1272
+ }
1273
+ /**
1274
+ * Устанавливает значение в поле
1275
+ * @example
1276
+ * await form.filterPanel.filterField('NumberFld').setValue(123);
1277
+ * await form.filterPanel.filterField('TextFld').setValue('TestValue');
1278
+ */
1279
+ async setValue(value) {
1280
+ return super.setValue(value);
1281
+ }
1282
+ /**
1283
+ * Очищает значение в поле
1284
+ * @example
1285
+ * await form.filterPanel.filterField('NumberFld').clear();
1286
+ */
1287
+ async clear() {
1288
+ return super.clear();
1289
+ }
1290
+ /**
1291
+ * Удаляет тег по переданному тексту
1292
+ * @example
1293
+ * await form.filterPanel.filterField('TagBox').remove('test');
1294
+ */
1295
+ async remove(itemText) {
1296
+ return super.remove(itemText);
1297
+ }
1298
+ };
1299
+
1300
+ // src/pageObjects/elements/Filters/FilterPanel.ts
1301
+ var drawerSelector = (formName) => `.secondary-drawer-side-panel.form-${formName}`;
1302
+ var FILTER_PANEL_SELECTOR = ".filter-panel";
1303
+ var CLOSE_SELECTOR = ".button-close";
1304
+ var FilterPanel = class extends AbstractElement {
1305
+ _formName;
1306
+ get filterPanelSelector() {
1307
+ return `${this.elementCssSelector} ${FILTER_PANEL_SELECTOR}`;
1308
+ }
1309
+ async filterPanelButtons() {
1310
+ const selector = `${this.elementCssSelector} ${FILTER_PANEL_SELECTOR} .filter-panel__buttons-panel .dx-button-text`;
1311
+ const el = await this.getElement();
1312
+ return el.findElements(By18.css(selector));
1313
+ }
1314
+ constructor(formName, driver) {
1315
+ super(driver, drawerSelector(formName));
1316
+ this._formName = formName;
1317
+ }
1318
+ /**
1319
+ * Возвращает фильтр на панели фильтрации
1320
+ * @returns {PanelFilterField}
1321
+ * @example
1322
+ * await form.filterPanel.filterField('NumberFld');
1323
+ */
1324
+ filterField(name) {
1325
+ return new PanelFilterField(this.filterPanelSelector, this._formName, name, this.driver);
1326
+ }
1327
+ async apply() {
1328
+ const btn = await this.findButtonByTitle("\u0417\u0430\u0441\u0442\u043E\u0441\u0443\u0432\u0430\u0442\u0438");
1329
+ await click(btn, this.driver);
1330
+ }
1331
+ async findButtonByTitle(title) {
1332
+ const buttons = await this.filterPanelButtons();
1333
+ for (const btn of buttons) {
1334
+ if (await btn.getText() === title) {
1335
+ return btn;
1336
+ }
1056
1337
  }
1057
- throw new Error(`Cannot find button by name: ${name}`);
1338
+ }
1339
+ async clearAll() {
1340
+ const btn = await this.findButtonByTitle("\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438");
1341
+ await click(btn, this.driver);
1342
+ await this.driver.sleep(300);
1343
+ }
1344
+ async close() {
1345
+ const btn = await this.driver.findElement(By18.css(`${this.elementCssSelector} ${CLOSE_SELECTOR}`));
1346
+ await click(btn, this.driver);
1058
1347
  }
1059
1348
  };
1060
1349
 
@@ -1062,7 +1351,7 @@ var TableToolbar = class extends AbstractElementWithParent {
1062
1351
  var ListForm = class extends AbstractForm {
1063
1352
  constructor(driver) {
1064
1353
  super(driver);
1065
- this.popupContainerBy = By17.className(`popup form-inline-${this.formName}`);
1354
+ this.popupContainerCssSelector = `.popup .form-inline-${this.formName}`;
1066
1355
  }
1067
1356
  /**
1068
1357
  * Находит таблицу
@@ -1072,7 +1361,7 @@ var ListForm = class extends AbstractForm {
1072
1361
  * expect(listForm.table());
1073
1362
  */
1074
1363
  table() {
1075
- return new Table(this.getContainerElement, this.formName, this.driver);
1364
+ return new Table(this.containerCssSelector, this.formName, this.driver);
1076
1365
  }
1077
1366
  /**
1078
1367
  * Находит группу на лист форме по имени
@@ -1082,7 +1371,7 @@ var ListForm = class extends AbstractForm {
1082
1371
  * expect(await formEdit.group('Name');
1083
1372
  */
1084
1373
  group(name) {
1085
- return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
1374
+ return new FormGroup(this.containerCssSelector, this.formName, name, this.driver);
1086
1375
  }
1087
1376
  /**
1088
1377
  * Находит таблицу
@@ -1092,78 +1381,51 @@ var ListForm = class extends AbstractForm {
1092
1381
  * expect(listForm.toolbarButton());
1093
1382
  */
1094
1383
  toolbarButton(name) {
1095
- const toolbar = new TableToolbar(this.getContainerElement, this.formName, this.driver);
1384
+ const toolbar = new FormToolbar(this.containerCssSelector, this.formName, this.driver);
1096
1385
  return toolbar.button(name);
1097
1386
  }
1098
- };
1099
-
1100
- // src/utils/signIn.ts
1101
- async function signIn(driver) {
1102
- const webDriver = driver ?? await createDriver();
1103
- config().driver = webDriver;
1104
- const loginPage = new LoginPage(webDriver);
1105
- await loginPage.locate();
1106
- await loginPage.authorize();
1107
- return webDriver;
1108
- }
1109
-
1110
- // src/utils/actions.ts
1111
- var click = async (webElement, driver) => {
1112
- driver = driver ?? config().driver;
1113
- const actions = driver.actions({ async: true });
1114
- await actions.move({ origin: webElement }).click().perform();
1115
- };
1116
-
1117
- // src/pageObjects/pages/LoginPage.ts
1118
- var LOGIN_PATH = "/login";
1119
- var LoginPage = class extends AbstractPage {
1120
- usernameField = byTestId("loginField", "input");
1121
- passwordField = byTestId("passwordField", "input");
1122
- loginButton = byTestId("loginButton");
1123
- async locate() {
1124
- await super.locate();
1125
- const login = await this.driver.findElement(this.usernameField);
1126
- await waitElementIsVisible({
1127
- element: login,
1128
- driver: this.driver
1129
- });
1130
- }
1131
- get path() {
1132
- return LOGIN_PATH;
1133
- }
1134
- async enterUsername(username) {
1135
- await this.driver.findElement(this.usernameField).sendKeys(username);
1136
- }
1137
- async enterPassword(password) {
1138
- await this.driver.findElement(this.passwordField).sendKeys(password);
1139
- }
1140
- async clickLoginButton() {
1141
- await click(await this.driver.findElement(this.loginButton), this.driver);
1142
- }
1143
- async loginWith(username, password) {
1144
- await this.enterUsername(username);
1145
- await this.enterPassword(password);
1146
- await this.clickLoginButton();
1387
+ /**
1388
+ * Фильтр который расположен на форме
1389
+ * @example
1390
+ * const listForm = new MyForm();
1391
+ * //...
1392
+ * expect(listForm.formFilter());
1393
+ */
1394
+ formFilter(name) {
1395
+ return new FormFilterField(this.containerCssSelector, this.formName, name, this.driver);
1147
1396
  }
1148
- async authorize() {
1149
- await this.loginWith(config().auth.login, config().auth.password);
1397
+ /**
1398
+ * Модель панели фильтрации
1399
+ * @returns {FilterPanel}
1400
+ * @example
1401
+ * const listForm = new MyForm();
1402
+ * //...
1403
+ * expect(listForm.filterPanel());
1404
+ */
1405
+ get filterPanel() {
1406
+ return new FilterPanel(this.formName, this.driver);
1150
1407
  }
1151
1408
  };
1152
1409
  export {
1153
1410
  AbstractPage,
1411
+ FilterPanel,
1154
1412
  FormEdit,
1155
1413
  FormField,
1414
+ FormFilterField,
1156
1415
  ListForm,
1157
1416
  LoginPage,
1158
1417
  NumberEditor,
1418
+ PanelFilterField,
1159
1419
  SubsystemsPanel,
1160
1420
  TextEditor,
1161
1421
  byTestId,
1422
+ byTestIdCssSelector,
1162
1423
  click,
1163
1424
  config,
1164
1425
  createDriver,
1165
1426
  editorFactory,
1166
1427
  elementIsNotPresent,
1167
1428
  signIn,
1429
+ wait,
1168
1430
  waitElementIsVisible
1169
1431
  };