d5-testing-library 1.0.3 → 1.0.5

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.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -29,6 +39,7 @@ __export(src_exports, {
29
39
  SubsystemsPanel: () => SubsystemsPanel,
30
40
  TextEditor: () => TextEditor,
31
41
  byTestId: () => byTestId,
42
+ click: () => click,
32
43
  config: () => config,
33
44
  createDriver: () => createDriver,
34
45
  editorFactory: () => editorFactory,
@@ -38,6 +49,25 @@ __export(src_exports, {
38
49
  module.exports = __toCommonJS(src_exports);
39
50
 
40
51
  // src/config.ts
52
+ var process = __toESM(require("process"));
53
+ var driversMap = /* @__PURE__ */ new Map();
54
+ var createConfigProxy = (config2) => {
55
+ return new Proxy(config2, {
56
+ get(_target, prop) {
57
+ if (prop === "driver") {
58
+ return driversMap.get(process.pid);
59
+ }
60
+ return Reflect.get(...arguments);
61
+ },
62
+ set(_target, prop, value) {
63
+ if (prop === "driver") {
64
+ driversMap.set(process.pid, value);
65
+ return true;
66
+ }
67
+ return Reflect.set(...arguments);
68
+ }
69
+ });
70
+ };
41
71
  var Config = class _Config {
42
72
  static instance;
43
73
  appConfig;
@@ -49,7 +79,7 @@ var Config = class _Config {
49
79
  }
50
80
  config = (cfg) => {
51
81
  if (!cfg)
52
- return this.appConfig;
82
+ return createConfigProxy(this.appConfig);
53
83
  this.appConfig = cfg;
54
84
  };
55
85
  };
@@ -120,6 +150,9 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
120
150
  });
121
151
  };
122
152
 
153
+ // src/utils/waitElementIsVisible.ts
154
+ var import_selenium_webdriver4 = require("selenium-webdriver");
155
+
123
156
  // src/pageObjects/AbstractElementWithParent.ts
124
157
  var AbstractElementWithParent = class extends AbstractElement {
125
158
  getParentElement;
@@ -144,9 +177,9 @@ var SubsystemsPanelHeader = class extends AbstractElementWithParent {
144
177
  };
145
178
 
146
179
  // src/pageObjects/elements/SubsystemsPanel/SubsystemsPanel.ts
147
- var import_selenium_webdriver4 = require("selenium-webdriver");
180
+ var import_selenium_webdriver5 = require("selenium-webdriver");
148
181
  var SubsystemsPanel = class extends AbstractElement {
149
- panelBy = import_selenium_webdriver4.By.id("aside");
182
+ panelBy = import_selenium_webdriver5.By.id("aside");
150
183
  header;
151
184
  constructor(driver) {
152
185
  super(driver);
@@ -161,7 +194,7 @@ var SubsystemsPanel = class extends AbstractElement {
161
194
  };
162
195
 
163
196
  // src/pageObjects/elements/Forms/AbstractForm.ts
164
- var import_selenium_webdriver5 = require("selenium-webdriver");
197
+ var import_selenium_webdriver6 = require("selenium-webdriver");
165
198
  var AbstractForm = class extends AbstractPage {
166
199
  containerBy;
167
200
  popupContainerBy;
@@ -206,20 +239,20 @@ var AbstractForm = class extends AbstractPage {
206
239
  async getTitleText() {
207
240
  if (await this.isModal()) {
208
241
  const popupEl = await this.driver.findElement(this.popupContainerBy);
209
- const titleEl2 = await popupEl.findElement(import_selenium_webdriver5.By.className("popup-title"));
242
+ const titleEl2 = await popupEl.findElement(import_selenium_webdriver6.By.className("popup-title"));
210
243
  return titleEl2.getText();
211
244
  }
212
245
  let container = await this.getContainerElement();
213
- let titleEl = await container.findElement(import_selenium_webdriver5.By.className("form-toolbar-name-container"));
246
+ let titleEl = await container.findElement(import_selenium_webdriver6.By.className("form-toolbar-name-container"));
214
247
  return titleEl.getText();
215
248
  }
216
249
  };
217
250
 
218
251
  // src/pageObjects/elements/Forms/FormEdit.ts
219
- var import_selenium_webdriver8 = require("selenium-webdriver");
252
+ var import_selenium_webdriver9 = require("selenium-webdriver");
220
253
 
221
254
  // src/pageObjects/elements/Editors/AbstractEditor.ts
222
- var import_selenium_webdriver6 = require("selenium-webdriver");
255
+ var import_selenium_webdriver7 = require("selenium-webdriver");
223
256
 
224
257
  // src/pageObjects/AbstractFormElement.ts
225
258
  var AbstractFormElement = class extends AbstractElementWithParent {
@@ -233,7 +266,7 @@ var AbstractFormElement = class extends AbstractElementWithParent {
233
266
  var AbstractDXEditorWithInput = class extends AbstractFormElement {
234
267
  async getInputElement() {
235
268
  const controlEl = await this.getElement();
236
- return controlEl.findElement(import_selenium_webdriver6.By.className("dx-texteditor-input"));
269
+ return controlEl.findElement(import_selenium_webdriver7.By.className("dx-texteditor-input"));
237
270
  }
238
271
  async getInputValue() {
239
272
  const inputEl = await this.getInputElement();
@@ -241,8 +274,8 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
241
274
  }
242
275
  async setInputValue(value) {
243
276
  const inputEl = await this.getInputElement();
244
- await inputEl.click();
245
- await inputEl.sendKeys(value, import_selenium_webdriver6.Key.ENTER);
277
+ await click(inputEl, this.driver);
278
+ await inputEl.sendKeys(value, import_selenium_webdriver7.Key.ENTER);
246
279
  }
247
280
  };
248
281
 
@@ -282,13 +315,13 @@ var CheckBox = class extends AbstractFormElement {
282
315
  const inputEl = await this.getElement();
283
316
  const currentValue = await this.getValue();
284
317
  if (currentValue !== value) {
285
- await inputEl.click();
318
+ await click(inputEl, this.driver);
286
319
  }
287
320
  }
288
321
  };
289
322
 
290
323
  // src/pageObjects/elements/Editors/SelectBoxEditor.ts
291
- var import_selenium_webdriver7 = require("selenium-webdriver");
324
+ var import_selenium_webdriver8 = require("selenium-webdriver");
292
325
 
293
326
  // src/utils/xpathHelper.ts
294
327
  var XPathHelper = class {
@@ -306,13 +339,13 @@ var SELECT_BOX_ELEMENT_ROLE = "option";
306
339
  var SelectBoxEditor = class extends AbstractDXEditorWithInput {
307
340
  async setSelectInputValue(value) {
308
341
  const inputEl = await this.getInputElement();
309
- await inputEl.click();
310
- await inputEl.sendKeys(value, import_selenium_webdriver7.Key.ENTER);
342
+ await click(inputEl, this.driver);
343
+ await inputEl.sendKeys(value, import_selenium_webdriver8.Key.ENTER);
311
344
  const combinedValueXpath = XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE) + XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value);
312
345
  await this.driver.wait(async () => {
313
346
  try {
314
- const optElement = await inputEl.findElement(import_selenium_webdriver7.By.xpath(combinedValueXpath));
315
- await optElement.click();
347
+ const optElement = await inputEl.findElement(import_selenium_webdriver8.By.xpath(combinedValueXpath));
348
+ await click(optElement, this.driver);
316
349
  return true;
317
350
  } catch (e) {
318
351
  return false;
@@ -328,6 +361,33 @@ var SelectBoxEditor = class extends AbstractDXEditorWithInput {
328
361
  }
329
362
  };
330
363
 
364
+ // src/pageObjects/elements/Editors/SwitchEditor.ts
365
+ var SwitchEditor = class extends AbstractFormElement {
366
+ async getValue() {
367
+ const inputEl = await this.getElement();
368
+ const result = await inputEl.getAttribute("aria-label");
369
+ if (result === "ON")
370
+ return 1;
371
+ if (result === "OFF")
372
+ return 0;
373
+ return void 0;
374
+ }
375
+ async setValue(value) {
376
+ if (value !== 0 && value !== 1) {
377
+ value = value ? 1 : 0;
378
+ }
379
+ const inputEl = await this.getElement();
380
+ const currentValue = await this.getValue();
381
+ if (currentValue !== value) {
382
+ await click(inputEl, this.driver);
383
+ await this.driver.wait(async () => {
384
+ const updatedValue = await this.getValue();
385
+ return updatedValue !== currentValue;
386
+ });
387
+ }
388
+ }
389
+ };
390
+
331
391
  // src/pageObjects/elements/Editors/editorFactory.ts
332
392
  var editorFactory = async (getParentElement, elementBy, driver) => {
333
393
  const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
@@ -341,6 +401,8 @@ var editorFactory = async (getParentElement, elementBy, driver) => {
341
401
  return new CheckBox(getParentElement, elementBy, driver);
342
402
  if (classSting.includes("select-control"))
343
403
  return new SelectBoxEditor(getParentElement, elementBy, driver);
404
+ if (classSting.includes("switch-control"))
405
+ return new SwitchEditor(getParentElement, elementBy, driver);
344
406
  throw new Error("Unknown type of editor. Please write ticket to the support");
345
407
  };
346
408
 
@@ -391,10 +453,10 @@ var FormField = class extends AbstractElementWithParent {
391
453
 
392
454
  // src/pageObjects/elements/Forms/FormEdit.ts
393
455
  var FormEdit = class extends AbstractForm {
394
- saveButtonBy = import_selenium_webdriver8.By.id("button-save");
456
+ saveButtonBy = import_selenium_webdriver9.By.id("button-save");
395
457
  constructor(driver) {
396
458
  super(driver);
397
- this.popupContainerBy = import_selenium_webdriver8.By.className(`popup form-edit-${this.formName}`);
459
+ this.popupContainerBy = import_selenium_webdriver9.By.className(`popup form-edit-${this.formName}`);
398
460
  }
399
461
  /**
400
462
  * Находит поле формы редактирования по имени
@@ -414,41 +476,41 @@ var FormEdit = class extends AbstractForm {
414
476
  * await formEdit.saveButtonClick();
415
477
  */
416
478
  async saveButtonClick() {
417
- await this.driver.findElement(this.saveButtonBy).click();
479
+ await click(await this.driver.findElement(this.saveButtonBy), this.driver);
418
480
  }
419
481
  };
420
482
 
421
483
  // src/pageObjects/elements/Forms/ListForm.ts
422
- var import_selenium_webdriver14 = require("selenium-webdriver");
484
+ var import_selenium_webdriver15 = require("selenium-webdriver");
423
485
 
424
486
  // src/pageObjects/elements/Table/Table.ts
425
- var import_selenium_webdriver11 = require("selenium-webdriver");
487
+ var import_selenium_webdriver12 = require("selenium-webdriver");
426
488
 
427
489
  // src/pageObjects/elements/Table/utils.ts
428
- var import_selenium_webdriver9 = require("selenium-webdriver");
490
+ var import_selenium_webdriver10 = require("selenium-webdriver");
429
491
  var getRowPathByIndex = (index) => {
430
- return import_selenium_webdriver9.By.xpath(`//tr[@aria-rowindex="${transformInputIndex(index)}"]`);
492
+ return import_selenium_webdriver10.By.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
431
493
  };
432
494
  var getColumnPathByIndex = (index) => {
433
- return import_selenium_webdriver9.By.xpath(`//td[@aria-colindex="${transformInputIndex(index)}"]`);
495
+ return import_selenium_webdriver10.By.css(`td[aria-colindex="${transformInputIndex(index)}"]`);
434
496
  };
435
497
  var getColumnPathByCaption = (caption) => {
436
- return import_selenium_webdriver9.By.xpath(`//td[@role="columnheader"][@aria-label="Column ${caption}"]`);
498
+ return import_selenium_webdriver10.By.css(`td[role="columnheader"][aria-label="Column ${caption}"]`);
437
499
  };
438
500
  var getCellPathByIndex = (index) => {
439
- return import_selenium_webdriver9.By.xpath(`//td[@role="gridcell"][@aria-colindex="${transformInputIndex(index)}"]`);
501
+ return import_selenium_webdriver10.By.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
440
502
  };
441
503
  var transformInputIndex = (index) => index + 1;
442
504
  var transformOutputIndex = (index) => +index - 1;
443
505
 
444
506
  // src/pageObjects/elements/Table/elements/Row.ts
445
- var import_selenium_webdriver10 = require("selenium-webdriver");
507
+ var import_selenium_webdriver11 = require("selenium-webdriver");
446
508
 
447
509
  // src/pageObjects/elements/Table/elements/Cell.ts
448
510
  var Cell = class extends AbstractElementWithParent {
449
511
  index;
450
- constructor(getParentElement, index, driver) {
451
- super(getParentElement, driver);
512
+ constructor(rowEl, index, driver) {
513
+ super(() => Promise.resolve(rowEl), driver);
452
514
  this.index = index;
453
515
  this.elementBy = getCellPathByIndex(index);
454
516
  }
@@ -462,6 +524,8 @@ var Cell = class extends AbstractElementWithParent {
462
524
  };
463
525
 
464
526
  // src/pageObjects/elements/Table/elements/Row.ts
527
+ var DX_SELECTION_CLASS = "dx-selection";
528
+ var DX_ROW_EDIT_CLASS = "dx-edit-row";
465
529
  var Row = class extends AbstractElementWithParent {
466
530
  index;
467
531
  getColumnByCaption;
@@ -471,14 +535,11 @@ var Row = class extends AbstractElementWithParent {
471
535
  this.elementBy = getRowPathByIndex(index);
472
536
  this.getColumnByCaption = getColumnByCaption;
473
537
  }
474
- getRowElement = () => {
475
- return this.driver.findElement(this.elementBy);
476
- };
477
538
  async getCellByIndex(index) {
478
539
  const rowEl = await this.getElement();
479
540
  const cell = rowEl.findElement(getCellPathByIndex(index));
480
541
  if (cell) {
481
- return new Cell(this.getRowElement, index, this.driver);
542
+ return new Cell(rowEl, index, this.driver);
482
543
  }
483
544
  throw new Error(`Cannot find cell by index: ${index}`);
484
545
  }
@@ -492,7 +553,13 @@ var Row = class extends AbstractElementWithParent {
492
553
  }
493
554
  async select() {
494
555
  const rowEl = await this.getElement();
495
- await rowEl.click();
556
+ await click(rowEl, this.driver);
557
+ await this.driver.wait(async () => {
558
+ const classes = await rowEl.getAttribute("class");
559
+ if (!classes.includes(DX_SELECTION_CLASS))
560
+ throw new Error("Cannot select row");
561
+ return true;
562
+ }, 500);
496
563
  }
497
564
  async isSelected() {
498
565
  const rowEl = await this.getElement();
@@ -504,14 +571,35 @@ var Row = class extends AbstractElementWithParent {
504
571
  }
505
572
  async getCells() {
506
573
  const rowEl = await this.getElement();
507
- const cells = await rowEl.findElements(import_selenium_webdriver10.By.css(`td[role="gridcell"]`));
574
+ const cells = await rowEl.findElements(import_selenium_webdriver11.By.css(`td[role="gridcell"]`));
508
575
  const result = [];
509
576
  cells.forEach((_, index) => {
510
- const newCell = new Cell(this.getRowElement, index, this.driver);
577
+ const newCell = new Cell(rowEl, index, this.driver);
511
578
  result.push(newCell);
512
579
  });
513
580
  return result;
514
581
  }
582
+ async clickInlineButton(rowClass, buttonClass) {
583
+ const fixedTable = (await this.getParentElement()).findElement(
584
+ import_selenium_webdriver11.By.css(".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed")
585
+ );
586
+ const rowEl = await fixedTable.findElement(import_selenium_webdriver11.By.className(rowClass));
587
+ const button = await rowEl.findElement(import_selenium_webdriver11.By.className(buttonClass));
588
+ if (button) {
589
+ return click(button, this.driver);
590
+ }
591
+ throw new Error(`Cannot find ${buttonClass} button`);
592
+ }
593
+ async edit() {
594
+ await this.select();
595
+ return this.clickInlineButton(DX_SELECTION_CLASS, "edit");
596
+ }
597
+ async save() {
598
+ return this.clickInlineButton(DX_ROW_EDIT_CLASS, "save");
599
+ }
600
+ async cancel() {
601
+ return this.clickInlineButton(DX_ROW_EDIT_CLASS, "cancel");
602
+ }
515
603
  };
516
604
 
517
605
  // src/pageObjects/elements/Table/elements/Column.ts
@@ -533,17 +621,19 @@ var Column = class extends AbstractElementWithParent {
533
621
 
534
622
  // src/pageObjects/elements/Table/Table.ts
535
623
  var Table = class extends AbstractElementWithParent {
624
+ formName;
536
625
  constructor(getParentElement, formName, driver) {
537
626
  super(getParentElement, driver);
538
- this.elementBy = import_selenium_webdriver11.By.id(createTableId(formName));
627
+ this.elementBy = import_selenium_webdriver12.By.id(createTableId(formName));
628
+ this.formName = formName;
539
629
  }
540
630
  async getHeaderElement() {
541
631
  const parentEl = await this.getElement();
542
- return parentEl.findElement(import_selenium_webdriver11.By.className("dx-header-row"));
632
+ return parentEl.findElement(import_selenium_webdriver12.By.className("dx-header-row"));
543
633
  }
544
634
  async getDataGrid() {
545
635
  const parentEl = await this.getElement();
546
- return parentEl.findElement(import_selenium_webdriver11.By.css(`div[role="grid"]`));
636
+ return parentEl.findElement(import_selenium_webdriver12.By.css(`div[role="grid"]`));
547
637
  }
548
638
  getTableElement = () => {
549
639
  return this.driver.findElement(this.elementBy);
@@ -583,7 +673,7 @@ var Table = class extends AbstractElementWithParent {
583
673
  }
584
674
  async getRows() {
585
675
  const gridContainer = await this.getDataGrid();
586
- const rows = await gridContainer.findElements(import_selenium_webdriver11.By.className("dx-row dx-data-row"));
676
+ const rows = await gridContainer.findElements(import_selenium_webdriver12.By.className("dx-row dx-data-row"));
587
677
  const result = [];
588
678
  rows.forEach((_, index) => {
589
679
  const newRow = new Row(this.getTableElement, index, this.driver, this.getColumnByCaption.bind(this));
@@ -593,7 +683,7 @@ var Table = class extends AbstractElementWithParent {
593
683
  }
594
684
  async getColumns() {
595
685
  const headerContainer = await this.getHeaderElement();
596
- const columns = await headerContainer.findElements(import_selenium_webdriver11.By.css(`td[role="columnheader"]`));
686
+ const columns = await headerContainer.findElements(import_selenium_webdriver12.By.css(`td[role="columnheader"]`));
597
687
  const result = [];
598
688
  columns.forEach((_, index) => {
599
689
  const newCol = new Column(this.getTableElement, index, this.driver);
@@ -601,25 +691,40 @@ var Table = class extends AbstractElementWithParent {
601
691
  });
602
692
  return result;
603
693
  }
604
- async element() {
694
+ element() {
605
695
  return this.getElement();
606
696
  }
697
+ /**
698
+ * Находит поле когда форма находится в состоянии редактирования
699
+ * @example
700
+ * const form = new MyForm();
701
+ * //...
702
+ * expect(await form.field('Name').getValue()).toBe('test value');
703
+ */
704
+ field(name) {
705
+ return new FormField(this.getElement, this.formName, name, this.driver);
706
+ }
607
707
  };
608
708
 
609
709
  // src/pageObjects/elements/TableToolbar/TableToolbar.ts
610
- var import_selenium_webdriver13 = require("selenium-webdriver");
710
+ var import_selenium_webdriver14 = require("selenium-webdriver");
611
711
 
612
712
  // src/pageObjects/elements/TableToolbar/TableToolbarButton.ts
613
- var import_selenium_webdriver12 = require("selenium-webdriver");
713
+ var import_selenium_webdriver13 = require("selenium-webdriver");
614
714
  var TOOLBAR_BUTTON_CLASS = "toolbar-button";
615
715
  var TableToolbarButton = class extends AbstractElementWithParent {
616
716
  constructor(getParentElement, name, driver) {
617
717
  super(getParentElement, driver);
618
- this.elementBy = import_selenium_webdriver12.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
718
+ this.elementBy = import_selenium_webdriver13.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
619
719
  }
620
720
  async click() {
621
721
  const button = await this.getElement();
622
- return button.click();
722
+ return click(button, this.driver);
723
+ }
724
+ async isDisabled() {
725
+ const button = await this.getElement();
726
+ const result = await button.getAttribute("aria-disabled");
727
+ return result === "true";
623
728
  }
624
729
  };
625
730
 
@@ -628,14 +733,14 @@ var TABLE_TOOLBAR_CLASS = "d5-table-toolbar";
628
733
  var TableToolbar = class extends AbstractElementWithParent {
629
734
  constructor(getParentElement, formName, driver) {
630
735
  super(getParentElement, driver);
631
- this.elementBy = import_selenium_webdriver13.By.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
736
+ this.elementBy = import_selenium_webdriver14.By.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
632
737
  }
633
738
  getTableToolbarElement = () => {
634
739
  return this.driver.findElement(this.elementBy);
635
740
  };
636
741
  async button(name) {
637
742
  const toolbar = await this.getTableToolbarElement();
638
- const button = await toolbar.findElement(import_selenium_webdriver13.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
743
+ const button = await toolbar.findElement(import_selenium_webdriver14.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
639
744
  if (button) {
640
745
  return new TableToolbarButton(this.getTableToolbarElement, name, this.driver);
641
746
  }
@@ -647,7 +752,7 @@ var TableToolbar = class extends AbstractElementWithParent {
647
752
  var ListForm = class extends AbstractForm {
648
753
  constructor(driver) {
649
754
  super(driver);
650
- this.popupContainerBy = import_selenium_webdriver14.By.className(`popup form-inline-${this.formName}`);
755
+ this.popupContainerBy = import_selenium_webdriver15.By.className(`popup form-inline-${this.formName}`);
651
756
  }
652
757
  /**
653
758
  * Находит таблицу
@@ -682,6 +787,13 @@ async function signIn(driver) {
682
787
  return webDriver;
683
788
  }
684
789
 
790
+ // src/utils/actions.ts
791
+ var click = async (webElement, driver) => {
792
+ driver = driver ?? config().driver;
793
+ const actions = driver.actions({ async: true });
794
+ await actions.move({ origin: webElement }).click().perform();
795
+ };
796
+
685
797
  // src/pageObjects/pages/LoginPage.ts
686
798
  var LOGIN_PATH = "/login";
687
799
  var LoginPage = class extends AbstractPage {
@@ -698,7 +810,7 @@ var LoginPage = class extends AbstractPage {
698
810
  await this.driver.findElement(this.passwordField).sendKeys(password);
699
811
  }
700
812
  async clickLoginButton() {
701
- await this.driver.findElement(this.loginButton).click();
813
+ await click(await this.driver.findElement(this.loginButton), this.driver);
702
814
  }
703
815
  async loginWith(username, password) {
704
816
  await this.enterUsername(username);
@@ -720,6 +832,7 @@ var LoginPage = class extends AbstractPage {
720
832
  SubsystemsPanel,
721
833
  TextEditor,
722
834
  byTestId,
835
+ click,
723
836
  config,
724
837
  createDriver,
725
838
  editorFactory,
@@ -1,5 +1,5 @@
1
1
  import * as selenium_webdriver from 'selenium-webdriver';
2
- import { WebDriver, Browser, By, Condition, WebElementPromise } from 'selenium-webdriver';
2
+ import { WebDriver, Browser, By, Condition, WebElement, WebElementPromise } from 'selenium-webdriver';
3
3
 
4
4
  type DriverType = typeof Browser;
5
5
  type BrowserList = DriverType[keyof DriverType];
@@ -66,6 +66,15 @@ declare const elementIsNotPresent: (locator: By) => Condition<boolean>;
66
66
 
67
67
  declare function signIn(driver?: WebDriver): Promise<WebDriver>;
68
68
 
69
+ /**
70
+ * Clicks on a specified web element.
71
+ *
72
+ * @param {WebElement} webElement - The web element to click on.
73
+ * @param {WebDriver} [driver] - The web driver instance to use. If not provided, the default driver from the configuration is used.
74
+ * @returns {Promise<void>} A promise that resolves when the click action is complete.
75
+ */
76
+ declare const click: (webElement: WebElement, driver?: WebDriver) => Promise<void>;
77
+
69
78
  declare class SubsystemsPanel extends AbstractElement {
70
79
  private panelBy;
71
80
  private header;
@@ -101,10 +110,10 @@ declare abstract class AbstractForm extends AbstractPage {
101
110
  }
102
111
 
103
112
  declare abstract class AbstractElementWithParent extends AbstractElement {
104
- protected getParentElement: () => WebElementPromise;
113
+ protected getParentElement: () => Promise<WebElement>;
105
114
  protected elementBy: By;
106
- constructor(getParentElement: () => WebElementPromise, driver?: WebDriver);
107
- getElement(): Promise<selenium_webdriver.WebElement>;
115
+ constructor(getParentElement: () => Promise<WebElement>, driver?: WebDriver);
116
+ getElement(): Promise<WebElement>;
108
117
  }
109
118
 
110
119
  interface Editor {
@@ -113,7 +122,7 @@ interface Editor {
113
122
  }
114
123
 
115
124
  declare class AbstractFormElement extends AbstractElementWithParent {
116
- constructor(getParentElement: () => WebElementPromise, elementBy: By, driver?: WebDriver);
125
+ constructor(getParentElement: () => Promise<WebElement>, elementBy: By, driver?: WebDriver);
117
126
  }
118
127
 
119
128
  declare abstract class AbstractDXEditorWithInput extends AbstractFormElement implements Editor {
@@ -134,11 +143,11 @@ declare class NumberEditor extends AbstractDXEditorWithInput {
134
143
  setValue(value: any): Promise<void>;
135
144
  }
136
145
 
137
- declare const editorFactory: (getParentElement: () => WebElementPromise, elementBy: By, driver?: WebDriver) => Promise<Editor>;
146
+ declare const editorFactory: (getParentElement: () => Promise<WebElement>, elementBy: By, driver?: WebDriver) => Promise<Editor>;
138
147
 
139
148
  declare class FormField extends AbstractElementWithParent implements Editor {
140
149
  editor: Editor;
141
- constructor(getParentElement: () => WebElementPromise, formName: string, name: string, driver?: WebDriver);
150
+ constructor(getParentElement: () => Promise<WebElement>, formName: string, name: string, driver?: WebDriver);
142
151
  private initEditor;
143
152
  /**
144
153
  * Возвращает значение в поле
@@ -180,11 +189,12 @@ declare abstract class FormEdit extends AbstractForm {
180
189
  declare class TableToolbarButton extends AbstractElementWithParent {
181
190
  constructor(getParentElement: () => WebElementPromise, name: string, driver?: WebDriver);
182
191
  click(): Promise<void>;
192
+ isDisabled(): Promise<boolean>;
183
193
  }
184
194
 
185
195
  declare class Cell extends AbstractElementWithParent {
186
196
  index: number;
187
- constructor(getParentElement: () => WebElementPromise, index: number, driver?: WebDriver);
197
+ constructor(rowEl: WebElement, index: number, driver?: WebDriver);
188
198
  getValue(): Promise<string>;
189
199
  getIndex(): number;
190
200
  }
@@ -200,16 +210,20 @@ declare class Row extends AbstractElementWithParent {
200
210
  index: number;
201
211
  protected getColumnByCaption: (caption: string) => Promise<Column>;
202
212
  constructor(getParentElement: () => WebElementPromise, index: number, driver?: WebDriver, getColumnByCaption?: (caption: string) => Promise<Column>);
203
- protected getRowElement: () => WebElementPromise;
204
213
  getCellByIndex(index: number): Promise<Cell>;
205
214
  getCell(caption: string): Promise<Cell>;
206
215
  select(): Promise<void>;
207
216
  isSelected(): Promise<boolean>;
208
217
  getIndex(): number;
209
218
  getCells(): Promise<Cell[]>;
219
+ private clickInlineButton;
220
+ edit(): Promise<void>;
221
+ save(): Promise<void>;
222
+ cancel(): Promise<void>;
210
223
  }
211
224
 
212
225
  declare class Table extends AbstractElementWithParent {
226
+ protected formName: string;
213
227
  constructor(getParentElement: () => WebElementPromise, formName: string, driver?: WebDriver);
214
228
  protected getHeaderElement(): Promise<selenium_webdriver.WebElement>;
215
229
  protected getDataGrid(): Promise<selenium_webdriver.WebElement>;
@@ -221,6 +235,14 @@ declare class Table extends AbstractElementWithParent {
221
235
  getRows(): Promise<Row[]>;
222
236
  getColumns(): Promise<Column[]>;
223
237
  element(): Promise<selenium_webdriver.WebElement>;
238
+ /**
239
+ * Находит поле когда форма находится в состоянии редактирования
240
+ * @example
241
+ * const form = new MyForm();
242
+ * //...
243
+ * expect(await form.field('Name').getValue()).toBe('test value');
244
+ */
245
+ field(name: string): FormField;
224
246
  }
225
247
 
226
248
  declare abstract class ListForm extends AbstractForm {
@@ -243,4 +265,4 @@ declare abstract class ListForm extends AbstractForm {
243
265
  toolbarButton(name: string): Promise<TableToolbarButton>;
244
266
  }
245
267
 
246
- export { AbstractPage, Editor, FormEdit, FormField, ListForm, LoginPage, NumberEditor, SubsystemsPanel, TextEditor, byTestId, config, createDriver, editorFactory, elementIsNotPresent, signIn };
268
+ export { AbstractPage, Editor, FormEdit, FormField, ListForm, LoginPage, NumberEditor, SubsystemsPanel, TextEditor, byTestId, click, config, createDriver, editorFactory, elementIsNotPresent, signIn };
@@ -1,4 +1,23 @@
1
1
  // src/config.ts
2
+ import * as process from "node:process";
3
+ var driversMap = /* @__PURE__ */ new Map();
4
+ var createConfigProxy = (config2) => {
5
+ return new Proxy(config2, {
6
+ get(_target, prop) {
7
+ if (prop === "driver") {
8
+ return driversMap.get(process.pid);
9
+ }
10
+ return Reflect.get(...arguments);
11
+ },
12
+ set(_target, prop, value) {
13
+ if (prop === "driver") {
14
+ driversMap.set(process.pid, value);
15
+ return true;
16
+ }
17
+ return Reflect.set(...arguments);
18
+ }
19
+ });
20
+ };
2
21
  var Config = class _Config {
3
22
  static instance;
4
23
  appConfig;
@@ -10,7 +29,7 @@ var Config = class _Config {
10
29
  }
11
30
  config = (cfg) => {
12
31
  if (!cfg)
13
- return this.appConfig;
32
+ return createConfigProxy(this.appConfig);
14
33
  this.appConfig = cfg;
15
34
  };
16
35
  };
@@ -81,6 +100,9 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
81
100
  });
82
101
  };
83
102
 
103
+ // src/utils/waitElementIsVisible.ts
104
+ import { until } from "selenium-webdriver";
105
+
84
106
  // src/pageObjects/AbstractElementWithParent.ts
85
107
  var AbstractElementWithParent = class extends AbstractElement {
86
108
  getParentElement;
@@ -202,7 +224,7 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
202
224
  }
203
225
  async setInputValue(value) {
204
226
  const inputEl = await this.getInputElement();
205
- await inputEl.click();
227
+ await click(inputEl, this.driver);
206
228
  await inputEl.sendKeys(value, Key.ENTER);
207
229
  }
208
230
  };
@@ -243,7 +265,7 @@ var CheckBox = class extends AbstractFormElement {
243
265
  const inputEl = await this.getElement();
244
266
  const currentValue = await this.getValue();
245
267
  if (currentValue !== value) {
246
- await inputEl.click();
268
+ await click(inputEl, this.driver);
247
269
  }
248
270
  }
249
271
  };
@@ -267,13 +289,13 @@ var SELECT_BOX_ELEMENT_ROLE = "option";
267
289
  var SelectBoxEditor = class extends AbstractDXEditorWithInput {
268
290
  async setSelectInputValue(value) {
269
291
  const inputEl = await this.getInputElement();
270
- await inputEl.click();
292
+ await click(inputEl, this.driver);
271
293
  await inputEl.sendKeys(value, Key2.ENTER);
272
294
  const combinedValueXpath = XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE) + XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value);
273
295
  await this.driver.wait(async () => {
274
296
  try {
275
297
  const optElement = await inputEl.findElement(By6.xpath(combinedValueXpath));
276
- await optElement.click();
298
+ await click(optElement, this.driver);
277
299
  return true;
278
300
  } catch (e) {
279
301
  return false;
@@ -289,6 +311,33 @@ var SelectBoxEditor = class extends AbstractDXEditorWithInput {
289
311
  }
290
312
  };
291
313
 
314
+ // src/pageObjects/elements/Editors/SwitchEditor.ts
315
+ var SwitchEditor = class extends AbstractFormElement {
316
+ async getValue() {
317
+ const inputEl = await this.getElement();
318
+ const result = await inputEl.getAttribute("aria-label");
319
+ if (result === "ON")
320
+ return 1;
321
+ if (result === "OFF")
322
+ return 0;
323
+ return void 0;
324
+ }
325
+ async setValue(value) {
326
+ if (value !== 0 && value !== 1) {
327
+ value = value ? 1 : 0;
328
+ }
329
+ const inputEl = await this.getElement();
330
+ const currentValue = await this.getValue();
331
+ if (currentValue !== value) {
332
+ await click(inputEl, this.driver);
333
+ await this.driver.wait(async () => {
334
+ const updatedValue = await this.getValue();
335
+ return updatedValue !== currentValue;
336
+ });
337
+ }
338
+ }
339
+ };
340
+
292
341
  // src/pageObjects/elements/Editors/editorFactory.ts
293
342
  var editorFactory = async (getParentElement, elementBy, driver) => {
294
343
  const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
@@ -302,6 +351,8 @@ var editorFactory = async (getParentElement, elementBy, driver) => {
302
351
  return new CheckBox(getParentElement, elementBy, driver);
303
352
  if (classSting.includes("select-control"))
304
353
  return new SelectBoxEditor(getParentElement, elementBy, driver);
354
+ if (classSting.includes("switch-control"))
355
+ return new SwitchEditor(getParentElement, elementBy, driver);
305
356
  throw new Error("Unknown type of editor. Please write ticket to the support");
306
357
  };
307
358
 
@@ -375,7 +426,7 @@ var FormEdit = class extends AbstractForm {
375
426
  * await formEdit.saveButtonClick();
376
427
  */
377
428
  async saveButtonClick() {
378
- await this.driver.findElement(this.saveButtonBy).click();
429
+ await click(await this.driver.findElement(this.saveButtonBy), this.driver);
379
430
  }
380
431
  };
381
432
 
@@ -388,16 +439,16 @@ import { By as By10 } from "selenium-webdriver";
388
439
  // src/pageObjects/elements/Table/utils.ts
389
440
  import { By as By8 } from "selenium-webdriver";
390
441
  var getRowPathByIndex = (index) => {
391
- return By8.xpath(`//tr[@aria-rowindex="${transformInputIndex(index)}"]`);
442
+ return By8.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
392
443
  };
393
444
  var getColumnPathByIndex = (index) => {
394
- return By8.xpath(`//td[@aria-colindex="${transformInputIndex(index)}"]`);
445
+ return By8.css(`td[aria-colindex="${transformInputIndex(index)}"]`);
395
446
  };
396
447
  var getColumnPathByCaption = (caption) => {
397
- return By8.xpath(`//td[@role="columnheader"][@aria-label="Column ${caption}"]`);
448
+ return By8.css(`td[role="columnheader"][aria-label="Column ${caption}"]`);
398
449
  };
399
450
  var getCellPathByIndex = (index) => {
400
- return By8.xpath(`//td[@role="gridcell"][@aria-colindex="${transformInputIndex(index)}"]`);
451
+ return By8.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
401
452
  };
402
453
  var transformInputIndex = (index) => index + 1;
403
454
  var transformOutputIndex = (index) => +index - 1;
@@ -408,8 +459,8 @@ import { By as By9 } from "selenium-webdriver";
408
459
  // src/pageObjects/elements/Table/elements/Cell.ts
409
460
  var Cell = class extends AbstractElementWithParent {
410
461
  index;
411
- constructor(getParentElement, index, driver) {
412
- super(getParentElement, driver);
462
+ constructor(rowEl, index, driver) {
463
+ super(() => Promise.resolve(rowEl), driver);
413
464
  this.index = index;
414
465
  this.elementBy = getCellPathByIndex(index);
415
466
  }
@@ -423,6 +474,8 @@ var Cell = class extends AbstractElementWithParent {
423
474
  };
424
475
 
425
476
  // src/pageObjects/elements/Table/elements/Row.ts
477
+ var DX_SELECTION_CLASS = "dx-selection";
478
+ var DX_ROW_EDIT_CLASS = "dx-edit-row";
426
479
  var Row = class extends AbstractElementWithParent {
427
480
  index;
428
481
  getColumnByCaption;
@@ -432,14 +485,11 @@ var Row = class extends AbstractElementWithParent {
432
485
  this.elementBy = getRowPathByIndex(index);
433
486
  this.getColumnByCaption = getColumnByCaption;
434
487
  }
435
- getRowElement = () => {
436
- return this.driver.findElement(this.elementBy);
437
- };
438
488
  async getCellByIndex(index) {
439
489
  const rowEl = await this.getElement();
440
490
  const cell = rowEl.findElement(getCellPathByIndex(index));
441
491
  if (cell) {
442
- return new Cell(this.getRowElement, index, this.driver);
492
+ return new Cell(rowEl, index, this.driver);
443
493
  }
444
494
  throw new Error(`Cannot find cell by index: ${index}`);
445
495
  }
@@ -453,7 +503,13 @@ var Row = class extends AbstractElementWithParent {
453
503
  }
454
504
  async select() {
455
505
  const rowEl = await this.getElement();
456
- await rowEl.click();
506
+ await click(rowEl, this.driver);
507
+ await this.driver.wait(async () => {
508
+ const classes = await rowEl.getAttribute("class");
509
+ if (!classes.includes(DX_SELECTION_CLASS))
510
+ throw new Error("Cannot select row");
511
+ return true;
512
+ }, 500);
457
513
  }
458
514
  async isSelected() {
459
515
  const rowEl = await this.getElement();
@@ -468,11 +524,32 @@ var Row = class extends AbstractElementWithParent {
468
524
  const cells = await rowEl.findElements(By9.css(`td[role="gridcell"]`));
469
525
  const result = [];
470
526
  cells.forEach((_, index) => {
471
- const newCell = new Cell(this.getRowElement, index, this.driver);
527
+ const newCell = new Cell(rowEl, index, this.driver);
472
528
  result.push(newCell);
473
529
  });
474
530
  return result;
475
531
  }
532
+ async clickInlineButton(rowClass, buttonClass) {
533
+ const fixedTable = (await this.getParentElement()).findElement(
534
+ By9.css(".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed")
535
+ );
536
+ const rowEl = await fixedTable.findElement(By9.className(rowClass));
537
+ const button = await rowEl.findElement(By9.className(buttonClass));
538
+ if (button) {
539
+ return click(button, this.driver);
540
+ }
541
+ throw new Error(`Cannot find ${buttonClass} button`);
542
+ }
543
+ async edit() {
544
+ await this.select();
545
+ return this.clickInlineButton(DX_SELECTION_CLASS, "edit");
546
+ }
547
+ async save() {
548
+ return this.clickInlineButton(DX_ROW_EDIT_CLASS, "save");
549
+ }
550
+ async cancel() {
551
+ return this.clickInlineButton(DX_ROW_EDIT_CLASS, "cancel");
552
+ }
476
553
  };
477
554
 
478
555
  // src/pageObjects/elements/Table/elements/Column.ts
@@ -494,9 +571,11 @@ var Column = class extends AbstractElementWithParent {
494
571
 
495
572
  // src/pageObjects/elements/Table/Table.ts
496
573
  var Table = class extends AbstractElementWithParent {
574
+ formName;
497
575
  constructor(getParentElement, formName, driver) {
498
576
  super(getParentElement, driver);
499
577
  this.elementBy = By10.id(createTableId(formName));
578
+ this.formName = formName;
500
579
  }
501
580
  async getHeaderElement() {
502
581
  const parentEl = await this.getElement();
@@ -562,9 +641,19 @@ var Table = class extends AbstractElementWithParent {
562
641
  });
563
642
  return result;
564
643
  }
565
- async element() {
644
+ element() {
566
645
  return this.getElement();
567
646
  }
647
+ /**
648
+ * Находит поле когда форма находится в состоянии редактирования
649
+ * @example
650
+ * const form = new MyForm();
651
+ * //...
652
+ * expect(await form.field('Name').getValue()).toBe('test value');
653
+ */
654
+ field(name) {
655
+ return new FormField(this.getElement, this.formName, name, this.driver);
656
+ }
568
657
  };
569
658
 
570
659
  // src/pageObjects/elements/TableToolbar/TableToolbar.ts
@@ -580,7 +669,12 @@ var TableToolbarButton = class extends AbstractElementWithParent {
580
669
  }
581
670
  async click() {
582
671
  const button = await this.getElement();
583
- return button.click();
672
+ return click(button, this.driver);
673
+ }
674
+ async isDisabled() {
675
+ const button = await this.getElement();
676
+ const result = await button.getAttribute("aria-disabled");
677
+ return result === "true";
584
678
  }
585
679
  };
586
680
 
@@ -643,6 +737,13 @@ async function signIn(driver) {
643
737
  return webDriver;
644
738
  }
645
739
 
740
+ // src/utils/actions.ts
741
+ var click = async (webElement, driver) => {
742
+ driver = driver ?? config().driver;
743
+ const actions = driver.actions({ async: true });
744
+ await actions.move({ origin: webElement }).click().perform();
745
+ };
746
+
646
747
  // src/pageObjects/pages/LoginPage.ts
647
748
  var LOGIN_PATH = "/login";
648
749
  var LoginPage = class extends AbstractPage {
@@ -659,7 +760,7 @@ var LoginPage = class extends AbstractPage {
659
760
  await this.driver.findElement(this.passwordField).sendKeys(password);
660
761
  }
661
762
  async clickLoginButton() {
662
- await this.driver.findElement(this.loginButton).click();
763
+ await click(await this.driver.findElement(this.loginButton), this.driver);
663
764
  }
664
765
  async loginWith(username, password) {
665
766
  await this.enterUsername(username);
@@ -680,6 +781,7 @@ export {
680
781
  SubsystemsPanel,
681
782
  TextEditor,
682
783
  byTestId,
784
+ click,
683
785
  config,
684
786
  createDriver,
685
787
  editorFactory,
@@ -1,4 +1,23 @@
1
1
  // src/config.ts
2
+ import * as process from "node:process";
3
+ var driversMap = /* @__PURE__ */ new Map();
4
+ var createConfigProxy = (config2) => {
5
+ return new Proxy(config2, {
6
+ get(_target, prop) {
7
+ if (prop === "driver") {
8
+ return driversMap.get(process.pid);
9
+ }
10
+ return Reflect.get(...arguments);
11
+ },
12
+ set(_target, prop, value) {
13
+ if (prop === "driver") {
14
+ driversMap.set(process.pid, value);
15
+ return true;
16
+ }
17
+ return Reflect.set(...arguments);
18
+ }
19
+ });
20
+ };
2
21
  var Config = class _Config {
3
22
  static instance;
4
23
  appConfig;
@@ -10,7 +29,7 @@ var Config = class _Config {
10
29
  }
11
30
  config = (cfg) => {
12
31
  if (!cfg)
13
- return this.appConfig;
32
+ return createConfigProxy(this.appConfig);
14
33
  this.appConfig = cfg;
15
34
  };
16
35
  };
@@ -81,6 +100,9 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
81
100
  });
82
101
  };
83
102
 
103
+ // src/utils/waitElementIsVisible.ts
104
+ import { until } from "selenium-webdriver";
105
+
84
106
  // src/pageObjects/AbstractElementWithParent.ts
85
107
  var AbstractElementWithParent = class extends AbstractElement {
86
108
  getParentElement;
@@ -202,7 +224,7 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
202
224
  }
203
225
  async setInputValue(value) {
204
226
  const inputEl = await this.getInputElement();
205
- await inputEl.click();
227
+ await click(inputEl, this.driver);
206
228
  await inputEl.sendKeys(value, Key.ENTER);
207
229
  }
208
230
  };
@@ -243,7 +265,7 @@ var CheckBox = class extends AbstractFormElement {
243
265
  const inputEl = await this.getElement();
244
266
  const currentValue = await this.getValue();
245
267
  if (currentValue !== value) {
246
- await inputEl.click();
268
+ await click(inputEl, this.driver);
247
269
  }
248
270
  }
249
271
  };
@@ -267,13 +289,13 @@ var SELECT_BOX_ELEMENT_ROLE = "option";
267
289
  var SelectBoxEditor = class extends AbstractDXEditorWithInput {
268
290
  async setSelectInputValue(value) {
269
291
  const inputEl = await this.getInputElement();
270
- await inputEl.click();
292
+ await click(inputEl, this.driver);
271
293
  await inputEl.sendKeys(value, Key2.ENTER);
272
294
  const combinedValueXpath = XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE) + XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value);
273
295
  await this.driver.wait(async () => {
274
296
  try {
275
297
  const optElement = await inputEl.findElement(By6.xpath(combinedValueXpath));
276
- await optElement.click();
298
+ await click(optElement, this.driver);
277
299
  return true;
278
300
  } catch (e) {
279
301
  return false;
@@ -289,6 +311,33 @@ var SelectBoxEditor = class extends AbstractDXEditorWithInput {
289
311
  }
290
312
  };
291
313
 
314
+ // src/pageObjects/elements/Editors/SwitchEditor.ts
315
+ var SwitchEditor = class extends AbstractFormElement {
316
+ async getValue() {
317
+ const inputEl = await this.getElement();
318
+ const result = await inputEl.getAttribute("aria-label");
319
+ if (result === "ON")
320
+ return 1;
321
+ if (result === "OFF")
322
+ return 0;
323
+ return void 0;
324
+ }
325
+ async setValue(value) {
326
+ if (value !== 0 && value !== 1) {
327
+ value = value ? 1 : 0;
328
+ }
329
+ const inputEl = await this.getElement();
330
+ const currentValue = await this.getValue();
331
+ if (currentValue !== value) {
332
+ await click(inputEl, this.driver);
333
+ await this.driver.wait(async () => {
334
+ const updatedValue = await this.getValue();
335
+ return updatedValue !== currentValue;
336
+ });
337
+ }
338
+ }
339
+ };
340
+
292
341
  // src/pageObjects/elements/Editors/editorFactory.ts
293
342
  var editorFactory = async (getParentElement, elementBy, driver) => {
294
343
  const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
@@ -302,6 +351,8 @@ var editorFactory = async (getParentElement, elementBy, driver) => {
302
351
  return new CheckBox(getParentElement, elementBy, driver);
303
352
  if (classSting.includes("select-control"))
304
353
  return new SelectBoxEditor(getParentElement, elementBy, driver);
354
+ if (classSting.includes("switch-control"))
355
+ return new SwitchEditor(getParentElement, elementBy, driver);
305
356
  throw new Error("Unknown type of editor. Please write ticket to the support");
306
357
  };
307
358
 
@@ -375,7 +426,7 @@ var FormEdit = class extends AbstractForm {
375
426
  * await formEdit.saveButtonClick();
376
427
  */
377
428
  async saveButtonClick() {
378
- await this.driver.findElement(this.saveButtonBy).click();
429
+ await click(await this.driver.findElement(this.saveButtonBy), this.driver);
379
430
  }
380
431
  };
381
432
 
@@ -388,16 +439,16 @@ import { By as By10 } from "selenium-webdriver";
388
439
  // src/pageObjects/elements/Table/utils.ts
389
440
  import { By as By8 } from "selenium-webdriver";
390
441
  var getRowPathByIndex = (index) => {
391
- return By8.xpath(`//tr[@aria-rowindex="${transformInputIndex(index)}"]`);
442
+ return By8.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
392
443
  };
393
444
  var getColumnPathByIndex = (index) => {
394
- return By8.xpath(`//td[@aria-colindex="${transformInputIndex(index)}"]`);
445
+ return By8.css(`td[aria-colindex="${transformInputIndex(index)}"]`);
395
446
  };
396
447
  var getColumnPathByCaption = (caption) => {
397
- return By8.xpath(`//td[@role="columnheader"][@aria-label="Column ${caption}"]`);
448
+ return By8.css(`td[role="columnheader"][aria-label="Column ${caption}"]`);
398
449
  };
399
450
  var getCellPathByIndex = (index) => {
400
- return By8.xpath(`//td[@role="gridcell"][@aria-colindex="${transformInputIndex(index)}"]`);
451
+ return By8.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
401
452
  };
402
453
  var transformInputIndex = (index) => index + 1;
403
454
  var transformOutputIndex = (index) => +index - 1;
@@ -408,8 +459,8 @@ import { By as By9 } from "selenium-webdriver";
408
459
  // src/pageObjects/elements/Table/elements/Cell.ts
409
460
  var Cell = class extends AbstractElementWithParent {
410
461
  index;
411
- constructor(getParentElement, index, driver) {
412
- super(getParentElement, driver);
462
+ constructor(rowEl, index, driver) {
463
+ super(() => Promise.resolve(rowEl), driver);
413
464
  this.index = index;
414
465
  this.elementBy = getCellPathByIndex(index);
415
466
  }
@@ -423,6 +474,8 @@ var Cell = class extends AbstractElementWithParent {
423
474
  };
424
475
 
425
476
  // src/pageObjects/elements/Table/elements/Row.ts
477
+ var DX_SELECTION_CLASS = "dx-selection";
478
+ var DX_ROW_EDIT_CLASS = "dx-edit-row";
426
479
  var Row = class extends AbstractElementWithParent {
427
480
  index;
428
481
  getColumnByCaption;
@@ -432,14 +485,11 @@ var Row = class extends AbstractElementWithParent {
432
485
  this.elementBy = getRowPathByIndex(index);
433
486
  this.getColumnByCaption = getColumnByCaption;
434
487
  }
435
- getRowElement = () => {
436
- return this.driver.findElement(this.elementBy);
437
- };
438
488
  async getCellByIndex(index) {
439
489
  const rowEl = await this.getElement();
440
490
  const cell = rowEl.findElement(getCellPathByIndex(index));
441
491
  if (cell) {
442
- return new Cell(this.getRowElement, index, this.driver);
492
+ return new Cell(rowEl, index, this.driver);
443
493
  }
444
494
  throw new Error(`Cannot find cell by index: ${index}`);
445
495
  }
@@ -453,7 +503,13 @@ var Row = class extends AbstractElementWithParent {
453
503
  }
454
504
  async select() {
455
505
  const rowEl = await this.getElement();
456
- await rowEl.click();
506
+ await click(rowEl, this.driver);
507
+ await this.driver.wait(async () => {
508
+ const classes = await rowEl.getAttribute("class");
509
+ if (!classes.includes(DX_SELECTION_CLASS))
510
+ throw new Error("Cannot select row");
511
+ return true;
512
+ }, 500);
457
513
  }
458
514
  async isSelected() {
459
515
  const rowEl = await this.getElement();
@@ -468,11 +524,32 @@ var Row = class extends AbstractElementWithParent {
468
524
  const cells = await rowEl.findElements(By9.css(`td[role="gridcell"]`));
469
525
  const result = [];
470
526
  cells.forEach((_, index) => {
471
- const newCell = new Cell(this.getRowElement, index, this.driver);
527
+ const newCell = new Cell(rowEl, index, this.driver);
472
528
  result.push(newCell);
473
529
  });
474
530
  return result;
475
531
  }
532
+ async clickInlineButton(rowClass, buttonClass) {
533
+ const fixedTable = (await this.getParentElement()).findElement(
534
+ By9.css(".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed")
535
+ );
536
+ const rowEl = await fixedTable.findElement(By9.className(rowClass));
537
+ const button = await rowEl.findElement(By9.className(buttonClass));
538
+ if (button) {
539
+ return click(button, this.driver);
540
+ }
541
+ throw new Error(`Cannot find ${buttonClass} button`);
542
+ }
543
+ async edit() {
544
+ await this.select();
545
+ return this.clickInlineButton(DX_SELECTION_CLASS, "edit");
546
+ }
547
+ async save() {
548
+ return this.clickInlineButton(DX_ROW_EDIT_CLASS, "save");
549
+ }
550
+ async cancel() {
551
+ return this.clickInlineButton(DX_ROW_EDIT_CLASS, "cancel");
552
+ }
476
553
  };
477
554
 
478
555
  // src/pageObjects/elements/Table/elements/Column.ts
@@ -494,9 +571,11 @@ var Column = class extends AbstractElementWithParent {
494
571
 
495
572
  // src/pageObjects/elements/Table/Table.ts
496
573
  var Table = class extends AbstractElementWithParent {
574
+ formName;
497
575
  constructor(getParentElement, formName, driver) {
498
576
  super(getParentElement, driver);
499
577
  this.elementBy = By10.id(createTableId(formName));
578
+ this.formName = formName;
500
579
  }
501
580
  async getHeaderElement() {
502
581
  const parentEl = await this.getElement();
@@ -562,9 +641,19 @@ var Table = class extends AbstractElementWithParent {
562
641
  });
563
642
  return result;
564
643
  }
565
- async element() {
644
+ element() {
566
645
  return this.getElement();
567
646
  }
647
+ /**
648
+ * Находит поле когда форма находится в состоянии редактирования
649
+ * @example
650
+ * const form = new MyForm();
651
+ * //...
652
+ * expect(await form.field('Name').getValue()).toBe('test value');
653
+ */
654
+ field(name) {
655
+ return new FormField(this.getElement, this.formName, name, this.driver);
656
+ }
568
657
  };
569
658
 
570
659
  // src/pageObjects/elements/TableToolbar/TableToolbar.ts
@@ -580,7 +669,12 @@ var TableToolbarButton = class extends AbstractElementWithParent {
580
669
  }
581
670
  async click() {
582
671
  const button = await this.getElement();
583
- return button.click();
672
+ return click(button, this.driver);
673
+ }
674
+ async isDisabled() {
675
+ const button = await this.getElement();
676
+ const result = await button.getAttribute("aria-disabled");
677
+ return result === "true";
584
678
  }
585
679
  };
586
680
 
@@ -643,6 +737,13 @@ async function signIn(driver) {
643
737
  return webDriver;
644
738
  }
645
739
 
740
+ // src/utils/actions.ts
741
+ var click = async (webElement, driver) => {
742
+ driver = driver ?? config().driver;
743
+ const actions = driver.actions({ async: true });
744
+ await actions.move({ origin: webElement }).click().perform();
745
+ };
746
+
646
747
  // src/pageObjects/pages/LoginPage.ts
647
748
  var LOGIN_PATH = "/login";
648
749
  var LoginPage = class extends AbstractPage {
@@ -659,7 +760,7 @@ var LoginPage = class extends AbstractPage {
659
760
  await this.driver.findElement(this.passwordField).sendKeys(password);
660
761
  }
661
762
  async clickLoginButton() {
662
- await this.driver.findElement(this.loginButton).click();
763
+ await click(await this.driver.findElement(this.loginButton), this.driver);
663
764
  }
664
765
  async loginWith(username, password) {
665
766
  await this.enterUsername(username);
@@ -680,6 +781,7 @@ export {
680
781
  SubsystemsPanel,
681
782
  TextEditor,
682
783
  byTestId,
784
+ click,
683
785
  config,
684
786
  createDriver,
685
787
  editorFactory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "d5-testing-library",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "e2e testing D5 projects",
5
5
  "main": "dist/cjs/d5-testing-library.cjs",
6
6
  "module": "dist/d5-testing-library.legacy-esm.js",