d5-testing-library 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/d5-testing-library.cjs +446 -66
- package/dist/d5-testing-library.d.ts +97 -11
- package/dist/d5-testing-library.legacy-esm.js +443 -64
- package/dist/d5-testing-library.mjs +443 -64
- package/package.json +1 -1
|
@@ -78,7 +78,7 @@ var AbstractPage = class extends AbstractElement {
|
|
|
78
78
|
// src/utils/locators.ts
|
|
79
79
|
import { By } from "selenium-webdriver";
|
|
80
80
|
var byTestId = (testId, element = "div") => {
|
|
81
|
-
return By.css(`${element}[data-testid
|
|
81
|
+
return By.css(`${element}[data-testid="${testId}"]`);
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
// src/utils/createDriver.ts
|
|
@@ -102,6 +102,11 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
|
|
|
102
102
|
|
|
103
103
|
// src/utils/waitElementIsVisible.ts
|
|
104
104
|
import { until } from "selenium-webdriver";
|
|
105
|
+
async function waitElementIsVisible({ element, timeout, errorMessage, driver }) {
|
|
106
|
+
driver = driver ?? config().driver;
|
|
107
|
+
const condition = until.elementIsVisible(element);
|
|
108
|
+
await driver.wait(condition.fn, timeout ?? 1e4, errorMessage ?? condition.description());
|
|
109
|
+
}
|
|
105
110
|
|
|
106
111
|
// src/pageObjects/AbstractElementWithParent.ts
|
|
107
112
|
var AbstractElementWithParent = class extends AbstractElement {
|
|
@@ -113,7 +118,23 @@ var AbstractElementWithParent = class extends AbstractElement {
|
|
|
113
118
|
}
|
|
114
119
|
async getElement() {
|
|
115
120
|
const parentEl = await this.getParentElement();
|
|
116
|
-
|
|
121
|
+
await waitElementIsVisible({
|
|
122
|
+
element: parentEl,
|
|
123
|
+
driver: this.driver
|
|
124
|
+
});
|
|
125
|
+
const el = await parentEl.findElement(this.elementBy);
|
|
126
|
+
await waitElementIsVisible({
|
|
127
|
+
element: el,
|
|
128
|
+
driver: this.driver
|
|
129
|
+
});
|
|
130
|
+
return el;
|
|
131
|
+
}
|
|
132
|
+
async getAttribute(attr) {
|
|
133
|
+
const el = await this.getElement();
|
|
134
|
+
return await el.getAttribute(attr);
|
|
135
|
+
}
|
|
136
|
+
async getClasses() {
|
|
137
|
+
return await this.getAttribute("class");
|
|
117
138
|
}
|
|
118
139
|
};
|
|
119
140
|
|
|
@@ -199,7 +220,7 @@ var AbstractForm = class extends AbstractPage {
|
|
|
199
220
|
};
|
|
200
221
|
|
|
201
222
|
// src/pageObjects/elements/Forms/FormEdit.ts
|
|
202
|
-
import { By as
|
|
223
|
+
import { By as By11 } from "selenium-webdriver";
|
|
203
224
|
|
|
204
225
|
// src/pageObjects/elements/Editors/AbstractEditor.ts
|
|
205
226
|
import { By as By5, Key } from "selenium-webdriver";
|
|
@@ -212,8 +233,20 @@ var AbstractFormElement = class extends AbstractElementWithParent {
|
|
|
212
233
|
}
|
|
213
234
|
};
|
|
214
235
|
|
|
236
|
+
// src/pageObjects/elements/Editors/ClearStrategy/InputClearStrategy.ts
|
|
237
|
+
var InputClearStrategy = class {
|
|
238
|
+
async clear(editor) {
|
|
239
|
+
const inputEl = await editor.getInputElement();
|
|
240
|
+
await inputEl.clear();
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
215
244
|
// src/pageObjects/elements/Editors/AbstractEditor.ts
|
|
216
245
|
var AbstractDXEditorWithInput = class extends AbstractFormElement {
|
|
246
|
+
clearStrategy = new InputClearStrategy();
|
|
247
|
+
setClearStrategy(strategy) {
|
|
248
|
+
this.clearStrategy = strategy;
|
|
249
|
+
}
|
|
217
250
|
async getInputElement() {
|
|
218
251
|
const controlEl = await this.getElement();
|
|
219
252
|
return controlEl.findElement(By5.className("dx-texteditor-input"));
|
|
@@ -227,10 +260,17 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
|
|
|
227
260
|
await click(inputEl, this.driver);
|
|
228
261
|
await inputEl.sendKeys(value, Key.ENTER);
|
|
229
262
|
}
|
|
263
|
+
async clear() {
|
|
264
|
+
await this.clearStrategy.clear(this);
|
|
265
|
+
}
|
|
230
266
|
};
|
|
231
267
|
|
|
232
268
|
// src/pageObjects/elements/Editors/TextEditor.ts
|
|
233
269
|
var TextEditor = class extends AbstractDXEditorWithInput {
|
|
270
|
+
constructor(getParentElement, elementBy, driver) {
|
|
271
|
+
super(getParentElement, elementBy, driver);
|
|
272
|
+
this.setClearStrategy(new InputClearStrategy());
|
|
273
|
+
}
|
|
234
274
|
getValue() {
|
|
235
275
|
return this.getInputValue();
|
|
236
276
|
}
|
|
@@ -241,6 +281,10 @@ var TextEditor = class extends AbstractDXEditorWithInput {
|
|
|
241
281
|
|
|
242
282
|
// src/pageObjects/elements/Editors/NumberEditor.ts
|
|
243
283
|
var NumberEditor = class extends AbstractDXEditorWithInput {
|
|
284
|
+
constructor(getParentElement, elementBy, driver) {
|
|
285
|
+
super(getParentElement, elementBy, driver);
|
|
286
|
+
this.setClearStrategy(new InputClearStrategy());
|
|
287
|
+
}
|
|
244
288
|
async getValue() {
|
|
245
289
|
const value = await super.getInputValue();
|
|
246
290
|
return value == "" ? null : Number.parseFloat(value);
|
|
@@ -256,10 +300,10 @@ var CheckBox = class extends AbstractFormElement {
|
|
|
256
300
|
const inputEl = await this.getElement();
|
|
257
301
|
const result = await inputEl.getAttribute("aria-checked");
|
|
258
302
|
if (result === "true")
|
|
259
|
-
return
|
|
303
|
+
return 1;
|
|
260
304
|
if (result === "false")
|
|
261
|
-
return
|
|
262
|
-
return
|
|
305
|
+
return 0;
|
|
306
|
+
return null;
|
|
263
307
|
}
|
|
264
308
|
async setValue(value) {
|
|
265
309
|
const inputEl = await this.getElement();
|
|
@@ -271,7 +315,7 @@ var CheckBox = class extends AbstractFormElement {
|
|
|
271
315
|
};
|
|
272
316
|
|
|
273
317
|
// src/pageObjects/elements/Editors/SelectBoxEditor.ts
|
|
274
|
-
import { By as
|
|
318
|
+
import { By as By7, Key as Key2 } from "selenium-webdriver";
|
|
275
319
|
|
|
276
320
|
// src/utils/xpathHelper.ts
|
|
277
321
|
var XPathHelper = class {
|
|
@@ -283,18 +327,52 @@ var XPathHelper = class {
|
|
|
283
327
|
}
|
|
284
328
|
};
|
|
285
329
|
|
|
330
|
+
// src/pageObjects/elements/Editors/ClearStrategy/ClearButtonStrategy.ts
|
|
331
|
+
import { By as By6 } from "selenium-webdriver";
|
|
332
|
+
var DX_TEXTEDITOR_EMPTY = "dx-texteditor-empty";
|
|
333
|
+
var DX_CLEAR_BUTTON_AREA = "dx-clear-button-area";
|
|
334
|
+
var ClearButtonStrategy = class {
|
|
335
|
+
editorContainerClass;
|
|
336
|
+
constructor(editorContainerClass) {
|
|
337
|
+
this.editorContainerClass = editorContainerClass;
|
|
338
|
+
}
|
|
339
|
+
async isEmptyEditorField(editor) {
|
|
340
|
+
const parentEl = await editor.getParentElement();
|
|
341
|
+
const editorContainer = await parentEl.findElement(By6.className(this.editorContainerClass));
|
|
342
|
+
const classAttribute = await editorContainer.getAttribute("class");
|
|
343
|
+
return classAttribute.includes(DX_TEXTEDITOR_EMPTY);
|
|
344
|
+
}
|
|
345
|
+
async clear(editor) {
|
|
346
|
+
if (await this.isEmptyEditorField(editor)) {
|
|
347
|
+
throw new Error("This field is already empty");
|
|
348
|
+
}
|
|
349
|
+
const clearBtnSelector = `.${this.editorContainerClass} .${DX_CLEAR_BUTTON_AREA}`;
|
|
350
|
+
const parentEl = await editor.getParentElement();
|
|
351
|
+
const clearBtn = await parentEl.findElement(By6.css(clearBtnSelector));
|
|
352
|
+
await click(clearBtn, editor.driver);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
286
356
|
// src/pageObjects/elements/Editors/SelectBoxEditor.ts
|
|
287
357
|
var SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS = "d5-multi-select-item";
|
|
288
358
|
var SELECT_BOX_ELEMENT_ROLE = "option";
|
|
359
|
+
var combinedValueXpath = (value) => `${XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)}${XPathHelper.getClassAndValueXpath(
|
|
360
|
+
SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS,
|
|
361
|
+
value
|
|
362
|
+
)}`;
|
|
363
|
+
var DX_SELECTBOX = "dx-selectbox";
|
|
289
364
|
var SelectBoxEditor = class extends AbstractDXEditorWithInput {
|
|
365
|
+
constructor(getParentElement, elementBy, driver) {
|
|
366
|
+
super(getParentElement, elementBy, driver);
|
|
367
|
+
this.setClearStrategy(new ClearButtonStrategy(DX_SELECTBOX));
|
|
368
|
+
}
|
|
290
369
|
async setSelectInputValue(value) {
|
|
291
370
|
const inputEl = await this.getInputElement();
|
|
292
371
|
await click(inputEl, this.driver);
|
|
293
372
|
await inputEl.sendKeys(value, Key2.ENTER);
|
|
294
|
-
const combinedValueXpath = XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE) + XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value);
|
|
295
373
|
await this.driver.wait(async () => {
|
|
296
374
|
try {
|
|
297
|
-
const optElement = await inputEl.findElement(
|
|
375
|
+
const optElement = await inputEl.findElement(By7.xpath(combinedValueXpath(value)));
|
|
298
376
|
await click(optElement, this.driver);
|
|
299
377
|
return true;
|
|
300
378
|
} catch (e) {
|
|
@@ -320,7 +398,7 @@ var SwitchEditor = class extends AbstractFormElement {
|
|
|
320
398
|
return 1;
|
|
321
399
|
if (result === "OFF")
|
|
322
400
|
return 0;
|
|
323
|
-
return
|
|
401
|
+
return null;
|
|
324
402
|
}
|
|
325
403
|
async setValue(value) {
|
|
326
404
|
if (value !== 0 && value !== 1) {
|
|
@@ -338,21 +416,205 @@ var SwitchEditor = class extends AbstractFormElement {
|
|
|
338
416
|
}
|
|
339
417
|
};
|
|
340
418
|
|
|
419
|
+
// src/pageObjects/elements/Editors/TagBox.ts
|
|
420
|
+
import { By as By8 } from "selenium-webdriver";
|
|
421
|
+
var TAGS_SELECTOR = ".dx-tag .tag-text";
|
|
422
|
+
var DX_TAG_CONTAINER = "dx-tag-container";
|
|
423
|
+
var DX_TAGBOX = "dx-tagbox";
|
|
424
|
+
var DX_TEXTEDITOR_EMPTY2 = "dx-texteditor-empty";
|
|
425
|
+
var BTN_OK_SELECTOR = ".dx-tagbox-popup-wrapper .dx-popup-bottom .dx-button.dx-popup-done";
|
|
426
|
+
var TagBox = class extends AbstractDXEditorWithInput {
|
|
427
|
+
constructor(getParentElement, elementBy, driver) {
|
|
428
|
+
super(getParentElement, elementBy, driver);
|
|
429
|
+
this.setClearStrategy(new ClearButtonStrategy(DX_TAGBOX));
|
|
430
|
+
}
|
|
431
|
+
async setTagBoxInputValue(values) {
|
|
432
|
+
const lastElement = values[values.length - 1];
|
|
433
|
+
const inputEl = await this.getInputElement();
|
|
434
|
+
await inputEl.click();
|
|
435
|
+
for (const value of values) {
|
|
436
|
+
await this.selectOption(inputEl, value, lastElement);
|
|
437
|
+
}
|
|
438
|
+
await this.confirmSelection();
|
|
439
|
+
}
|
|
440
|
+
async selectOption(inputEl, value, lastElement) {
|
|
441
|
+
await inputEl.sendKeys(value);
|
|
442
|
+
await this.driver.wait(async () => {
|
|
443
|
+
try {
|
|
444
|
+
const optElement = await inputEl.findElement(By8.xpath(combinedValueXpath(value)));
|
|
445
|
+
await click(optElement, this.driver);
|
|
446
|
+
return true;
|
|
447
|
+
} catch (e) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
if (value !== lastElement) {
|
|
452
|
+
await inputEl.clear();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async confirmSelection() {
|
|
456
|
+
const inputEl = await this.getInputElement();
|
|
457
|
+
const option = await inputEl.findElement(By8.xpath(XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)));
|
|
458
|
+
const btnOk = await this.driver.findElement(By8.css(BTN_OK_SELECTOR));
|
|
459
|
+
await this.driver.wait(async () => {
|
|
460
|
+
return await option.getAttribute("aria-selected") === "true";
|
|
461
|
+
});
|
|
462
|
+
await click(btnOk, this.driver);
|
|
463
|
+
}
|
|
464
|
+
async getTagBoxInputValue() {
|
|
465
|
+
if (await this.isTagBoxEmpty()) {
|
|
466
|
+
return [];
|
|
467
|
+
}
|
|
468
|
+
const parentEl = await this.getParentElement();
|
|
469
|
+
const inputEl = await parentEl.findElement(By8.className(DX_TAG_CONTAINER));
|
|
470
|
+
const tags = await inputEl.findElements(By8.css(TAGS_SELECTOR));
|
|
471
|
+
const values = [];
|
|
472
|
+
for (const tag of tags) {
|
|
473
|
+
const text = await tag.getText();
|
|
474
|
+
values.push(text);
|
|
475
|
+
}
|
|
476
|
+
return values;
|
|
477
|
+
}
|
|
478
|
+
async isTagBoxEmpty() {
|
|
479
|
+
const parentEl = await this.getParentElement();
|
|
480
|
+
const tagboxContainer = await parentEl.findElement(By8.className(DX_TAGBOX));
|
|
481
|
+
const classAttribute = await tagboxContainer.getAttribute("class");
|
|
482
|
+
return classAttribute.includes(DX_TEXTEDITOR_EMPTY2);
|
|
483
|
+
}
|
|
484
|
+
async getValue() {
|
|
485
|
+
const value = await this.getTagBoxInputValue();
|
|
486
|
+
return value.length ? value : null;
|
|
487
|
+
}
|
|
488
|
+
async setValue(values) {
|
|
489
|
+
if (!Array.isArray(values)) {
|
|
490
|
+
throw new Error("The provided value is not an array");
|
|
491
|
+
}
|
|
492
|
+
await this.setTagBoxInputValue(values);
|
|
493
|
+
}
|
|
494
|
+
async remove(itemText) {
|
|
495
|
+
const tagValues = await this.getValue();
|
|
496
|
+
const tagExists = tagValues.includes(itemText);
|
|
497
|
+
if (!tagExists) {
|
|
498
|
+
throw new Error(`The tag with the text: ${itemText} was not found`);
|
|
499
|
+
}
|
|
500
|
+
const parentEl = await this.getParentElement();
|
|
501
|
+
const inputEl = await parentEl.findElement(By8.className(DX_TAG_CONTAINER));
|
|
502
|
+
const clearBtnTestId = byTestId(`clear-button-${itemText}`);
|
|
503
|
+
const clearBtn = await inputEl.findElement(clearBtnTestId);
|
|
504
|
+
await click(clearBtn, this.driver);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
// src/pageObjects/elements/Editors/ButtonGroup.ts
|
|
509
|
+
import { By as By9 } from "selenium-webdriver";
|
|
510
|
+
var ITEM_CLASS = "dx-buttongroup-item";
|
|
511
|
+
var SELECTED_CLASS = "dx-state-selected";
|
|
512
|
+
var ButtonGroup = class extends AbstractFormElement {
|
|
513
|
+
async getItems() {
|
|
514
|
+
return (await this.getElement()).findElements(By9.className(ITEM_CLASS));
|
|
515
|
+
}
|
|
516
|
+
getDataValue(el) {
|
|
517
|
+
return el.getAttribute("data-value");
|
|
518
|
+
}
|
|
519
|
+
async getValue() {
|
|
520
|
+
const inputEl = await this.getElement();
|
|
521
|
+
const selectedEl = await inputEl.findElement(By9.className(`${ITEM_CLASS} ${SELECTED_CLASS}`));
|
|
522
|
+
return this.getDataValue(selectedEl);
|
|
523
|
+
}
|
|
524
|
+
async setValue(value) {
|
|
525
|
+
const items = await this.getItems();
|
|
526
|
+
let buttonEl = void 0;
|
|
527
|
+
for (const item of items) {
|
|
528
|
+
const text = await this.getDataValue(item);
|
|
529
|
+
if (text == value) {
|
|
530
|
+
buttonEl = item;
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (!buttonEl)
|
|
535
|
+
throw new Error(`Cannot find item in button group with text: ${value}`);
|
|
536
|
+
await click(buttonEl, this.driver);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
// src/pageObjects/elements/Editors/BooleanSelector.ts
|
|
541
|
+
var BooleanSelector = class extends ButtonGroup {
|
|
542
|
+
// @ts-ignore
|
|
543
|
+
async getValue() {
|
|
544
|
+
const value = await super.getValue();
|
|
545
|
+
return value === "null" ? null : value === "1" ? 1 : 0;
|
|
546
|
+
}
|
|
547
|
+
// @ts-ignore
|
|
548
|
+
async setValue(value) {
|
|
549
|
+
const val = value == null ? "null" : value ? "1" : "0";
|
|
550
|
+
await super.setValue(val);
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
// src/pageObjects/elements/Editors/DateEditor.ts
|
|
555
|
+
import { By as By10, Key as Key3 } from "selenium-webdriver";
|
|
556
|
+
var DateEditor = class extends AbstractDXEditorWithInput {
|
|
557
|
+
constructor(getParentElement, elementBy, driver) {
|
|
558
|
+
super(getParentElement, elementBy, driver);
|
|
559
|
+
this.setClearStrategy(new InputClearStrategy());
|
|
560
|
+
}
|
|
561
|
+
async getControlElement() {
|
|
562
|
+
const controlEl = await this.getElement();
|
|
563
|
+
return controlEl.findElement(By10.className("dx-dropdowneditor-input-wrapper"));
|
|
564
|
+
}
|
|
565
|
+
async getDateElement() {
|
|
566
|
+
const controlEl = await this.getControlElement();
|
|
567
|
+
return controlEl.findElement(By10.css("input[type=hidden]"));
|
|
568
|
+
}
|
|
569
|
+
async setDateValue(value) {
|
|
570
|
+
const dateEl = await this.getInputElement();
|
|
571
|
+
const stringDate = value.toJSON().split("T")[0];
|
|
572
|
+
const dateArr = stringDate.split("-");
|
|
573
|
+
const [year, month, day] = dateArr;
|
|
574
|
+
const keys = day + month + year;
|
|
575
|
+
await click(dateEl, this.driver);
|
|
576
|
+
const actions = this.driver.actions({ async: true });
|
|
577
|
+
await actions.move({ origin: dateEl }).sendKeys(Key3.HOME).perform();
|
|
578
|
+
await actions.move({ origin: dateEl }).sendKeys(keys, Key3.ENTER).perform();
|
|
579
|
+
}
|
|
580
|
+
async getDateValue() {
|
|
581
|
+
const inputEl = await this.getDateElement();
|
|
582
|
+
return inputEl.getAttribute("value");
|
|
583
|
+
}
|
|
584
|
+
async getValue() {
|
|
585
|
+
const value = await this.getDateValue();
|
|
586
|
+
return value == "" ? null : new Date(value);
|
|
587
|
+
}
|
|
588
|
+
setValue(value) {
|
|
589
|
+
if (typeof value === "object") {
|
|
590
|
+
return this.setDateValue(value);
|
|
591
|
+
}
|
|
592
|
+
throw new Error(`Value is incorrect. It should be Object`);
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
|
|
341
596
|
// src/pageObjects/elements/Editors/editorFactory.ts
|
|
342
597
|
var editorFactory = async (getParentElement, elementBy, driver) => {
|
|
343
598
|
const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
|
|
344
|
-
const
|
|
345
|
-
const classSting = await element.getAttribute("class");
|
|
599
|
+
const classSting = await elementInstance.getClasses();
|
|
346
600
|
if (classSting.includes("text-control"))
|
|
347
601
|
return new TextEditor(getParentElement, elementBy, driver);
|
|
348
602
|
if (classSting.includes("number-control"))
|
|
349
603
|
return new NumberEditor(getParentElement, elementBy, driver);
|
|
350
604
|
if (classSting.includes("check-box"))
|
|
351
605
|
return new CheckBox(getParentElement, elementBy, driver);
|
|
606
|
+
if (classSting.includes("multi-select-control"))
|
|
607
|
+
return new TagBox(getParentElement, elementBy, driver);
|
|
352
608
|
if (classSting.includes("select-control"))
|
|
353
609
|
return new SelectBoxEditor(getParentElement, elementBy, driver);
|
|
354
610
|
if (classSting.includes("switch-control"))
|
|
355
611
|
return new SwitchEditor(getParentElement, elementBy, driver);
|
|
612
|
+
if (classSting.includes("date-control"))
|
|
613
|
+
return new DateEditor(getParentElement, elementBy, driver);
|
|
614
|
+
if (classSting.includes("buttons-group"))
|
|
615
|
+
return new BooleanSelector(getParentElement, elementBy, driver);
|
|
616
|
+
if (classSting.includes("button-group-field"))
|
|
617
|
+
return new ButtonGroup(getParentElement, elementBy, driver);
|
|
356
618
|
throw new Error("Unknown type of editor. Please write ticket to the support");
|
|
357
619
|
};
|
|
358
620
|
|
|
@@ -363,6 +625,9 @@ function createDataTestId(formName, itemType, itemName) {
|
|
|
363
625
|
function createFieldTestId(formName, itemName) {
|
|
364
626
|
return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
|
|
365
627
|
}
|
|
628
|
+
function createGroupTestId(formName, itemName) {
|
|
629
|
+
return createDataTestId(formName, "group" /* GROUP */, itemName);
|
|
630
|
+
}
|
|
366
631
|
function createTableId(formName) {
|
|
367
632
|
return `${"table" /* TABLE */}-${formName}`;
|
|
368
633
|
}
|
|
@@ -399,14 +664,82 @@ var FormField = class extends AbstractElementWithParent {
|
|
|
399
664
|
await this.initEditor();
|
|
400
665
|
return this.editor.setValue(value);
|
|
401
666
|
}
|
|
667
|
+
/**
|
|
668
|
+
* Очищает значение в поле
|
|
669
|
+
* @example
|
|
670
|
+
* await formEdit.field('NumberFld').clear();
|
|
671
|
+
*/
|
|
672
|
+
async clear() {
|
|
673
|
+
await this.initEditor();
|
|
674
|
+
if (!this.editor.clear) {
|
|
675
|
+
throw new Error("The clear method is not available for this field type.");
|
|
676
|
+
}
|
|
677
|
+
return this.editor.clear();
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Удаляет тег по переданному тексту
|
|
681
|
+
* @example
|
|
682
|
+
* await formEdit.field('TagBox').remove('test');
|
|
683
|
+
*/
|
|
684
|
+
async remove(itemText) {
|
|
685
|
+
await this.initEditor();
|
|
686
|
+
if (!this.editor.remove) {
|
|
687
|
+
throw new Error("This method is only available for the TagBox field.");
|
|
688
|
+
}
|
|
689
|
+
return this.editor.remove(itemText);
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
// src/pageObjects/elements/Groups/AbstractGroup.ts
|
|
694
|
+
var AbstractDXGroup = class extends AbstractFormElement {
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
// src/pageObjects/elements/Groups/Panel.ts
|
|
698
|
+
var Panel = class extends AbstractDXGroup {
|
|
699
|
+
async isDisplayed() {
|
|
700
|
+
const groupElement = await this.getElement();
|
|
701
|
+
return await groupElement.isDisplayed();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
// src/pageObjects/elements/Groups/groupFactory.ts
|
|
706
|
+
var groupFactory = async (getParentElement, elementBy, driver) => {
|
|
707
|
+
const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
|
|
708
|
+
const classSting = await elementInstance.getClasses();
|
|
709
|
+
if (classSting.includes("panel-group"))
|
|
710
|
+
return new Panel(getParentElement, elementBy, driver);
|
|
711
|
+
throw new Error("Unknown type of group. Please write ticket to the support");
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
// src/pageObjects/elements/FormGroup.ts
|
|
715
|
+
var FormGroup = class extends AbstractElementWithParent {
|
|
716
|
+
editor;
|
|
717
|
+
constructor(getParentElement, formName, name, driver) {
|
|
718
|
+
super(getParentElement, driver);
|
|
719
|
+
this.elementBy = byTestId(createGroupTestId(formName, name));
|
|
720
|
+
}
|
|
721
|
+
async initEditor() {
|
|
722
|
+
if (!this.editor) {
|
|
723
|
+
this.editor = await groupFactory(this.getParentElement, this.elementBy, this.driver);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Возвращает булевое значение доступна ли группа
|
|
728
|
+
* @example
|
|
729
|
+
* expect(await tableList.group('MainSuperPanel').isDisplayed();
|
|
730
|
+
*/
|
|
731
|
+
async isDisplayed() {
|
|
732
|
+
await this.initEditor();
|
|
733
|
+
return this.editor.isDisplayed();
|
|
734
|
+
}
|
|
402
735
|
};
|
|
403
736
|
|
|
404
737
|
// src/pageObjects/elements/Forms/FormEdit.ts
|
|
405
738
|
var FormEdit = class extends AbstractForm {
|
|
406
|
-
saveButtonBy =
|
|
739
|
+
saveButtonBy = By11.id("button-save");
|
|
407
740
|
constructor(driver) {
|
|
408
741
|
super(driver);
|
|
409
|
-
this.popupContainerBy =
|
|
742
|
+
this.popupContainerBy = By11.className(`popup form-edit-${this.formName}`);
|
|
410
743
|
}
|
|
411
744
|
/**
|
|
412
745
|
* Находит поле формы редактирования по имени
|
|
@@ -418,6 +751,28 @@ var FormEdit = class extends AbstractForm {
|
|
|
418
751
|
field(name) {
|
|
419
752
|
return new FormField(this.getContainerElement, this.formName, name, this.driver);
|
|
420
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* Проверяет не отключена ли кнопка Сохранить
|
|
756
|
+
* @example
|
|
757
|
+
* const formEdit = new MyForm();
|
|
758
|
+
* //...
|
|
759
|
+
* await formEdit.isSaveButtonDisabled();
|
|
760
|
+
*/
|
|
761
|
+
async isSaveButtonDisabled() {
|
|
762
|
+
const saveButton = await this.driver.findElement(this.saveButtonBy);
|
|
763
|
+
const result = await saveButton.getAttribute("aria-disabled");
|
|
764
|
+
return result === "true";
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Находит группу формы редактирования по имени
|
|
768
|
+
* @example
|
|
769
|
+
* const formEdit = new MyForm();
|
|
770
|
+
* //...
|
|
771
|
+
* expect(await formEdit.group('Name');
|
|
772
|
+
*/
|
|
773
|
+
group(name) {
|
|
774
|
+
return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
|
|
775
|
+
}
|
|
421
776
|
/**
|
|
422
777
|
* Нажатие на кнопку Сохранить
|
|
423
778
|
* @example
|
|
@@ -426,35 +781,36 @@ var FormEdit = class extends AbstractForm {
|
|
|
426
781
|
* await formEdit.saveButtonClick();
|
|
427
782
|
*/
|
|
428
783
|
async saveButtonClick() {
|
|
429
|
-
|
|
784
|
+
const saveButton = await this.driver.findElement(this.saveButtonBy);
|
|
785
|
+
await this.driver.wait(async () => !await this.isSaveButtonDisabled(), void 0, "Button is disabled");
|
|
786
|
+
await click(saveButton, this.driver);
|
|
430
787
|
}
|
|
431
788
|
};
|
|
432
789
|
|
|
433
790
|
// src/pageObjects/elements/Forms/ListForm.ts
|
|
434
|
-
import { By as
|
|
791
|
+
import { By as By17 } from "selenium-webdriver";
|
|
435
792
|
|
|
436
793
|
// src/pageObjects/elements/Table/Table.ts
|
|
437
|
-
import { By as
|
|
794
|
+
import { By as By14 } from "selenium-webdriver";
|
|
438
795
|
|
|
439
796
|
// src/pageObjects/elements/Table/utils.ts
|
|
440
|
-
import { By as
|
|
797
|
+
import { By as By12 } from "selenium-webdriver";
|
|
441
798
|
var getRowPathByIndex = (index) => {
|
|
442
|
-
return
|
|
799
|
+
return By12.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
|
|
443
800
|
};
|
|
801
|
+
var getColumnByIndexCssSelector = (columnIndex) => `td[aria-colindex="${transformInputIndex(columnIndex)}"]`;
|
|
444
802
|
var getColumnPathByIndex = (index) => {
|
|
445
|
-
return
|
|
446
|
-
};
|
|
447
|
-
var getColumnPathByCaption = (caption) => {
|
|
448
|
-
return By8.css(`td[role="columnheader"][aria-label="Column ${caption}"]`);
|
|
803
|
+
return By12.css(getColumnByIndexCssSelector(index));
|
|
449
804
|
};
|
|
805
|
+
var getColumnByCaptionCssSelector = (caption) => `td[role="columnheader"][aria-label="Column ${caption}"]`;
|
|
450
806
|
var getCellPathByIndex = (index) => {
|
|
451
|
-
return
|
|
807
|
+
return By12.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
|
|
452
808
|
};
|
|
453
809
|
var transformInputIndex = (index) => index + 1;
|
|
454
810
|
var transformOutputIndex = (index) => +index - 1;
|
|
455
811
|
|
|
456
812
|
// src/pageObjects/elements/Table/elements/Row.ts
|
|
457
|
-
import { By as
|
|
813
|
+
import { By as By13 } from "selenium-webdriver";
|
|
458
814
|
|
|
459
815
|
// src/pageObjects/elements/Table/elements/Cell.ts
|
|
460
816
|
var Cell = class extends AbstractElementWithParent {
|
|
@@ -476,6 +832,7 @@ var Cell = class extends AbstractElementWithParent {
|
|
|
476
832
|
// src/pageObjects/elements/Table/elements/Row.ts
|
|
477
833
|
var DX_SELECTION_CLASS = "dx-selection";
|
|
478
834
|
var DX_ROW_EDIT_CLASS = "dx-edit-row";
|
|
835
|
+
var DX_DATA_ROW_CLASS = "dx-data-row";
|
|
479
836
|
var Row = class extends AbstractElementWithParent {
|
|
480
837
|
index;
|
|
481
838
|
getColumnByCaption;
|
|
@@ -506,10 +863,8 @@ var Row = class extends AbstractElementWithParent {
|
|
|
506
863
|
await click(rowEl, this.driver);
|
|
507
864
|
await this.driver.wait(async () => {
|
|
508
865
|
const classes = await rowEl.getAttribute("class");
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
return true;
|
|
512
|
-
}, 500);
|
|
866
|
+
return classes.includes(DX_SELECTION_CLASS);
|
|
867
|
+
}, 500, "Cannot select row");
|
|
513
868
|
}
|
|
514
869
|
async isSelected() {
|
|
515
870
|
const rowEl = await this.getElement();
|
|
@@ -521,7 +876,7 @@ var Row = class extends AbstractElementWithParent {
|
|
|
521
876
|
}
|
|
522
877
|
async getCells() {
|
|
523
878
|
const rowEl = await this.getElement();
|
|
524
|
-
const cells = await rowEl.findElements(
|
|
879
|
+
const cells = await rowEl.findElements(By13.css(`td[role="gridcell"]`));
|
|
525
880
|
const result = [];
|
|
526
881
|
cells.forEach((_, index) => {
|
|
527
882
|
const newCell = new Cell(rowEl, index, this.driver);
|
|
@@ -529,26 +884,30 @@ var Row = class extends AbstractElementWithParent {
|
|
|
529
884
|
});
|
|
530
885
|
return result;
|
|
531
886
|
}
|
|
532
|
-
async clickInlineButton(
|
|
533
|
-
const
|
|
534
|
-
|
|
887
|
+
async clickInlineButton(buttonClass) {
|
|
888
|
+
const FIXED_TABLE_CSS_SELECTOR = ".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed";
|
|
889
|
+
const buttonCssSelector = `.${DX_DATA_ROW_CLASS}[aria-rowindex="${transformInputIndex(this.index)}"] .${buttonClass}`;
|
|
890
|
+
const button = (await this.getParentElement()).findElement(
|
|
891
|
+
By13.css(`${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`)
|
|
535
892
|
);
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
893
|
+
return click(button, this.driver);
|
|
894
|
+
}
|
|
895
|
+
async checkEditingMode(isEditing, msg) {
|
|
896
|
+
await this.driver.wait(async () => {
|
|
897
|
+
return (await this.getClasses()).includes(DX_ROW_EDIT_CLASS) === isEditing;
|
|
898
|
+
}, 2e3, msg);
|
|
542
899
|
}
|
|
543
900
|
async edit() {
|
|
544
|
-
await this.
|
|
545
|
-
|
|
901
|
+
await this.clickInlineButton("edit");
|
|
902
|
+
await this.checkEditingMode(true, "Row did not switch to edit mode");
|
|
546
903
|
}
|
|
547
904
|
async save() {
|
|
548
|
-
|
|
905
|
+
await this.clickInlineButton("save");
|
|
906
|
+
await this.checkEditingMode(false, "Row did not saved");
|
|
549
907
|
}
|
|
550
908
|
async cancel() {
|
|
551
|
-
|
|
909
|
+
await this.clickInlineButton("cancel");
|
|
910
|
+
await this.checkEditingMode(false, "Row did not switch to normal mode");
|
|
552
911
|
}
|
|
553
912
|
};
|
|
554
913
|
|
|
@@ -574,19 +933,18 @@ var Table = class extends AbstractElementWithParent {
|
|
|
574
933
|
formName;
|
|
575
934
|
constructor(getParentElement, formName, driver) {
|
|
576
935
|
super(getParentElement, driver);
|
|
577
|
-
this.elementBy =
|
|
936
|
+
this.elementBy = By14.id(createTableId(formName));
|
|
578
937
|
this.formName = formName;
|
|
579
938
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
return parentEl.findElement(By10.className("dx-header-row"));
|
|
939
|
+
getHeaderCssSelector() {
|
|
940
|
+
return ".dx-datagrid-headers .dx-datagrid-content:not(.dx-datagrid-content-fixed)";
|
|
583
941
|
}
|
|
584
942
|
async getDataGrid() {
|
|
585
943
|
const parentEl = await this.getElement();
|
|
586
|
-
return parentEl.findElement(
|
|
944
|
+
return parentEl.findElement(By14.css(`div[role="grid"]`));
|
|
587
945
|
}
|
|
588
946
|
getTableElement = () => {
|
|
589
|
-
return this.
|
|
947
|
+
return this.getElement();
|
|
590
948
|
};
|
|
591
949
|
async getRowByIndex(index) {
|
|
592
950
|
const gridContainer = await this.getDataGrid();
|
|
@@ -597,16 +955,14 @@ var Table = class extends AbstractElementWithParent {
|
|
|
597
955
|
throw new Error(`Cannot find row by index: ${index}`);
|
|
598
956
|
}
|
|
599
957
|
async getColumnByIndex(index) {
|
|
600
|
-
const
|
|
601
|
-
const column = await headerContainer.findElement(getColumnPathByIndex(index));
|
|
958
|
+
const column = await (await this.getElement()).findElement(By14.css(`${this.getHeaderCssSelector()} ${getColumnByIndexCssSelector(index)}`));
|
|
602
959
|
if (column) {
|
|
603
960
|
return new Column(this.getTableElement, index, this.driver);
|
|
604
961
|
}
|
|
605
962
|
throw new Error(`Cannot find column by index: ${index}`);
|
|
606
963
|
}
|
|
607
964
|
async getColumnByCaption(caption) {
|
|
608
|
-
const
|
|
609
|
-
const column = await headerContainer.findElement(getColumnPathByCaption(caption));
|
|
965
|
+
const column = await (await this.getElement()).findElement(By14.css(`${this.getHeaderCssSelector()} ${getColumnByCaptionCssSelector(caption)}`));
|
|
610
966
|
if (column) {
|
|
611
967
|
const index = await column.getAttribute("aria-colindex");
|
|
612
968
|
return new Column(this.getTableElement, transformOutputIndex(index), this.driver);
|
|
@@ -623,7 +979,7 @@ var Table = class extends AbstractElementWithParent {
|
|
|
623
979
|
}
|
|
624
980
|
async getRows() {
|
|
625
981
|
const gridContainer = await this.getDataGrid();
|
|
626
|
-
const rows = await gridContainer.findElements(
|
|
982
|
+
const rows = await gridContainer.findElements(By14.className("dx-row dx-data-row"));
|
|
627
983
|
const result = [];
|
|
628
984
|
rows.forEach((_, index) => {
|
|
629
985
|
const newRow = new Row(this.getTableElement, index, this.driver, this.getColumnByCaption.bind(this));
|
|
@@ -632,8 +988,7 @@ var Table = class extends AbstractElementWithParent {
|
|
|
632
988
|
return result;
|
|
633
989
|
}
|
|
634
990
|
async getColumns() {
|
|
635
|
-
const
|
|
636
|
-
const columns = await headerContainer.findElements(By10.css(`td[role="columnheader"]`));
|
|
991
|
+
const columns = await (await this.getElement()).findElements(By14.css(`${this.getHeaderCssSelector()} td[role="columnheader"]`));
|
|
637
992
|
const result = [];
|
|
638
993
|
columns.forEach((_, index) => {
|
|
639
994
|
const newCol = new Column(this.getTableElement, index, this.driver);
|
|
@@ -652,23 +1007,28 @@ var Table = class extends AbstractElementWithParent {
|
|
|
652
1007
|
* expect(await form.field('Name').getValue()).toBe('test value');
|
|
653
1008
|
*/
|
|
654
1009
|
field(name) {
|
|
655
|
-
return new FormField(this.
|
|
1010
|
+
return new FormField(this.getTableElement, this.formName, name, this.driver);
|
|
656
1011
|
}
|
|
657
1012
|
};
|
|
658
1013
|
|
|
659
1014
|
// src/pageObjects/elements/TableToolbar/TableToolbar.ts
|
|
660
|
-
import { By as
|
|
1015
|
+
import { By as By16 } from "selenium-webdriver";
|
|
661
1016
|
|
|
662
1017
|
// src/pageObjects/elements/TableToolbar/TableToolbarButton.ts
|
|
663
|
-
import { By as
|
|
1018
|
+
import { By as By15 } from "selenium-webdriver";
|
|
664
1019
|
var TOOLBAR_BUTTON_CLASS = "toolbar-button";
|
|
665
1020
|
var TableToolbarButton = class extends AbstractElementWithParent {
|
|
1021
|
+
name;
|
|
666
1022
|
constructor(getParentElement, name, driver) {
|
|
667
1023
|
super(getParentElement, driver);
|
|
668
|
-
this.
|
|
1024
|
+
this.name = name;
|
|
1025
|
+
this.elementBy = By15.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
|
|
669
1026
|
}
|
|
670
1027
|
async click() {
|
|
671
1028
|
const button = await this.getElement();
|
|
1029
|
+
await this.driver.wait(async () => {
|
|
1030
|
+
return await button.isDisplayed() && !await this.isDisabled();
|
|
1031
|
+
}, 1e3, `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`);
|
|
672
1032
|
return click(button, this.driver);
|
|
673
1033
|
}
|
|
674
1034
|
async isDisabled() {
|
|
@@ -683,14 +1043,14 @@ var TABLE_TOOLBAR_CLASS = "d5-table-toolbar";
|
|
|
683
1043
|
var TableToolbar = class extends AbstractElementWithParent {
|
|
684
1044
|
constructor(getParentElement, formName, driver) {
|
|
685
1045
|
super(getParentElement, driver);
|
|
686
|
-
this.elementBy =
|
|
1046
|
+
this.elementBy = By16.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
|
|
687
1047
|
}
|
|
688
1048
|
getTableToolbarElement = () => {
|
|
689
1049
|
return this.driver.findElement(this.elementBy);
|
|
690
1050
|
};
|
|
691
1051
|
async button(name) {
|
|
692
1052
|
const toolbar = await this.getTableToolbarElement();
|
|
693
|
-
const button = await toolbar.findElement(
|
|
1053
|
+
const button = await toolbar.findElement(By16.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
|
|
694
1054
|
if (button) {
|
|
695
1055
|
return new TableToolbarButton(this.getTableToolbarElement, name, this.driver);
|
|
696
1056
|
}
|
|
@@ -702,7 +1062,7 @@ var TableToolbar = class extends AbstractElementWithParent {
|
|
|
702
1062
|
var ListForm = class extends AbstractForm {
|
|
703
1063
|
constructor(driver) {
|
|
704
1064
|
super(driver);
|
|
705
|
-
this.popupContainerBy =
|
|
1065
|
+
this.popupContainerBy = By17.className(`popup form-inline-${this.formName}`);
|
|
706
1066
|
}
|
|
707
1067
|
/**
|
|
708
1068
|
* Находит таблицу
|
|
@@ -714,6 +1074,16 @@ var ListForm = class extends AbstractForm {
|
|
|
714
1074
|
table() {
|
|
715
1075
|
return new Table(this.getContainerElement, this.formName, this.driver);
|
|
716
1076
|
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Находит группу на лист форме по имени
|
|
1079
|
+
* @example
|
|
1080
|
+
* const formEdit = new MyForm();
|
|
1081
|
+
* //...
|
|
1082
|
+
* expect(await formEdit.group('Name');
|
|
1083
|
+
*/
|
|
1084
|
+
group(name) {
|
|
1085
|
+
return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
|
|
1086
|
+
}
|
|
717
1087
|
/**
|
|
718
1088
|
* Находит таблицу
|
|
719
1089
|
* @example
|
|
@@ -750,6 +1120,14 @@ var LoginPage = class extends AbstractPage {
|
|
|
750
1120
|
usernameField = byTestId("loginField", "input");
|
|
751
1121
|
passwordField = byTestId("passwordField", "input");
|
|
752
1122
|
loginButton = byTestId("loginButton");
|
|
1123
|
+
async locate() {
|
|
1124
|
+
await super.locate();
|
|
1125
|
+
const login = await this.driver.findElement(this.usernameField);
|
|
1126
|
+
await waitElementIsVisible({
|
|
1127
|
+
element: login,
|
|
1128
|
+
driver: this.driver
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
753
1131
|
get path() {
|
|
754
1132
|
return LOGIN_PATH;
|
|
755
1133
|
}
|
|
@@ -786,5 +1164,6 @@ export {
|
|
|
786
1164
|
createDriver,
|
|
787
1165
|
editorFactory,
|
|
788
1166
|
elementIsNotPresent,
|
|
789
|
-
signIn
|
|
1167
|
+
signIn,
|
|
1168
|
+
waitElementIsVisible
|
|
790
1169
|
};
|