d5-testing-library 1.4.0 → 1.5.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.
@@ -0,0 +1,1106 @@
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
+ };
21
+ var Config = class _Config {
22
+ static instance;
23
+ appConfig;
24
+ static getInstance() {
25
+ if (!_Config.instance) {
26
+ _Config.instance = new _Config();
27
+ }
28
+ return _Config.instance;
29
+ }
30
+ config = (cfg) => {
31
+ if (!cfg)
32
+ return createConfigProxy(this.appConfig);
33
+ this.appConfig = cfg;
34
+ };
35
+ };
36
+ var configInstance = Config.getInstance();
37
+ function config(cfg) {
38
+ return configInstance.config(cfg);
39
+ }
40
+
41
+ // src/pageObjects/AbstractElement.ts
42
+ import { By } from "selenium-webdriver";
43
+
44
+ // src/utils/fixElementStaleError.ts
45
+ function fixElementStaleError(by, driver) {
46
+ const maxCount = 3;
47
+ let err;
48
+ const call = async (times = 0) => {
49
+ if (times > maxCount)
50
+ throw err;
51
+ try {
52
+ let el = await driver.findElement(by);
53
+ await el.getAttribute("class");
54
+ return el;
55
+ } catch (e) {
56
+ err = e;
57
+ if (e instanceof Error && e.name === "StaleElementReferenceError") {
58
+ return call(++times);
59
+ }
60
+ }
61
+ if (err)
62
+ throw err;
63
+ };
64
+ return call();
65
+ }
66
+
67
+ // src/pageObjects/AbstractElement.ts
68
+ var AbstractElement = class {
69
+ driver;
70
+ elementCssSelector;
71
+ constructor(driver, elementCssSelector) {
72
+ this.driver = driver || config().driver;
73
+ this.elementCssSelector = elementCssSelector;
74
+ }
75
+ getFullCssSelector() {
76
+ return this.elementCssSelector;
77
+ }
78
+ joinRelativeCssSelectors(selectors) {
79
+ return selectors.join(" ");
80
+ }
81
+ getElement() {
82
+ return fixElementStaleError(By.css(this.getFullCssSelector()), this.driver);
83
+ }
84
+ async getAttribute(attr) {
85
+ const element = await this.getElement();
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");
93
+ }
94
+ };
95
+
96
+ // src/pageObjects/pages/AbstractPage.ts
97
+ var AbstractPage = class extends AbstractElement {
98
+ url;
99
+ host;
100
+ constructor(driver) {
101
+ super(driver);
102
+ this.host = config().auth.host;
103
+ this.url = this.host + this.prependHash(this.path);
104
+ }
105
+ prependHash(urlPath) {
106
+ if (!urlPath.startsWith("/#")) {
107
+ return `/#${urlPath}`;
108
+ }
109
+ return urlPath;
110
+ }
111
+ async goToUrl(url) {
112
+ await this.driver.get(url);
113
+ }
114
+ get path() {
115
+ return "/#";
116
+ }
117
+ async locate() {
118
+ await this.goToUrl(this.url);
119
+ }
120
+ async reloadPage() {
121
+ await this.driver.navigate().refresh();
122
+ }
123
+ };
124
+
125
+ // src/utils/wait.ts
126
+ async function wait(condition, driver, errorMessage, timeout) {
127
+ driver = driver ?? config().driver;
128
+ await driver.wait(condition, timeout ?? config().timeout, errorMessage);
129
+ }
130
+
131
+ // src/utils/waitElementIsVisible.ts
132
+ import { until } from "selenium-webdriver";
133
+ async function waitElementIsVisible({
134
+ element,
135
+ timeout,
136
+ errorMessage,
137
+ driver
138
+ }) {
139
+ driver = driver ?? config().driver;
140
+ const condition = until.elementIsVisible(element);
141
+ await wait(condition.fn, driver, errorMessage ?? condition.description(), timeout ?? config().timeout);
142
+ }
143
+
144
+ // src/utils/actions.ts
145
+ var click = async (webElement, driver) => {
146
+ driver = driver ?? config().driver;
147
+ if (!await webElement.isDisplayed()) {
148
+ await driver.executeScript("arguments[0].scrollIntoView(true);", webElement);
149
+ }
150
+ const actions = driver.actions({ async: true });
151
+ await actions.move({ origin: webElement }).click().perform();
152
+ };
153
+
154
+ // src/utils/locators.ts
155
+ import { By as By2 } from "selenium-webdriver";
156
+ var byTestIdCssSelector = (testId, element = "div") => {
157
+ return `${element}[data-testid="${testId}"]`;
158
+ };
159
+ var byTestId = (testId, element = "div") => {
160
+ return By2.css(byTestIdCssSelector(testId, element));
161
+ };
162
+ var readonlyLocator = "readonly";
163
+
164
+ // src/pageObjects/elements/Editors/AbstractEditor.ts
165
+ import { By as By3, Key } from "selenium-webdriver";
166
+
167
+ // src/pageObjects/elements/Editors/ClearStrategy/InputClearStrategy.ts
168
+ var InputClearStrategy = class {
169
+ async clear(editor) {
170
+ const inputEl = await editor.getInputElement();
171
+ await inputEl.clear();
172
+ }
173
+ };
174
+
175
+ // src/pageObjects/AbstractElementWithParent.ts
176
+ var AbstractElementWithParent = class extends AbstractElement {
177
+ parentCssSelector;
178
+ constructor(parentCssSelector, elementCssSelector, driver) {
179
+ super(driver, elementCssSelector);
180
+ this.parentCssSelector = parentCssSelector;
181
+ }
182
+ getFullCssSelector() {
183
+ if (!this.elementCssSelector) {
184
+ return this.parentCssSelector;
185
+ }
186
+ if (!this.parentCssSelector) {
187
+ return this.elementCssSelector;
188
+ }
189
+ return `${this.parentCssSelector} ${this.elementCssSelector}`;
190
+ }
191
+ async isReadonly() {
192
+ const classSting = await this.getClasses();
193
+ return classSting.includes(readonlyLocator);
194
+ }
195
+ };
196
+
197
+ // src/pageObjects/elements/Editors/AbstractEditor.ts
198
+ var AbstractDXEditorWithInput = class extends AbstractElementWithParent {
199
+ clearStrategy = new InputClearStrategy();
200
+ setClearStrategy(strategy) {
201
+ this.clearStrategy = strategy;
202
+ }
203
+ getInputCssSelector() {
204
+ return `${this.getFullCssSelector()} .dx-texteditor-input`;
205
+ }
206
+ async getInputElement() {
207
+ return this.driver.findElement(By3.css(this.getInputCssSelector()));
208
+ }
209
+ async getInputValue() {
210
+ const inputEl = await this.getInputElement();
211
+ return inputEl.getAttribute("value");
212
+ }
213
+ async setInputValue(value) {
214
+ const inputEl = await this.getInputElement();
215
+ await click(inputEl, this.driver);
216
+ await inputEl.sendKeys(value, Key.ENTER);
217
+ }
218
+ async clear() {
219
+ await this.clearStrategy.clear(this);
220
+ }
221
+ };
222
+
223
+ // src/pageObjects/elements/Editors/TextEditor.ts
224
+ var TextEditor = class extends AbstractDXEditorWithInput {
225
+ constructor(parentCssSelector, elementCssSelector, driver) {
226
+ super(parentCssSelector, elementCssSelector, driver);
227
+ this.setClearStrategy(new InputClearStrategy());
228
+ }
229
+ getValue() {
230
+ return this.getInputValue();
231
+ }
232
+ setValue(value) {
233
+ return this.setInputValue(value);
234
+ }
235
+ };
236
+
237
+ // src/pageObjects/elements/Editors/NumberEditor.ts
238
+ var NumberEditor = class extends AbstractDXEditorWithInput {
239
+ constructor(parentCssSelector, elementCssSelector, driver) {
240
+ super(parentCssSelector, elementCssSelector, driver);
241
+ this.setClearStrategy(new InputClearStrategy());
242
+ }
243
+ async getValue() {
244
+ const value = await super.getInputValue();
245
+ return value == "" ? null : Number.parseFloat(value);
246
+ }
247
+ setValue(value) {
248
+ return this.setInputValue(value);
249
+ }
250
+ };
251
+
252
+ // src/pageObjects/elements/Editors/types.ts
253
+ var ControlClass = /* @__PURE__ */ ((ControlClass2) => {
254
+ ControlClass2["Text"] = "text-control";
255
+ ControlClass2["TextArea"] = "text-area-control";
256
+ ControlClass2["Number"] = "number-control";
257
+ ControlClass2["CheckBox"] = "check-box";
258
+ ControlClass2["Multiselect"] = "multi-select-control";
259
+ ControlClass2["Select"] = "select-control";
260
+ ControlClass2["Switch"] = "switch-control";
261
+ ControlClass2["Date"] = "date-control";
262
+ ControlClass2["SingleDateRange"] = "single-date-range-control";
263
+ ControlClass2["BooleanSelector"] = "buttons-group";
264
+ ControlClass2["ButtonGroup"] = "button-group-field";
265
+ return ControlClass2;
266
+ })(ControlClass || {});
267
+
268
+ // src/pageObjects/AbstractFormElement.ts
269
+ var AbstractFormElement = class extends AbstractElementWithParent {
270
+ constructor(parentCssSelector, elementCssSelector, driver) {
271
+ super(parentCssSelector, elementCssSelector, driver);
272
+ }
273
+ };
274
+
275
+ // src/pageObjects/elements/Editors/CheckBox.ts
276
+ var CheckBox = class extends AbstractElementWithParent {
277
+ async getValue() {
278
+ const result = await this.getAttribute("aria-checked");
279
+ if (result === "true")
280
+ return 1;
281
+ if (result === "false")
282
+ return 0;
283
+ return null;
284
+ }
285
+ async setValue(value) {
286
+ const inputEl = await this.getElement();
287
+ const currentValue = await this.getValue();
288
+ if (currentValue !== value) {
289
+ await click(inputEl, this.driver);
290
+ }
291
+ }
292
+ };
293
+
294
+ // src/pageObjects/elements/Editors/SelectBoxEditor.ts
295
+ import { By as By5, Key as Key2 } from "selenium-webdriver";
296
+
297
+ // src/utils/xpathHelper.ts
298
+ var XPathHelper = class {
299
+ static getClassAndValueXpath(cssClass, value) {
300
+ return `div[contains(@class, '${cssClass}') and contains(.,'${value}')]`;
301
+ }
302
+ };
303
+
304
+ // src/pageObjects/elements/Editors/ClearStrategy/ClearButtonStrategy.ts
305
+ import { By as By4 } from "selenium-webdriver";
306
+ var DX_TEXTEDITOR_EMPTY = "dx-texteditor-empty";
307
+ var DX_CLEAR_BUTTON_AREA = "dx-clear-button-area";
308
+ var ClearButtonStrategy = class {
309
+ editorContainerClass;
310
+ _driver;
311
+ constructor(editorContainerClass, driver) {
312
+ this.editorContainerClass = editorContainerClass;
313
+ this._driver = driver;
314
+ }
315
+ async isEmptyEditorField() {
316
+ const editorContainer = await this._driver.findElement(By4.css(this.editorContainerClass));
317
+ const classAttribute = await editorContainer.getAttribute("class");
318
+ return classAttribute.includes(DX_TEXTEDITOR_EMPTY);
319
+ }
320
+ async clear() {
321
+ if (await this.isEmptyEditorField()) {
322
+ throw new Error("This field is already empty");
323
+ }
324
+ const clearBtnSelector = `${this.editorContainerClass} .${DX_CLEAR_BUTTON_AREA}`;
325
+ const clearBtn = await this._driver.findElement(By4.css(clearBtnSelector));
326
+ await click(clearBtn, this._driver);
327
+ }
328
+ };
329
+
330
+ // src/pageObjects/elements/Editors/SelectBoxEditor.ts
331
+ var SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS = "d5-multi-select-item";
332
+ var combinedValueXpath = (value) => `//body/div[@id="root"]/div[contains(@class, "dx-overlay-wrapper")]//${XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value)}`;
333
+ var dropDownOptionClick = async (optionValue, driver, delay = true) => {
334
+ const { implicit } = await driver.manage().getTimeouts();
335
+ let optElement = null;
336
+ const timeout = delay ? implicit : 200;
337
+ let err = null;
338
+ try {
339
+ await driver.manage().setTimeouts({ implicit: timeout });
340
+ optElement = await driver.findElement(By5.xpath(combinedValueXpath(optionValue)));
341
+ await click(optElement, driver);
342
+ } catch (e) {
343
+ err = new Error(`Item not found: "${optionValue}"`);
344
+ } finally {
345
+ await driver.manage().setTimeouts({ implicit });
346
+ }
347
+ if (err)
348
+ throw err;
349
+ };
350
+ var SelectBoxEditor = class extends AbstractDXEditorWithInput {
351
+ constructor(parentCssSelector, elementCssSelector, driver) {
352
+ super(parentCssSelector, elementCssSelector, driver);
353
+ this.setClearStrategy(new ClearButtonStrategy(this.getFullCssSelector(), this.driver));
354
+ }
355
+ async setSelectInputValue(value) {
356
+ const inputEl = await this.getInputElement();
357
+ await click(inputEl, this.driver);
358
+ try {
359
+ await dropDownOptionClick(value, this.driver, false);
360
+ } catch {
361
+ await inputEl.sendKeys(value, Key2.ENTER);
362
+ await dropDownOptionClick(value, this.driver);
363
+ }
364
+ }
365
+ async getValue() {
366
+ const value = await super.getInputValue();
367
+ return value == "" ? null : value;
368
+ }
369
+ setValue(value) {
370
+ return this.setSelectInputValue(value);
371
+ }
372
+ };
373
+
374
+ // src/pageObjects/elements/Editors/SwitchEditor.ts
375
+ var SwitchEditor = class extends AbstractElementWithParent {
376
+ async getValue() {
377
+ const result = await this.getAttribute("aria-label");
378
+ if (result === "ON")
379
+ return 1;
380
+ if (result === "OFF")
381
+ return 0;
382
+ return null;
383
+ }
384
+ async setValue(value) {
385
+ if (value !== 0 && value !== 1) {
386
+ value = value ? 1 : 0;
387
+ }
388
+ const inputEl = await this.getElement();
389
+ const currentValue = await this.getValue();
390
+ if (currentValue === value) {
391
+ return;
392
+ }
393
+ await click(inputEl, this.driver);
394
+ await wait(async () => {
395
+ const updatedValue = await this.getValue();
396
+ return updatedValue !== currentValue;
397
+ }, this.driver);
398
+ }
399
+ };
400
+
401
+ // src/pageObjects/elements/Editors/TagBox.ts
402
+ import { By as By6 } from "selenium-webdriver";
403
+ var TAGS_SELECTOR = ".dx-tag .tag-text";
404
+ var DX_TAG_CONTAINER = "dx-tag-container";
405
+ var DX_TEXTEDITOR_EMPTY2 = "dx-texteditor-empty";
406
+ var BTN_OK_SELECTOR = ".dx-tagbox-popup-wrapper .dx-popup-bottom .dx-button.dx-popup-done";
407
+ var TAG_BOX_LIST_ITEM_SELECTOR = '.dx-tagbox-popup-wrapper .dx-list-item[aria-selected="true"]';
408
+ var TagBox = class extends AbstractDXEditorWithInput {
409
+ constructor(parentCssSelector, elementCssSelector, driver) {
410
+ super(parentCssSelector, elementCssSelector, driver);
411
+ this.setClearStrategy(new ClearButtonStrategy(this.getFullCssSelector(), this.driver));
412
+ }
413
+ async setTagBoxInputValue(values) {
414
+ const lastElement = values[values.length - 1];
415
+ const inputEl = await this.getInputElement();
416
+ await inputEl.click();
417
+ for (const value of values) {
418
+ await this.selectOption(inputEl, value, lastElement);
419
+ }
420
+ await this.confirmSelection();
421
+ }
422
+ async waitOptionSelection() {
423
+ const option = await this.driver.findElement(By6.css(TAG_BOX_LIST_ITEM_SELECTOR));
424
+ await wait(() => option.isDisplayed(), this.driver);
425
+ }
426
+ async selectOption(inputEl, value, lastElement) {
427
+ try {
428
+ await dropDownOptionClick(value, this.driver, false);
429
+ } catch {
430
+ await inputEl.sendKeys(value);
431
+ await dropDownOptionClick(value, this.driver);
432
+ }
433
+ await this.waitOptionSelection();
434
+ if (value !== lastElement) {
435
+ await inputEl.clear();
436
+ }
437
+ }
438
+ async confirmSelection() {
439
+ const btnOk = await this.driver.findElement(By6.css(BTN_OK_SELECTOR));
440
+ await click(btnOk, this.driver);
441
+ }
442
+ async getTagBoxInputValue() {
443
+ if (await this.isTagBoxEmpty()) {
444
+ return [];
445
+ }
446
+ const tags = await this.driver.findElements(
447
+ By6.css(`${this.getFullCssSelector()} .${DX_TAG_CONTAINER} ${TAGS_SELECTOR}`)
448
+ );
449
+ const values = [];
450
+ for (const tag of tags) {
451
+ values.push(await tag.getAttribute("textContent"));
452
+ }
453
+ return values;
454
+ }
455
+ async isTagBoxEmpty() {
456
+ const classAttribute = await this.getClasses();
457
+ return classAttribute.includes(DX_TEXTEDITOR_EMPTY2);
458
+ }
459
+ async getValue() {
460
+ const value = await this.getTagBoxInputValue();
461
+ return value.length ? value : null;
462
+ }
463
+ async setValue(values) {
464
+ if (!Array.isArray(values)) {
465
+ throw new Error("The provided value is not an array");
466
+ }
467
+ await this.setTagBoxInputValue(values);
468
+ }
469
+ async remove(itemText) {
470
+ const tagValues = await this.getValue();
471
+ const tagExists = tagValues.includes(itemText);
472
+ if (!tagExists) {
473
+ throw new Error(`The tag with the text: ${itemText} was not found`);
474
+ }
475
+ const clearBtnTestId = byTestIdCssSelector(`clear-button-${itemText}`);
476
+ const clearBtn = await this.driver.findElement(
477
+ By6.css(`${this.getFullCssSelector()} .${DX_TAG_CONTAINER} ${clearBtnTestId}`)
478
+ );
479
+ await click(clearBtn, this.driver);
480
+ }
481
+ };
482
+
483
+ // src/pageObjects/elements/Editors/ButtonGroup.ts
484
+ import { By as By7 } from "selenium-webdriver";
485
+ var ITEM_CLASS = "dx-buttongroup-item";
486
+ var SELECTED_CLASS = "dx-state-selected";
487
+ var ButtonGroup = class extends AbstractElementWithParent {
488
+ getItems() {
489
+ return this.driver.findElements(By7.css(`${this.getFullCssSelector()} .${ITEM_CLASS}`));
490
+ }
491
+ getDataValue(el) {
492
+ return el.getAttribute("data-value");
493
+ }
494
+ async getValue() {
495
+ const selectedEl = await this.driver.findElement(By7.css(`${this.getFullCssSelector()} .${ITEM_CLASS}.${SELECTED_CLASS}`));
496
+ return this.getDataValue(selectedEl);
497
+ }
498
+ async setValue(value) {
499
+ const items = await this.getItems();
500
+ let buttonEl = void 0;
501
+ for (const item of items) {
502
+ const text = await this.getDataValue(item);
503
+ if (text == value) {
504
+ buttonEl = item;
505
+ break;
506
+ }
507
+ }
508
+ if (!buttonEl)
509
+ throw new Error(`Cannot find item in button group with text: ${value}`);
510
+ await click(buttonEl, this.driver);
511
+ }
512
+ };
513
+
514
+ // src/pageObjects/elements/Editors/BooleanSelector.ts
515
+ var BooleanSelector = class extends ButtonGroup {
516
+ // @ts-ignore
517
+ async getValue() {
518
+ const value = await super.getValue();
519
+ return value === "null" ? null : value === "1" ? 1 : 0;
520
+ }
521
+ // @ts-ignore
522
+ async setValue(value) {
523
+ const val = value == null ? "null" : value ? "1" : "0";
524
+ await super.setValue(val);
525
+ }
526
+ };
527
+
528
+ // src/pageObjects/elements/Editors/Date/SingleDateEditor.ts
529
+ import { By as By9 } from "selenium-webdriver";
530
+
531
+ // src/pageObjects/elements/Editors/Date/BaseDateEditor.ts
532
+ import { By as By8, Key as Key3 } from "selenium-webdriver";
533
+
534
+ // src/pageObjects/elements/Editors/Date/utils.ts
535
+ var formatDMYDate = (date) => {
536
+ const [year, month, day] = date.toJSON().split("T")[0].split("-");
537
+ return `${day}${month}${year}`;
538
+ };
539
+
540
+ // src/pageObjects/elements/Editors/Date/BaseDateEditor.ts
541
+ var BTN_CALENDAR_POPOVER_OPEN_SELECTOR = "calendar-popover-open-button";
542
+ var BTN_CALENDAR_POPOVER_DATE_FROM_INPUT_SELECTOR = "DateRange__inputs-item--dateFrom";
543
+ var BTN_CALENDAR_POPOVER_DATE_TO_INPUT_SELECTOR = "DateRange__inputs-item--dateTo";
544
+ var BTN_SAVE_SELECTOR = "DateRange__button-save";
545
+ var BaseDateEditor = class extends AbstractDXEditorWithInput {
546
+ constructor(parentCssSelector, elementCssSelector, driver) {
547
+ super(parentCssSelector, elementCssSelector, driver);
548
+ this.setClearStrategy(new InputClearStrategy());
549
+ }
550
+ async setDateValue(value) {
551
+ const actions = this.driver.actions({ async: true });
552
+ const dateField = await this.driver.findElement(By8.css(`${this.getFullCssSelector()}`));
553
+ const dateFieldDataTestID = await this.getDataTestId();
554
+ const calendarPopoverSelector = byTestIdCssSelector(`${dateFieldDataTestID}-calendar-popover`);
555
+ const dateInputEl = await this.getInputElement();
556
+ await dateInputEl.clear();
557
+ if (Array.isArray(value)) {
558
+ const formattedDates = value.map(formatDMYDate);
559
+ const button = await dateField.findElement(By8.css(`.${BTN_CALENDAR_POPOVER_OPEN_SELECTOR}`));
560
+ await button.click();
561
+ const calendarPopoverElement = await this.driver.findElement(By8.css(calendarPopoverSelector));
562
+ const dateFromInput = await calendarPopoverElement.findElement(By8.css(`.${BTN_CALENDAR_POPOVER_DATE_FROM_INPUT_SELECTOR} .dx-texteditor-input`));
563
+ const dateToInput = await calendarPopoverElement.findElement(By8.css(`.${BTN_CALENDAR_POPOVER_DATE_TO_INPUT_SELECTOR} .dx-texteditor-input`));
564
+ await dateFromInput.click();
565
+ await dateFromInput.sendKeys(formattedDates[0]);
566
+ await dateToInput.click();
567
+ await actions.move({ origin: dateInputEl }).sendKeys(Key3.HOME).perform();
568
+ await dateToInput.sendKeys(formattedDates[1]);
569
+ await actions.move({ origin: dateInputEl }).sendKeys(Key3.ENTER).perform();
570
+ const btnOk = await this.driver.findElement(By8.css(`.${BTN_SAVE_SELECTOR}`));
571
+ await btnOk.click();
572
+ } else {
573
+ const formattedDate = formatDMYDate(value);
574
+ await click(dateInputEl, this.driver);
575
+ await actions.move({ origin: dateInputEl }).sendKeys(Key3.HOME).perform();
576
+ await actions.move({ origin: dateInputEl }).sendKeys(formattedDate, Key3.ENTER).perform();
577
+ }
578
+ }
579
+ };
580
+
581
+ // src/pageObjects/elements/Editors/Date/SingleDateEditor.ts
582
+ var SingleDateEditor = class extends BaseDateEditor {
583
+ constructor(parentCssSelector, elementCssSelector, driver) {
584
+ super(parentCssSelector, elementCssSelector, driver);
585
+ this.setClearStrategy(new InputClearStrategy());
586
+ }
587
+ async getDateElement() {
588
+ return this.driver.findElement(By9.css(this.getFullCssSelector() + " .dx-dropdowneditor-input-wrapper input[type=hidden]"));
589
+ }
590
+ async getDateValue() {
591
+ const inputEl = await this.getDateElement();
592
+ return inputEl.getAttribute("value");
593
+ }
594
+ async getValue() {
595
+ const value = await this.getDateValue();
596
+ return value == "" ? null : new Date(value);
597
+ }
598
+ setValue(value) {
599
+ if (typeof value === "object") {
600
+ return this.setDateValue(value);
601
+ }
602
+ throw new Error(`Value is incorrect. It should be Object`);
603
+ }
604
+ };
605
+
606
+ // src/pageObjects/elements/Editors/Date/DateRangeEditor.ts
607
+ import { By as By10 } from "selenium-webdriver";
608
+ var DateRangeEditor = class extends BaseDateEditor {
609
+ constructor(parentCssSelector, elementCssSelector, driver) {
610
+ super(parentCssSelector, elementCssSelector, driver);
611
+ this.setClearStrategy(new InputClearStrategy());
612
+ }
613
+ async getDateElement() {
614
+ return this.driver.findElement(By10.css(this.getFullCssSelector() + " .dx-texteditor-input"));
615
+ }
616
+ async getDateValue() {
617
+ const inputEl = await this.getDateElement();
618
+ const dateFromStr = await inputEl.getAttribute("datefrom");
619
+ const dateToStr = await inputEl.getAttribute("dateto");
620
+ const dateFrom = new Date(dateFromStr);
621
+ const dateTo = new Date(dateToStr);
622
+ return [dateFrom, dateTo];
623
+ }
624
+ async getValue() {
625
+ const values = await this.getDateValue();
626
+ return !values.length ? null : values;
627
+ }
628
+ setValue(value) {
629
+ if (typeof value === "object") {
630
+ return this.setDateValue(value);
631
+ }
632
+ throw new Error(`Value is incorrect. It should be Object`);
633
+ }
634
+ };
635
+
636
+ // src/pageObjects/elements/Editors/Date/DateEditor.ts
637
+ var DateEditor = class extends AbstractDXEditorWithInput {
638
+ editorInstance = null;
639
+ initPromise;
640
+ constructor(parentCssSelector, elementCssSelector, driver) {
641
+ super(parentCssSelector, elementCssSelector, driver);
642
+ this.initPromise = this.init(parentCssSelector, elementCssSelector, driver);
643
+ }
644
+ async init(parentCssSelector, elementCssSelector, driver) {
645
+ await this.updateEditorInstance(parentCssSelector, elementCssSelector, driver);
646
+ }
647
+ async updateEditorInstance(parentCssSelector, elementCssSelector, driver) {
648
+ const elementInstance = new AbstractFormElement(parentCssSelector, elementCssSelector, driver);
649
+ const classString = await elementInstance.getClasses();
650
+ switch (true) {
651
+ case classString.includes("date-control" /* Date */):
652
+ this.editorInstance = new SingleDateEditor(parentCssSelector, elementCssSelector, driver);
653
+ break;
654
+ case classString.includes("single-date-range-control" /* SingleDateRange */):
655
+ this.editorInstance = new DateRangeEditor(parentCssSelector, elementCssSelector, driver);
656
+ break;
657
+ default:
658
+ this.editorInstance = new SingleDateEditor(parentCssSelector, elementCssSelector, driver);
659
+ }
660
+ }
661
+ async ensureInitialized() {
662
+ if (!this.editorInstance) {
663
+ await this.initPromise;
664
+ }
665
+ }
666
+ async setValue(value) {
667
+ await this.ensureInitialized();
668
+ if (this.editorInstance) {
669
+ await this.editorInstance.setValue(value);
670
+ return await this.updateEditorInstance(this.parentCssSelector, this.elementCssSelector, this.driver);
671
+ }
672
+ throw new Error("Editor instance is not initialized.");
673
+ }
674
+ async getValue() {
675
+ await this.ensureInitialized();
676
+ if (this.editorInstance) {
677
+ return this.editorInstance.getValue();
678
+ }
679
+ throw new Error("Editor instance is not initialized.");
680
+ }
681
+ };
682
+
683
+ // src/pageObjects/elements/Editors/editorFactory.ts
684
+ var editorFactory = async (parentCssSelector, elementCssSelector, driver) => {
685
+ const elementInstance = new AbstractFormElement(parentCssSelector, elementCssSelector, driver);
686
+ const classSting = await elementInstance.getClasses();
687
+ if ((classSting.includes("text-control" /* Text */) || classSting.includes("text-area-control" /* TextArea */)) && !classSting.includes("single-date-range-control" /* SingleDateRange */))
688
+ return new TextEditor(parentCssSelector, elementCssSelector, driver);
689
+ if (classSting.includes("number-control" /* Number */))
690
+ return new NumberEditor(parentCssSelector, elementCssSelector, driver);
691
+ if (classSting.includes("check-box" /* CheckBox */))
692
+ return new CheckBox(parentCssSelector, elementCssSelector, driver);
693
+ if (classSting.includes("multi-select-control" /* Multiselect */))
694
+ return new TagBox(parentCssSelector, elementCssSelector, driver);
695
+ if (classSting.includes("select-control" /* Select */))
696
+ return new SelectBoxEditor(parentCssSelector, elementCssSelector, driver);
697
+ if (classSting.includes("switch-control" /* Switch */))
698
+ return new SwitchEditor(parentCssSelector, elementCssSelector, driver);
699
+ if (classSting.includes("date-control" /* Date */) || classSting.includes("single-date-range-control" /* SingleDateRange */)) {
700
+ return new DateEditor(parentCssSelector, elementCssSelector, driver);
701
+ }
702
+ if (classSting.includes("buttons-group" /* BooleanSelector */))
703
+ return new BooleanSelector(parentCssSelector, elementCssSelector, driver);
704
+ if (classSting.includes("button-group-field" /* ButtonGroup */))
705
+ return new ButtonGroup(parentCssSelector, elementCssSelector, driver);
706
+ throw new Error("Unknown type of editor. Please write ticket to the support");
707
+ };
708
+
709
+ // src/utils/createDataTestId.ts
710
+ function createDataTestId(formName, itemType, itemName) {
711
+ return `${formName}-${itemType}-${itemName}`;
712
+ }
713
+ function createFieldTestId(formName, itemName) {
714
+ return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
715
+ }
716
+ function createGroupTestId(formName, itemName) {
717
+ return createDataTestId(formName, "group" /* GROUP */, itemName);
718
+ }
719
+ function createFilterTestId(formName, itemName, layout) {
720
+ return createDataTestId(formName, "filter" /* FILTER */, itemName) + `-${layout}`;
721
+ }
722
+ function createDocFilterTestId(formName, itemName) {
723
+ return createFilterTestId(formName, itemName, "dock-panel-filter" /* DOCK_PANEL */);
724
+ }
725
+ function createLayoutFilterTestId(formName, itemName) {
726
+ return createFilterTestId(formName, itemName, "layout-filter" /* LAYOUT */);
727
+ }
728
+ function createTableId(formName) {
729
+ return `${"table" /* TABLE */}-${formName}`;
730
+ }
731
+ function createFormButtonTestId(formName, itemName) {
732
+ return createDataTestId(formName, "button" /* BUTTON */, itemName);
733
+ }
734
+
735
+ // src/pageObjects/elements/AbstractEditor.ts
736
+ var AbstractEditor = class extends AbstractElementWithParent {
737
+ editor;
738
+ constructor(parentCssSelector, elementCssSelector, driver) {
739
+ super(parentCssSelector, elementCssSelector, driver);
740
+ }
741
+ async initEditor() {
742
+ if (!this.editor) {
743
+ this.editor = await editorFactory(this.parentCssSelector, this.elementCssSelector, this.driver);
744
+ }
745
+ }
746
+ /**
747
+ * Возвращает значение в поле
748
+ * @example
749
+ * expect(await formEdit.field('NumberFld').getValue()).toBe(10);
750
+ * expect(await formEdit.field('TextFld').getValue()).toBe('TestValue');
751
+ */
752
+ async getValue() {
753
+ await this.initEditor();
754
+ return this.editor.getValue();
755
+ }
756
+ /**
757
+ * Устанавливает значение в поле
758
+ * @example
759
+ * await formEdit.field('NumberFld').setValue(123);
760
+ * await formEdit.field('TextFld').setValue('TestValue');
761
+ */
762
+ async setValue(value) {
763
+ await this.initEditor();
764
+ return this.editor.setValue(value);
765
+ }
766
+ /**
767
+ * Очищает значение в поле
768
+ * @example
769
+ * await formEdit.field('NumberFld').clear();
770
+ */
771
+ async clear() {
772
+ await this.initEditor();
773
+ if (!this.editor.clear) {
774
+ throw new Error("The clear method is not available for this field type.");
775
+ }
776
+ return this.editor.clear();
777
+ }
778
+ /**
779
+ * Удаляет тег по переданному тексту
780
+ * @example
781
+ * await formEdit.field('TagBox').remove('test');
782
+ */
783
+ async remove(itemText) {
784
+ await this.initEditor();
785
+ if (!this.editor.remove) {
786
+ throw new Error("This method is only available for the TagBox field.");
787
+ }
788
+ return this.editor.remove(itemText);
789
+ }
790
+ /**
791
+ * Возвращает значение true|false в зависимости readOnly поле или нет
792
+ * @example
793
+ * expect(await formEdit.field('NumberFld').isReadonly()).toBe(true);
794
+ * expect(await formEdit.field('TextFld').isReadonly()).toBe(false);
795
+ */
796
+ async isReadonly() {
797
+ await this.initEditor();
798
+ return this.editor.isReadonly();
799
+ }
800
+ };
801
+
802
+ // src/pageObjects/elements/FormField.ts
803
+ var FormField = class extends AbstractEditor {
804
+ constructor(parentCssSelector, formName, name, driver) {
805
+ super(parentCssSelector, byTestIdCssSelector(createFieldTestId(formName, name)), driver);
806
+ }
807
+ };
808
+
809
+ // src/pageObjects/elements/Forms/Form.ts
810
+ import { By as By13 } from "selenium-webdriver";
811
+
812
+ // src/utils/waitElementIsClickable.ts
813
+ async function waitElementIsClickable({
814
+ element,
815
+ timeout,
816
+ errorMessage,
817
+ driver
818
+ }) {
819
+ driver = driver ?? config().driver;
820
+ await wait(async () => {
821
+ const isDisabled = await element.getCssValue("pointer-events") === "none";
822
+ return await element.isDisplayed() && !isDisabled;
823
+ }, driver, errorMessage, timeout ?? config().timeout);
824
+ }
825
+
826
+ // src/pageObjects/elements/TableToolbar/AbstractButton.ts
827
+ var AbstractButton = class extends AbstractElementWithParent {
828
+ constructor(parentCssSelector, elementCssSelector, driver) {
829
+ super(parentCssSelector, elementCssSelector, driver);
830
+ }
831
+ async click() {
832
+ const button = await this.getElement();
833
+ await waitElementIsClickable({
834
+ element: button,
835
+ errorMessage: this.buttonNotDisplayedError(),
836
+ driver: this.driver
837
+ });
838
+ await click(button, this.driver);
839
+ }
840
+ async isDisabled() {
841
+ const button = await this.getElement();
842
+ return await button.getCssValue("pointer-events") === "none";
843
+ }
844
+ };
845
+
846
+ // src/pageObjects/elements/DXComponents/DXButton.ts
847
+ import { By as By11 } from "selenium-webdriver";
848
+ var DXButton = class extends AbstractButton {
849
+ async getText() {
850
+ const classes = await this.getClasses();
851
+ if (!classes.includes("dx-button-has-text")) {
852
+ return null;
853
+ }
854
+ const el = await this.getElement();
855
+ const textEl = el.findElement(By11.className("dx-button-text"));
856
+ return await textEl.getText();
857
+ }
858
+ };
859
+
860
+ // src/pageObjects/elements/FormButton.ts
861
+ var FormButton = class extends DXButton {
862
+ name;
863
+ constructor(parentCssSelector, formName, name, driver) {
864
+ super(parentCssSelector, byTestIdCssSelector(createFormButtonTestId(formName, name)), driver);
865
+ this.name = name;
866
+ }
867
+ buttonNotDisplayedError() {
868
+ return `Form Button ${this.name} cannot be clicked. It is not displayed or it is disabled`;
869
+ }
870
+ };
871
+
872
+ // src/pageObjects/elements/Groups/AbstractGroup.ts
873
+ var AbstractGroup = class extends AbstractElementWithParent {
874
+ async isDisplayed() {
875
+ const groupElement = await this.getElement();
876
+ return await groupElement.isDisplayed();
877
+ }
878
+ };
879
+
880
+ // src/pageObjects/elements/Groups/Panel.ts
881
+ var Panel = class extends AbstractGroup {
882
+ };
883
+
884
+ // src/pageObjects/elements/Groups/TabPanel/TabPanel.ts
885
+ import { By as By12 } from "selenium-webdriver";
886
+ var getTabTestIdByName = (name) => `tab-caption-${name}`;
887
+ var TabPanel = class extends AbstractGroup {
888
+ constructor(parentCssSelector, elementCssSelector, driver) {
889
+ super(parentCssSelector, elementCssSelector, driver);
890
+ }
891
+ _getTab(name) {
892
+ return this.driver.findElement(By12.css(`${this.getFullCssSelector()} ${byTestIdCssSelector(getTabTestIdByName(name))}`));
893
+ }
894
+ async tabClick(name) {
895
+ const tabEl = this._getTab(name);
896
+ await tabEl.click();
897
+ }
898
+ };
899
+
900
+ // src/pageObjects/elements/Groups/groupFactory.ts
901
+ var groupFactory = async (parentCssSelector, elementCssSelector, driver) => {
902
+ const elementInstance = new AbstractFormElement(parentCssSelector, elementCssSelector, driver);
903
+ const classSting = await elementInstance.getClasses();
904
+ if (classSting.includes("tab-panel-group"))
905
+ return new TabPanel(parentCssSelector, elementCssSelector, driver);
906
+ if (classSting.includes("panel-group"))
907
+ return new Panel(parentCssSelector, elementCssSelector, driver);
908
+ throw new Error("Unknown type of group. Please write ticket to the support");
909
+ };
910
+
911
+ // src/pageObjects/elements/FormGroup.ts
912
+ var FormGroup = class extends AbstractElementWithParent {
913
+ editor;
914
+ constructor(parentCssSelector, formName, name, driver) {
915
+ super(parentCssSelector, byTestIdCssSelector(createGroupTestId(formName, name)), driver);
916
+ }
917
+ async initEditor() {
918
+ if (!this.editor) {
919
+ this.editor = await groupFactory(this.parentCssSelector, this.elementCssSelector, this.driver);
920
+ }
921
+ }
922
+ /**
923
+ * Возвращает булевое значение доступна ли группа
924
+ * @example
925
+ * expect(await tableList.group('MainSuperPanel').isDisplayed();
926
+ */
927
+ async isDisplayed() {
928
+ try {
929
+ await this.initEditor();
930
+ return this.editor.isDisplayed();
931
+ } catch {
932
+ return false;
933
+ }
934
+ }
935
+ /**
936
+ * Происходит клик по табе
937
+ * @example
938
+ * expect(await tableList.group('TabPanel').tabClick(tabName);
939
+ */
940
+ async tabClick(name) {
941
+ await this.initEditor();
942
+ await this.editor.tabClick(name);
943
+ }
944
+ };
945
+
946
+ // src/pageObjects/elements/Forms/AbstractForm.ts
947
+ var AbstractForm = class extends AbstractPage {
948
+ containerCssSelector = "";
949
+ _formName = "";
950
+ containerBy;
951
+ getContainerElement = () => {
952
+ return this.driver.findElement(this.containerBy);
953
+ };
954
+ set formName(name) {
955
+ this._formName = name;
956
+ }
957
+ get formName() {
958
+ return this._formName;
959
+ }
960
+ /**
961
+ * Возвращает true если форма есть в DOM
962
+ * @example
963
+ * class MyForm extends FormEdit {}
964
+ * //...
965
+ * const formEdit = new MyForm();
966
+ * expect(await formEdit.exists()).toBe(true);
967
+ */
968
+ async exists() {
969
+ try {
970
+ let elements = await this.driver.findElements(this.containerBy);
971
+ return elements.length > 0;
972
+ } catch (error) {
973
+ return false;
974
+ }
975
+ }
976
+ button(name) {
977
+ return new FormButton(this.containerCssSelector, this.formName, name, this.driver);
978
+ }
979
+ /**
980
+ * Находит группу на форме по имени
981
+ * @example
982
+ * const formEdit = new MyForm();
983
+ * //...
984
+ * expect(await formEdit.group('Name');
985
+ */
986
+ group(name) {
987
+ return new FormGroup(this.containerCssSelector, this.formName, name, this.driver);
988
+ }
989
+ };
990
+
991
+ // src/pageObjects/elements/Forms/createSubFormInstance.ts
992
+ var subFormTestId = (name) => `subform-${name}`;
993
+ function subformCssSelector(parentCssSelector, testId) {
994
+ return `${parentCssSelector} ${byTestIdCssSelector(testId)}`;
995
+ }
996
+ async function classDependencyInjector(formType) {
997
+ let SubFormFactoryClass;
998
+ switch (formType) {
999
+ case "1" /* LIST */:
1000
+ SubFormFactoryClass = (await import("./ListForm-HDVXB6CG.mjs")).default;
1001
+ break;
1002
+ case "3" /* TREE */:
1003
+ SubFormFactoryClass = (await import("./TreeView-DE5RBMDD.mjs")).default;
1004
+ break;
1005
+ case "2" /* EDIT */:
1006
+ case "99" /* FREE_FORM */:
1007
+ case "4" /* REPORT */:
1008
+ SubFormFactoryClass = (await import("./FormEdit-MZJH5R5H.mjs")).default;
1009
+ break;
1010
+ default:
1011
+ throw new Error(`Unsupported form type ${formType}`);
1012
+ }
1013
+ return SubFormFactoryClass;
1014
+ }
1015
+
1016
+ // src/pageObjects/elements/Forms/Form.ts
1017
+ var formTestId = (formName) => `form-content-wrapper-${formName}`;
1018
+ var Form = class extends AbstractForm {
1019
+ popupContainerCssSelector;
1020
+ constructor(driver) {
1021
+ super(driver);
1022
+ this.setSubFormMode();
1023
+ }
1024
+ async isModal() {
1025
+ const el = await this.getContainerElement();
1026
+ const value = await el.getAttribute("data-ismodal");
1027
+ return value === "true";
1028
+ }
1029
+ /**
1030
+ * Получение заголовка на формы
1031
+ * @example
1032
+ * const listForm = new MyForm();
1033
+ * //...
1034
+ * expect(await listForm.getTitleText()).toBe('MyFormTitle');
1035
+ */
1036
+ async getTitleText() {
1037
+ if (await this.isModal()) {
1038
+ const titleEl2 = await this.driver.findElement(By13.css(`${this.popupContainerCssSelector} .popup-title`));
1039
+ return titleEl2.getText();
1040
+ }
1041
+ let titleEl = await this.driver.findElement(By13.className("main-toolbar-form-title"));
1042
+ return titleEl.getText();
1043
+ }
1044
+ setSubFormMode() {
1045
+ const testId = formTestId(this.formName);
1046
+ this.containerBy = byTestId(testId);
1047
+ this.containerCssSelector = byTestIdCssSelector(testId);
1048
+ }
1049
+ /**
1050
+ * Возвращает сабформу
1051
+ * @returns {Promise<ListForm | TreeView | FormEdit>}
1052
+ * @example
1053
+ * const form = new MyForm();
1054
+ * //...
1055
+ * expect(await form.subForm(name));
1056
+ */
1057
+ async subForm(name) {
1058
+ const cssSelector = subformCssSelector(this.containerCssSelector, subFormTestId(name));
1059
+ const byCssSelector = By13.css(cssSelector);
1060
+ const subFormEl = await this.driver.findElement(byCssSelector);
1061
+ await waitElementIsVisible({
1062
+ element: subFormEl,
1063
+ driver: this.driver,
1064
+ errorMessage: `Subform "${name}" is not visible`
1065
+ });
1066
+ const formType = await subFormEl.getAttribute("data-formtype");
1067
+ const formName = await subFormEl.getAttribute("data-formname");
1068
+ let SubFormFactoryClass = await classDependencyInjector(formType);
1069
+ const SubForm = class extends SubFormFactoryClass {
1070
+ setSubFormMode() {
1071
+ this.containerCssSelector = cssSelector;
1072
+ this.containerBy = byCssSelector;
1073
+ }
1074
+ get formName() {
1075
+ return formName;
1076
+ }
1077
+ };
1078
+ return new SubForm(this.driver);
1079
+ }
1080
+ };
1081
+
1082
+ export {
1083
+ config,
1084
+ fixElementStaleError,
1085
+ AbstractElement,
1086
+ AbstractPage,
1087
+ wait,
1088
+ waitElementIsVisible,
1089
+ click,
1090
+ byTestIdCssSelector,
1091
+ byTestId,
1092
+ readonlyLocator,
1093
+ AbstractElementWithParent,
1094
+ createDocFilterTestId,
1095
+ createLayoutFilterTestId,
1096
+ createTableId,
1097
+ waitElementIsClickable,
1098
+ AbstractButton,
1099
+ TextEditor,
1100
+ NumberEditor,
1101
+ ControlClass,
1102
+ editorFactory,
1103
+ AbstractEditor,
1104
+ FormField,
1105
+ Form
1106
+ };