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
|
@@ -44,7 +44,8 @@ __export(src_exports, {
|
|
|
44
44
|
createDriver: () => createDriver,
|
|
45
45
|
editorFactory: () => editorFactory,
|
|
46
46
|
elementIsNotPresent: () => elementIsNotPresent,
|
|
47
|
-
signIn: () => signIn
|
|
47
|
+
signIn: () => signIn,
|
|
48
|
+
waitElementIsVisible: () => waitElementIsVisible
|
|
48
49
|
});
|
|
49
50
|
module.exports = __toCommonJS(src_exports);
|
|
50
51
|
|
|
@@ -128,7 +129,7 @@ var AbstractPage = class extends AbstractElement {
|
|
|
128
129
|
// src/utils/locators.ts
|
|
129
130
|
var import_selenium_webdriver = require("selenium-webdriver");
|
|
130
131
|
var byTestId = (testId, element = "div") => {
|
|
131
|
-
return import_selenium_webdriver.By.css(`${element}[data-testid
|
|
132
|
+
return import_selenium_webdriver.By.css(`${element}[data-testid="${testId}"]`);
|
|
132
133
|
};
|
|
133
134
|
|
|
134
135
|
// src/utils/createDriver.ts
|
|
@@ -152,6 +153,11 @@ var elementIsNotPresent = function elementIsNotPresent2(locator) {
|
|
|
152
153
|
|
|
153
154
|
// src/utils/waitElementIsVisible.ts
|
|
154
155
|
var import_selenium_webdriver4 = require("selenium-webdriver");
|
|
156
|
+
async function waitElementIsVisible({ element, timeout, errorMessage, driver }) {
|
|
157
|
+
driver = driver ?? config().driver;
|
|
158
|
+
const condition = import_selenium_webdriver4.until.elementIsVisible(element);
|
|
159
|
+
await driver.wait(condition.fn, timeout ?? 1e4, errorMessage ?? condition.description());
|
|
160
|
+
}
|
|
155
161
|
|
|
156
162
|
// src/pageObjects/AbstractElementWithParent.ts
|
|
157
163
|
var AbstractElementWithParent = class extends AbstractElement {
|
|
@@ -163,7 +169,23 @@ var AbstractElementWithParent = class extends AbstractElement {
|
|
|
163
169
|
}
|
|
164
170
|
async getElement() {
|
|
165
171
|
const parentEl = await this.getParentElement();
|
|
166
|
-
|
|
172
|
+
await waitElementIsVisible({
|
|
173
|
+
element: parentEl,
|
|
174
|
+
driver: this.driver
|
|
175
|
+
});
|
|
176
|
+
const el = await parentEl.findElement(this.elementBy);
|
|
177
|
+
await waitElementIsVisible({
|
|
178
|
+
element: el,
|
|
179
|
+
driver: this.driver
|
|
180
|
+
});
|
|
181
|
+
return el;
|
|
182
|
+
}
|
|
183
|
+
async getAttribute(attr) {
|
|
184
|
+
const el = await this.getElement();
|
|
185
|
+
return await el.getAttribute(attr);
|
|
186
|
+
}
|
|
187
|
+
async getClasses() {
|
|
188
|
+
return await this.getAttribute("class");
|
|
167
189
|
}
|
|
168
190
|
};
|
|
169
191
|
|
|
@@ -249,7 +271,7 @@ var AbstractForm = class extends AbstractPage {
|
|
|
249
271
|
};
|
|
250
272
|
|
|
251
273
|
// src/pageObjects/elements/Forms/FormEdit.ts
|
|
252
|
-
var
|
|
274
|
+
var import_selenium_webdriver13 = require("selenium-webdriver");
|
|
253
275
|
|
|
254
276
|
// src/pageObjects/elements/Editors/AbstractEditor.ts
|
|
255
277
|
var import_selenium_webdriver7 = require("selenium-webdriver");
|
|
@@ -262,8 +284,20 @@ var AbstractFormElement = class extends AbstractElementWithParent {
|
|
|
262
284
|
}
|
|
263
285
|
};
|
|
264
286
|
|
|
287
|
+
// src/pageObjects/elements/Editors/ClearStrategy/InputClearStrategy.ts
|
|
288
|
+
var InputClearStrategy = class {
|
|
289
|
+
async clear(editor) {
|
|
290
|
+
const inputEl = await editor.getInputElement();
|
|
291
|
+
await inputEl.clear();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
265
295
|
// src/pageObjects/elements/Editors/AbstractEditor.ts
|
|
266
296
|
var AbstractDXEditorWithInput = class extends AbstractFormElement {
|
|
297
|
+
clearStrategy = new InputClearStrategy();
|
|
298
|
+
setClearStrategy(strategy) {
|
|
299
|
+
this.clearStrategy = strategy;
|
|
300
|
+
}
|
|
267
301
|
async getInputElement() {
|
|
268
302
|
const controlEl = await this.getElement();
|
|
269
303
|
return controlEl.findElement(import_selenium_webdriver7.By.className("dx-texteditor-input"));
|
|
@@ -277,10 +311,17 @@ var AbstractDXEditorWithInput = class extends AbstractFormElement {
|
|
|
277
311
|
await click(inputEl, this.driver);
|
|
278
312
|
await inputEl.sendKeys(value, import_selenium_webdriver7.Key.ENTER);
|
|
279
313
|
}
|
|
314
|
+
async clear() {
|
|
315
|
+
await this.clearStrategy.clear(this);
|
|
316
|
+
}
|
|
280
317
|
};
|
|
281
318
|
|
|
282
319
|
// src/pageObjects/elements/Editors/TextEditor.ts
|
|
283
320
|
var TextEditor = class extends AbstractDXEditorWithInput {
|
|
321
|
+
constructor(getParentElement, elementBy, driver) {
|
|
322
|
+
super(getParentElement, elementBy, driver);
|
|
323
|
+
this.setClearStrategy(new InputClearStrategy());
|
|
324
|
+
}
|
|
284
325
|
getValue() {
|
|
285
326
|
return this.getInputValue();
|
|
286
327
|
}
|
|
@@ -291,6 +332,10 @@ var TextEditor = class extends AbstractDXEditorWithInput {
|
|
|
291
332
|
|
|
292
333
|
// src/pageObjects/elements/Editors/NumberEditor.ts
|
|
293
334
|
var NumberEditor = class extends AbstractDXEditorWithInput {
|
|
335
|
+
constructor(getParentElement, elementBy, driver) {
|
|
336
|
+
super(getParentElement, elementBy, driver);
|
|
337
|
+
this.setClearStrategy(new InputClearStrategy());
|
|
338
|
+
}
|
|
294
339
|
async getValue() {
|
|
295
340
|
const value = await super.getInputValue();
|
|
296
341
|
return value == "" ? null : Number.parseFloat(value);
|
|
@@ -306,10 +351,10 @@ var CheckBox = class extends AbstractFormElement {
|
|
|
306
351
|
const inputEl = await this.getElement();
|
|
307
352
|
const result = await inputEl.getAttribute("aria-checked");
|
|
308
353
|
if (result === "true")
|
|
309
|
-
return
|
|
354
|
+
return 1;
|
|
310
355
|
if (result === "false")
|
|
311
|
-
return
|
|
312
|
-
return
|
|
356
|
+
return 0;
|
|
357
|
+
return null;
|
|
313
358
|
}
|
|
314
359
|
async setValue(value) {
|
|
315
360
|
const inputEl = await this.getElement();
|
|
@@ -321,7 +366,7 @@ var CheckBox = class extends AbstractFormElement {
|
|
|
321
366
|
};
|
|
322
367
|
|
|
323
368
|
// src/pageObjects/elements/Editors/SelectBoxEditor.ts
|
|
324
|
-
var
|
|
369
|
+
var import_selenium_webdriver9 = require("selenium-webdriver");
|
|
325
370
|
|
|
326
371
|
// src/utils/xpathHelper.ts
|
|
327
372
|
var XPathHelper = class {
|
|
@@ -333,18 +378,52 @@ var XPathHelper = class {
|
|
|
333
378
|
}
|
|
334
379
|
};
|
|
335
380
|
|
|
381
|
+
// src/pageObjects/elements/Editors/ClearStrategy/ClearButtonStrategy.ts
|
|
382
|
+
var import_selenium_webdriver8 = require("selenium-webdriver");
|
|
383
|
+
var DX_TEXTEDITOR_EMPTY = "dx-texteditor-empty";
|
|
384
|
+
var DX_CLEAR_BUTTON_AREA = "dx-clear-button-area";
|
|
385
|
+
var ClearButtonStrategy = class {
|
|
386
|
+
editorContainerClass;
|
|
387
|
+
constructor(editorContainerClass) {
|
|
388
|
+
this.editorContainerClass = editorContainerClass;
|
|
389
|
+
}
|
|
390
|
+
async isEmptyEditorField(editor) {
|
|
391
|
+
const parentEl = await editor.getParentElement();
|
|
392
|
+
const editorContainer = await parentEl.findElement(import_selenium_webdriver8.By.className(this.editorContainerClass));
|
|
393
|
+
const classAttribute = await editorContainer.getAttribute("class");
|
|
394
|
+
return classAttribute.includes(DX_TEXTEDITOR_EMPTY);
|
|
395
|
+
}
|
|
396
|
+
async clear(editor) {
|
|
397
|
+
if (await this.isEmptyEditorField(editor)) {
|
|
398
|
+
throw new Error("This field is already empty");
|
|
399
|
+
}
|
|
400
|
+
const clearBtnSelector = `.${this.editorContainerClass} .${DX_CLEAR_BUTTON_AREA}`;
|
|
401
|
+
const parentEl = await editor.getParentElement();
|
|
402
|
+
const clearBtn = await parentEl.findElement(import_selenium_webdriver8.By.css(clearBtnSelector));
|
|
403
|
+
await click(clearBtn, editor.driver);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
336
407
|
// src/pageObjects/elements/Editors/SelectBoxEditor.ts
|
|
337
408
|
var SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS = "d5-multi-select-item";
|
|
338
409
|
var SELECT_BOX_ELEMENT_ROLE = "option";
|
|
410
|
+
var combinedValueXpath = (value) => `${XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)}${XPathHelper.getClassAndValueXpath(
|
|
411
|
+
SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS,
|
|
412
|
+
value
|
|
413
|
+
)}`;
|
|
414
|
+
var DX_SELECTBOX = "dx-selectbox";
|
|
339
415
|
var SelectBoxEditor = class extends AbstractDXEditorWithInput {
|
|
416
|
+
constructor(getParentElement, elementBy, driver) {
|
|
417
|
+
super(getParentElement, elementBy, driver);
|
|
418
|
+
this.setClearStrategy(new ClearButtonStrategy(DX_SELECTBOX));
|
|
419
|
+
}
|
|
340
420
|
async setSelectInputValue(value) {
|
|
341
421
|
const inputEl = await this.getInputElement();
|
|
342
422
|
await click(inputEl, this.driver);
|
|
343
|
-
await inputEl.sendKeys(value,
|
|
344
|
-
const combinedValueXpath = XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE) + XPathHelper.getClassAndValueXpath(SELECT_BOX_OPTION_TEXT_CONTAINER_CLASS, value);
|
|
423
|
+
await inputEl.sendKeys(value, import_selenium_webdriver9.Key.ENTER);
|
|
345
424
|
await this.driver.wait(async () => {
|
|
346
425
|
try {
|
|
347
|
-
const optElement = await inputEl.findElement(
|
|
426
|
+
const optElement = await inputEl.findElement(import_selenium_webdriver9.By.xpath(combinedValueXpath(value)));
|
|
348
427
|
await click(optElement, this.driver);
|
|
349
428
|
return true;
|
|
350
429
|
} catch (e) {
|
|
@@ -370,7 +449,7 @@ var SwitchEditor = class extends AbstractFormElement {
|
|
|
370
449
|
return 1;
|
|
371
450
|
if (result === "OFF")
|
|
372
451
|
return 0;
|
|
373
|
-
return
|
|
452
|
+
return null;
|
|
374
453
|
}
|
|
375
454
|
async setValue(value) {
|
|
376
455
|
if (value !== 0 && value !== 1) {
|
|
@@ -388,21 +467,205 @@ var SwitchEditor = class extends AbstractFormElement {
|
|
|
388
467
|
}
|
|
389
468
|
};
|
|
390
469
|
|
|
470
|
+
// src/pageObjects/elements/Editors/TagBox.ts
|
|
471
|
+
var import_selenium_webdriver10 = require("selenium-webdriver");
|
|
472
|
+
var TAGS_SELECTOR = ".dx-tag .tag-text";
|
|
473
|
+
var DX_TAG_CONTAINER = "dx-tag-container";
|
|
474
|
+
var DX_TAGBOX = "dx-tagbox";
|
|
475
|
+
var DX_TEXTEDITOR_EMPTY2 = "dx-texteditor-empty";
|
|
476
|
+
var BTN_OK_SELECTOR = ".dx-tagbox-popup-wrapper .dx-popup-bottom .dx-button.dx-popup-done";
|
|
477
|
+
var TagBox = class extends AbstractDXEditorWithInput {
|
|
478
|
+
constructor(getParentElement, elementBy, driver) {
|
|
479
|
+
super(getParentElement, elementBy, driver);
|
|
480
|
+
this.setClearStrategy(new ClearButtonStrategy(DX_TAGBOX));
|
|
481
|
+
}
|
|
482
|
+
async setTagBoxInputValue(values) {
|
|
483
|
+
const lastElement = values[values.length - 1];
|
|
484
|
+
const inputEl = await this.getInputElement();
|
|
485
|
+
await inputEl.click();
|
|
486
|
+
for (const value of values) {
|
|
487
|
+
await this.selectOption(inputEl, value, lastElement);
|
|
488
|
+
}
|
|
489
|
+
await this.confirmSelection();
|
|
490
|
+
}
|
|
491
|
+
async selectOption(inputEl, value, lastElement) {
|
|
492
|
+
await inputEl.sendKeys(value);
|
|
493
|
+
await this.driver.wait(async () => {
|
|
494
|
+
try {
|
|
495
|
+
const optElement = await inputEl.findElement(import_selenium_webdriver10.By.xpath(combinedValueXpath(value)));
|
|
496
|
+
await click(optElement, this.driver);
|
|
497
|
+
return true;
|
|
498
|
+
} catch (e) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
if (value !== lastElement) {
|
|
503
|
+
await inputEl.clear();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
async confirmSelection() {
|
|
507
|
+
const inputEl = await this.getInputElement();
|
|
508
|
+
const option = await inputEl.findElement(import_selenium_webdriver10.By.xpath(XPathHelper.getRoleXpath(SELECT_BOX_ELEMENT_ROLE)));
|
|
509
|
+
const btnOk = await this.driver.findElement(import_selenium_webdriver10.By.css(BTN_OK_SELECTOR));
|
|
510
|
+
await this.driver.wait(async () => {
|
|
511
|
+
return await option.getAttribute("aria-selected") === "true";
|
|
512
|
+
});
|
|
513
|
+
await click(btnOk, this.driver);
|
|
514
|
+
}
|
|
515
|
+
async getTagBoxInputValue() {
|
|
516
|
+
if (await this.isTagBoxEmpty()) {
|
|
517
|
+
return [];
|
|
518
|
+
}
|
|
519
|
+
const parentEl = await this.getParentElement();
|
|
520
|
+
const inputEl = await parentEl.findElement(import_selenium_webdriver10.By.className(DX_TAG_CONTAINER));
|
|
521
|
+
const tags = await inputEl.findElements(import_selenium_webdriver10.By.css(TAGS_SELECTOR));
|
|
522
|
+
const values = [];
|
|
523
|
+
for (const tag of tags) {
|
|
524
|
+
const text = await tag.getText();
|
|
525
|
+
values.push(text);
|
|
526
|
+
}
|
|
527
|
+
return values;
|
|
528
|
+
}
|
|
529
|
+
async isTagBoxEmpty() {
|
|
530
|
+
const parentEl = await this.getParentElement();
|
|
531
|
+
const tagboxContainer = await parentEl.findElement(import_selenium_webdriver10.By.className(DX_TAGBOX));
|
|
532
|
+
const classAttribute = await tagboxContainer.getAttribute("class");
|
|
533
|
+
return classAttribute.includes(DX_TEXTEDITOR_EMPTY2);
|
|
534
|
+
}
|
|
535
|
+
async getValue() {
|
|
536
|
+
const value = await this.getTagBoxInputValue();
|
|
537
|
+
return value.length ? value : null;
|
|
538
|
+
}
|
|
539
|
+
async setValue(values) {
|
|
540
|
+
if (!Array.isArray(values)) {
|
|
541
|
+
throw new Error("The provided value is not an array");
|
|
542
|
+
}
|
|
543
|
+
await this.setTagBoxInputValue(values);
|
|
544
|
+
}
|
|
545
|
+
async remove(itemText) {
|
|
546
|
+
const tagValues = await this.getValue();
|
|
547
|
+
const tagExists = tagValues.includes(itemText);
|
|
548
|
+
if (!tagExists) {
|
|
549
|
+
throw new Error(`The tag with the text: ${itemText} was not found`);
|
|
550
|
+
}
|
|
551
|
+
const parentEl = await this.getParentElement();
|
|
552
|
+
const inputEl = await parentEl.findElement(import_selenium_webdriver10.By.className(DX_TAG_CONTAINER));
|
|
553
|
+
const clearBtnTestId = byTestId(`clear-button-${itemText}`);
|
|
554
|
+
const clearBtn = await inputEl.findElement(clearBtnTestId);
|
|
555
|
+
await click(clearBtn, this.driver);
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
// src/pageObjects/elements/Editors/ButtonGroup.ts
|
|
560
|
+
var import_selenium_webdriver11 = require("selenium-webdriver");
|
|
561
|
+
var ITEM_CLASS = "dx-buttongroup-item";
|
|
562
|
+
var SELECTED_CLASS = "dx-state-selected";
|
|
563
|
+
var ButtonGroup = class extends AbstractFormElement {
|
|
564
|
+
async getItems() {
|
|
565
|
+
return (await this.getElement()).findElements(import_selenium_webdriver11.By.className(ITEM_CLASS));
|
|
566
|
+
}
|
|
567
|
+
getDataValue(el) {
|
|
568
|
+
return el.getAttribute("data-value");
|
|
569
|
+
}
|
|
570
|
+
async getValue() {
|
|
571
|
+
const inputEl = await this.getElement();
|
|
572
|
+
const selectedEl = await inputEl.findElement(import_selenium_webdriver11.By.className(`${ITEM_CLASS} ${SELECTED_CLASS}`));
|
|
573
|
+
return this.getDataValue(selectedEl);
|
|
574
|
+
}
|
|
575
|
+
async setValue(value) {
|
|
576
|
+
const items = await this.getItems();
|
|
577
|
+
let buttonEl = void 0;
|
|
578
|
+
for (const item of items) {
|
|
579
|
+
const text = await this.getDataValue(item);
|
|
580
|
+
if (text == value) {
|
|
581
|
+
buttonEl = item;
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (!buttonEl)
|
|
586
|
+
throw new Error(`Cannot find item in button group with text: ${value}`);
|
|
587
|
+
await click(buttonEl, this.driver);
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// src/pageObjects/elements/Editors/BooleanSelector.ts
|
|
592
|
+
var BooleanSelector = class extends ButtonGroup {
|
|
593
|
+
// @ts-ignore
|
|
594
|
+
async getValue() {
|
|
595
|
+
const value = await super.getValue();
|
|
596
|
+
return value === "null" ? null : value === "1" ? 1 : 0;
|
|
597
|
+
}
|
|
598
|
+
// @ts-ignore
|
|
599
|
+
async setValue(value) {
|
|
600
|
+
const val = value == null ? "null" : value ? "1" : "0";
|
|
601
|
+
await super.setValue(val);
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
// src/pageObjects/elements/Editors/DateEditor.ts
|
|
606
|
+
var import_selenium_webdriver12 = require("selenium-webdriver");
|
|
607
|
+
var DateEditor = class extends AbstractDXEditorWithInput {
|
|
608
|
+
constructor(getParentElement, elementBy, driver) {
|
|
609
|
+
super(getParentElement, elementBy, driver);
|
|
610
|
+
this.setClearStrategy(new InputClearStrategy());
|
|
611
|
+
}
|
|
612
|
+
async getControlElement() {
|
|
613
|
+
const controlEl = await this.getElement();
|
|
614
|
+
return controlEl.findElement(import_selenium_webdriver12.By.className("dx-dropdowneditor-input-wrapper"));
|
|
615
|
+
}
|
|
616
|
+
async getDateElement() {
|
|
617
|
+
const controlEl = await this.getControlElement();
|
|
618
|
+
return controlEl.findElement(import_selenium_webdriver12.By.css("input[type=hidden]"));
|
|
619
|
+
}
|
|
620
|
+
async setDateValue(value) {
|
|
621
|
+
const dateEl = await this.getInputElement();
|
|
622
|
+
const stringDate = value.toJSON().split("T")[0];
|
|
623
|
+
const dateArr = stringDate.split("-");
|
|
624
|
+
const [year, month, day] = dateArr;
|
|
625
|
+
const keys = day + month + year;
|
|
626
|
+
await click(dateEl, this.driver);
|
|
627
|
+
const actions = this.driver.actions({ async: true });
|
|
628
|
+
await actions.move({ origin: dateEl }).sendKeys(import_selenium_webdriver12.Key.HOME).perform();
|
|
629
|
+
await actions.move({ origin: dateEl }).sendKeys(keys, import_selenium_webdriver12.Key.ENTER).perform();
|
|
630
|
+
}
|
|
631
|
+
async getDateValue() {
|
|
632
|
+
const inputEl = await this.getDateElement();
|
|
633
|
+
return inputEl.getAttribute("value");
|
|
634
|
+
}
|
|
635
|
+
async getValue() {
|
|
636
|
+
const value = await this.getDateValue();
|
|
637
|
+
return value == "" ? null : new Date(value);
|
|
638
|
+
}
|
|
639
|
+
setValue(value) {
|
|
640
|
+
if (typeof value === "object") {
|
|
641
|
+
return this.setDateValue(value);
|
|
642
|
+
}
|
|
643
|
+
throw new Error(`Value is incorrect. It should be Object`);
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
|
|
391
647
|
// src/pageObjects/elements/Editors/editorFactory.ts
|
|
392
648
|
var editorFactory = async (getParentElement, elementBy, driver) => {
|
|
393
649
|
const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
|
|
394
|
-
const
|
|
395
|
-
const classSting = await element.getAttribute("class");
|
|
650
|
+
const classSting = await elementInstance.getClasses();
|
|
396
651
|
if (classSting.includes("text-control"))
|
|
397
652
|
return new TextEditor(getParentElement, elementBy, driver);
|
|
398
653
|
if (classSting.includes("number-control"))
|
|
399
654
|
return new NumberEditor(getParentElement, elementBy, driver);
|
|
400
655
|
if (classSting.includes("check-box"))
|
|
401
656
|
return new CheckBox(getParentElement, elementBy, driver);
|
|
657
|
+
if (classSting.includes("multi-select-control"))
|
|
658
|
+
return new TagBox(getParentElement, elementBy, driver);
|
|
402
659
|
if (classSting.includes("select-control"))
|
|
403
660
|
return new SelectBoxEditor(getParentElement, elementBy, driver);
|
|
404
661
|
if (classSting.includes("switch-control"))
|
|
405
662
|
return new SwitchEditor(getParentElement, elementBy, driver);
|
|
663
|
+
if (classSting.includes("date-control"))
|
|
664
|
+
return new DateEditor(getParentElement, elementBy, driver);
|
|
665
|
+
if (classSting.includes("buttons-group"))
|
|
666
|
+
return new BooleanSelector(getParentElement, elementBy, driver);
|
|
667
|
+
if (classSting.includes("button-group-field"))
|
|
668
|
+
return new ButtonGroup(getParentElement, elementBy, driver);
|
|
406
669
|
throw new Error("Unknown type of editor. Please write ticket to the support");
|
|
407
670
|
};
|
|
408
671
|
|
|
@@ -413,6 +676,9 @@ function createDataTestId(formName, itemType, itemName) {
|
|
|
413
676
|
function createFieldTestId(formName, itemName) {
|
|
414
677
|
return createDataTestId(formName, "form_field" /* FORM_FIELD */, itemName);
|
|
415
678
|
}
|
|
679
|
+
function createGroupTestId(formName, itemName) {
|
|
680
|
+
return createDataTestId(formName, "group" /* GROUP */, itemName);
|
|
681
|
+
}
|
|
416
682
|
function createTableId(formName) {
|
|
417
683
|
return `${"table" /* TABLE */}-${formName}`;
|
|
418
684
|
}
|
|
@@ -449,14 +715,82 @@ var FormField = class extends AbstractElementWithParent {
|
|
|
449
715
|
await this.initEditor();
|
|
450
716
|
return this.editor.setValue(value);
|
|
451
717
|
}
|
|
718
|
+
/**
|
|
719
|
+
* Очищает значение в поле
|
|
720
|
+
* @example
|
|
721
|
+
* await formEdit.field('NumberFld').clear();
|
|
722
|
+
*/
|
|
723
|
+
async clear() {
|
|
724
|
+
await this.initEditor();
|
|
725
|
+
if (!this.editor.clear) {
|
|
726
|
+
throw new Error("The clear method is not available for this field type.");
|
|
727
|
+
}
|
|
728
|
+
return this.editor.clear();
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Удаляет тег по переданному тексту
|
|
732
|
+
* @example
|
|
733
|
+
* await formEdit.field('TagBox').remove('test');
|
|
734
|
+
*/
|
|
735
|
+
async remove(itemText) {
|
|
736
|
+
await this.initEditor();
|
|
737
|
+
if (!this.editor.remove) {
|
|
738
|
+
throw new Error("This method is only available for the TagBox field.");
|
|
739
|
+
}
|
|
740
|
+
return this.editor.remove(itemText);
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
// src/pageObjects/elements/Groups/AbstractGroup.ts
|
|
745
|
+
var AbstractDXGroup = class extends AbstractFormElement {
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
// src/pageObjects/elements/Groups/Panel.ts
|
|
749
|
+
var Panel = class extends AbstractDXGroup {
|
|
750
|
+
async isDisplayed() {
|
|
751
|
+
const groupElement = await this.getElement();
|
|
752
|
+
return await groupElement.isDisplayed();
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
// src/pageObjects/elements/Groups/groupFactory.ts
|
|
757
|
+
var groupFactory = async (getParentElement, elementBy, driver) => {
|
|
758
|
+
const elementInstance = new AbstractFormElement(getParentElement, elementBy, driver);
|
|
759
|
+
const classSting = await elementInstance.getClasses();
|
|
760
|
+
if (classSting.includes("panel-group"))
|
|
761
|
+
return new Panel(getParentElement, elementBy, driver);
|
|
762
|
+
throw new Error("Unknown type of group. Please write ticket to the support");
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
// src/pageObjects/elements/FormGroup.ts
|
|
766
|
+
var FormGroup = class extends AbstractElementWithParent {
|
|
767
|
+
editor;
|
|
768
|
+
constructor(getParentElement, formName, name, driver) {
|
|
769
|
+
super(getParentElement, driver);
|
|
770
|
+
this.elementBy = byTestId(createGroupTestId(formName, name));
|
|
771
|
+
}
|
|
772
|
+
async initEditor() {
|
|
773
|
+
if (!this.editor) {
|
|
774
|
+
this.editor = await groupFactory(this.getParentElement, this.elementBy, this.driver);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Возвращает булевое значение доступна ли группа
|
|
779
|
+
* @example
|
|
780
|
+
* expect(await tableList.group('MainSuperPanel').isDisplayed();
|
|
781
|
+
*/
|
|
782
|
+
async isDisplayed() {
|
|
783
|
+
await this.initEditor();
|
|
784
|
+
return this.editor.isDisplayed();
|
|
785
|
+
}
|
|
452
786
|
};
|
|
453
787
|
|
|
454
788
|
// src/pageObjects/elements/Forms/FormEdit.ts
|
|
455
789
|
var FormEdit = class extends AbstractForm {
|
|
456
|
-
saveButtonBy =
|
|
790
|
+
saveButtonBy = import_selenium_webdriver13.By.id("button-save");
|
|
457
791
|
constructor(driver) {
|
|
458
792
|
super(driver);
|
|
459
|
-
this.popupContainerBy =
|
|
793
|
+
this.popupContainerBy = import_selenium_webdriver13.By.className(`popup form-edit-${this.formName}`);
|
|
460
794
|
}
|
|
461
795
|
/**
|
|
462
796
|
* Находит поле формы редактирования по имени
|
|
@@ -468,6 +802,28 @@ var FormEdit = class extends AbstractForm {
|
|
|
468
802
|
field(name) {
|
|
469
803
|
return new FormField(this.getContainerElement, this.formName, name, this.driver);
|
|
470
804
|
}
|
|
805
|
+
/**
|
|
806
|
+
* Проверяет не отключена ли кнопка Сохранить
|
|
807
|
+
* @example
|
|
808
|
+
* const formEdit = new MyForm();
|
|
809
|
+
* //...
|
|
810
|
+
* await formEdit.isSaveButtonDisabled();
|
|
811
|
+
*/
|
|
812
|
+
async isSaveButtonDisabled() {
|
|
813
|
+
const saveButton = await this.driver.findElement(this.saveButtonBy);
|
|
814
|
+
const result = await saveButton.getAttribute("aria-disabled");
|
|
815
|
+
return result === "true";
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Находит группу формы редактирования по имени
|
|
819
|
+
* @example
|
|
820
|
+
* const formEdit = new MyForm();
|
|
821
|
+
* //...
|
|
822
|
+
* expect(await formEdit.group('Name');
|
|
823
|
+
*/
|
|
824
|
+
group(name) {
|
|
825
|
+
return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
|
|
826
|
+
}
|
|
471
827
|
/**
|
|
472
828
|
* Нажатие на кнопку Сохранить
|
|
473
829
|
* @example
|
|
@@ -476,35 +832,36 @@ var FormEdit = class extends AbstractForm {
|
|
|
476
832
|
* await formEdit.saveButtonClick();
|
|
477
833
|
*/
|
|
478
834
|
async saveButtonClick() {
|
|
479
|
-
|
|
835
|
+
const saveButton = await this.driver.findElement(this.saveButtonBy);
|
|
836
|
+
await this.driver.wait(async () => !await this.isSaveButtonDisabled(), void 0, "Button is disabled");
|
|
837
|
+
await click(saveButton, this.driver);
|
|
480
838
|
}
|
|
481
839
|
};
|
|
482
840
|
|
|
483
841
|
// src/pageObjects/elements/Forms/ListForm.ts
|
|
484
|
-
var
|
|
842
|
+
var import_selenium_webdriver19 = require("selenium-webdriver");
|
|
485
843
|
|
|
486
844
|
// src/pageObjects/elements/Table/Table.ts
|
|
487
|
-
var
|
|
845
|
+
var import_selenium_webdriver16 = require("selenium-webdriver");
|
|
488
846
|
|
|
489
847
|
// src/pageObjects/elements/Table/utils.ts
|
|
490
|
-
var
|
|
848
|
+
var import_selenium_webdriver14 = require("selenium-webdriver");
|
|
491
849
|
var getRowPathByIndex = (index) => {
|
|
492
|
-
return
|
|
850
|
+
return import_selenium_webdriver14.By.css(`tr[aria-rowindex="${transformInputIndex(index)}"]`);
|
|
493
851
|
};
|
|
852
|
+
var getColumnByIndexCssSelector = (columnIndex) => `td[aria-colindex="${transformInputIndex(columnIndex)}"]`;
|
|
494
853
|
var getColumnPathByIndex = (index) => {
|
|
495
|
-
return
|
|
496
|
-
};
|
|
497
|
-
var getColumnPathByCaption = (caption) => {
|
|
498
|
-
return import_selenium_webdriver10.By.css(`td[role="columnheader"][aria-label="Column ${caption}"]`);
|
|
854
|
+
return import_selenium_webdriver14.By.css(getColumnByIndexCssSelector(index));
|
|
499
855
|
};
|
|
856
|
+
var getColumnByCaptionCssSelector = (caption) => `td[role="columnheader"][aria-label="Column ${caption}"]`;
|
|
500
857
|
var getCellPathByIndex = (index) => {
|
|
501
|
-
return
|
|
858
|
+
return import_selenium_webdriver14.By.css(`td[role="gridcell"][aria-colindex="${transformInputIndex(index)}"]`);
|
|
502
859
|
};
|
|
503
860
|
var transformInputIndex = (index) => index + 1;
|
|
504
861
|
var transformOutputIndex = (index) => +index - 1;
|
|
505
862
|
|
|
506
863
|
// src/pageObjects/elements/Table/elements/Row.ts
|
|
507
|
-
var
|
|
864
|
+
var import_selenium_webdriver15 = require("selenium-webdriver");
|
|
508
865
|
|
|
509
866
|
// src/pageObjects/elements/Table/elements/Cell.ts
|
|
510
867
|
var Cell = class extends AbstractElementWithParent {
|
|
@@ -526,6 +883,7 @@ var Cell = class extends AbstractElementWithParent {
|
|
|
526
883
|
// src/pageObjects/elements/Table/elements/Row.ts
|
|
527
884
|
var DX_SELECTION_CLASS = "dx-selection";
|
|
528
885
|
var DX_ROW_EDIT_CLASS = "dx-edit-row";
|
|
886
|
+
var DX_DATA_ROW_CLASS = "dx-data-row";
|
|
529
887
|
var Row = class extends AbstractElementWithParent {
|
|
530
888
|
index;
|
|
531
889
|
getColumnByCaption;
|
|
@@ -556,10 +914,8 @@ var Row = class extends AbstractElementWithParent {
|
|
|
556
914
|
await click(rowEl, this.driver);
|
|
557
915
|
await this.driver.wait(async () => {
|
|
558
916
|
const classes = await rowEl.getAttribute("class");
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
return true;
|
|
562
|
-
}, 500);
|
|
917
|
+
return classes.includes(DX_SELECTION_CLASS);
|
|
918
|
+
}, 500, "Cannot select row");
|
|
563
919
|
}
|
|
564
920
|
async isSelected() {
|
|
565
921
|
const rowEl = await this.getElement();
|
|
@@ -571,7 +927,7 @@ var Row = class extends AbstractElementWithParent {
|
|
|
571
927
|
}
|
|
572
928
|
async getCells() {
|
|
573
929
|
const rowEl = await this.getElement();
|
|
574
|
-
const cells = await rowEl.findElements(
|
|
930
|
+
const cells = await rowEl.findElements(import_selenium_webdriver15.By.css(`td[role="gridcell"]`));
|
|
575
931
|
const result = [];
|
|
576
932
|
cells.forEach((_, index) => {
|
|
577
933
|
const newCell = new Cell(rowEl, index, this.driver);
|
|
@@ -579,26 +935,30 @@ var Row = class extends AbstractElementWithParent {
|
|
|
579
935
|
});
|
|
580
936
|
return result;
|
|
581
937
|
}
|
|
582
|
-
async clickInlineButton(
|
|
583
|
-
const
|
|
584
|
-
|
|
938
|
+
async clickInlineButton(buttonClass) {
|
|
939
|
+
const FIXED_TABLE_CSS_SELECTOR = ".dx-fixed-columns .dx-datagrid-content.dx-datagrid-content-fixed";
|
|
940
|
+
const buttonCssSelector = `.${DX_DATA_ROW_CLASS}[aria-rowindex="${transformInputIndex(this.index)}"] .${buttonClass}`;
|
|
941
|
+
const button = (await this.getParentElement()).findElement(
|
|
942
|
+
import_selenium_webdriver15.By.css(`${FIXED_TABLE_CSS_SELECTOR} ${buttonCssSelector}`)
|
|
585
943
|
);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
944
|
+
return click(button, this.driver);
|
|
945
|
+
}
|
|
946
|
+
async checkEditingMode(isEditing, msg) {
|
|
947
|
+
await this.driver.wait(async () => {
|
|
948
|
+
return (await this.getClasses()).includes(DX_ROW_EDIT_CLASS) === isEditing;
|
|
949
|
+
}, 2e3, msg);
|
|
592
950
|
}
|
|
593
951
|
async edit() {
|
|
594
|
-
await this.
|
|
595
|
-
|
|
952
|
+
await this.clickInlineButton("edit");
|
|
953
|
+
await this.checkEditingMode(true, "Row did not switch to edit mode");
|
|
596
954
|
}
|
|
597
955
|
async save() {
|
|
598
|
-
|
|
956
|
+
await this.clickInlineButton("save");
|
|
957
|
+
await this.checkEditingMode(false, "Row did not saved");
|
|
599
958
|
}
|
|
600
959
|
async cancel() {
|
|
601
|
-
|
|
960
|
+
await this.clickInlineButton("cancel");
|
|
961
|
+
await this.checkEditingMode(false, "Row did not switch to normal mode");
|
|
602
962
|
}
|
|
603
963
|
};
|
|
604
964
|
|
|
@@ -624,19 +984,18 @@ var Table = class extends AbstractElementWithParent {
|
|
|
624
984
|
formName;
|
|
625
985
|
constructor(getParentElement, formName, driver) {
|
|
626
986
|
super(getParentElement, driver);
|
|
627
|
-
this.elementBy =
|
|
987
|
+
this.elementBy = import_selenium_webdriver16.By.id(createTableId(formName));
|
|
628
988
|
this.formName = formName;
|
|
629
989
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
return parentEl.findElement(import_selenium_webdriver12.By.className("dx-header-row"));
|
|
990
|
+
getHeaderCssSelector() {
|
|
991
|
+
return ".dx-datagrid-headers .dx-datagrid-content:not(.dx-datagrid-content-fixed)";
|
|
633
992
|
}
|
|
634
993
|
async getDataGrid() {
|
|
635
994
|
const parentEl = await this.getElement();
|
|
636
|
-
return parentEl.findElement(
|
|
995
|
+
return parentEl.findElement(import_selenium_webdriver16.By.css(`div[role="grid"]`));
|
|
637
996
|
}
|
|
638
997
|
getTableElement = () => {
|
|
639
|
-
return this.
|
|
998
|
+
return this.getElement();
|
|
640
999
|
};
|
|
641
1000
|
async getRowByIndex(index) {
|
|
642
1001
|
const gridContainer = await this.getDataGrid();
|
|
@@ -647,16 +1006,14 @@ var Table = class extends AbstractElementWithParent {
|
|
|
647
1006
|
throw new Error(`Cannot find row by index: ${index}`);
|
|
648
1007
|
}
|
|
649
1008
|
async getColumnByIndex(index) {
|
|
650
|
-
const
|
|
651
|
-
const column = await headerContainer.findElement(getColumnPathByIndex(index));
|
|
1009
|
+
const column = await (await this.getElement()).findElement(import_selenium_webdriver16.By.css(`${this.getHeaderCssSelector()} ${getColumnByIndexCssSelector(index)}`));
|
|
652
1010
|
if (column) {
|
|
653
1011
|
return new Column(this.getTableElement, index, this.driver);
|
|
654
1012
|
}
|
|
655
1013
|
throw new Error(`Cannot find column by index: ${index}`);
|
|
656
1014
|
}
|
|
657
1015
|
async getColumnByCaption(caption) {
|
|
658
|
-
const
|
|
659
|
-
const column = await headerContainer.findElement(getColumnPathByCaption(caption));
|
|
1016
|
+
const column = await (await this.getElement()).findElement(import_selenium_webdriver16.By.css(`${this.getHeaderCssSelector()} ${getColumnByCaptionCssSelector(caption)}`));
|
|
660
1017
|
if (column) {
|
|
661
1018
|
const index = await column.getAttribute("aria-colindex");
|
|
662
1019
|
return new Column(this.getTableElement, transformOutputIndex(index), this.driver);
|
|
@@ -673,7 +1030,7 @@ var Table = class extends AbstractElementWithParent {
|
|
|
673
1030
|
}
|
|
674
1031
|
async getRows() {
|
|
675
1032
|
const gridContainer = await this.getDataGrid();
|
|
676
|
-
const rows = await gridContainer.findElements(
|
|
1033
|
+
const rows = await gridContainer.findElements(import_selenium_webdriver16.By.className("dx-row dx-data-row"));
|
|
677
1034
|
const result = [];
|
|
678
1035
|
rows.forEach((_, index) => {
|
|
679
1036
|
const newRow = new Row(this.getTableElement, index, this.driver, this.getColumnByCaption.bind(this));
|
|
@@ -682,8 +1039,7 @@ var Table = class extends AbstractElementWithParent {
|
|
|
682
1039
|
return result;
|
|
683
1040
|
}
|
|
684
1041
|
async getColumns() {
|
|
685
|
-
const
|
|
686
|
-
const columns = await headerContainer.findElements(import_selenium_webdriver12.By.css(`td[role="columnheader"]`));
|
|
1042
|
+
const columns = await (await this.getElement()).findElements(import_selenium_webdriver16.By.css(`${this.getHeaderCssSelector()} td[role="columnheader"]`));
|
|
687
1043
|
const result = [];
|
|
688
1044
|
columns.forEach((_, index) => {
|
|
689
1045
|
const newCol = new Column(this.getTableElement, index, this.driver);
|
|
@@ -702,23 +1058,28 @@ var Table = class extends AbstractElementWithParent {
|
|
|
702
1058
|
* expect(await form.field('Name').getValue()).toBe('test value');
|
|
703
1059
|
*/
|
|
704
1060
|
field(name) {
|
|
705
|
-
return new FormField(this.
|
|
1061
|
+
return new FormField(this.getTableElement, this.formName, name, this.driver);
|
|
706
1062
|
}
|
|
707
1063
|
};
|
|
708
1064
|
|
|
709
1065
|
// src/pageObjects/elements/TableToolbar/TableToolbar.ts
|
|
710
|
-
var
|
|
1066
|
+
var import_selenium_webdriver18 = require("selenium-webdriver");
|
|
711
1067
|
|
|
712
1068
|
// src/pageObjects/elements/TableToolbar/TableToolbarButton.ts
|
|
713
|
-
var
|
|
1069
|
+
var import_selenium_webdriver17 = require("selenium-webdriver");
|
|
714
1070
|
var TOOLBAR_BUTTON_CLASS = "toolbar-button";
|
|
715
1071
|
var TableToolbarButton = class extends AbstractElementWithParent {
|
|
1072
|
+
name;
|
|
716
1073
|
constructor(getParentElement, name, driver) {
|
|
717
1074
|
super(getParentElement, driver);
|
|
718
|
-
this.
|
|
1075
|
+
this.name = name;
|
|
1076
|
+
this.elementBy = import_selenium_webdriver17.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`);
|
|
719
1077
|
}
|
|
720
1078
|
async click() {
|
|
721
1079
|
const button = await this.getElement();
|
|
1080
|
+
await this.driver.wait(async () => {
|
|
1081
|
+
return await button.isDisplayed() && !await this.isDisabled();
|
|
1082
|
+
}, 1e3, `Button ${this.name} cannot be clicked. It is not displayed or it is disabled`);
|
|
722
1083
|
return click(button, this.driver);
|
|
723
1084
|
}
|
|
724
1085
|
async isDisabled() {
|
|
@@ -733,14 +1094,14 @@ var TABLE_TOOLBAR_CLASS = "d5-table-toolbar";
|
|
|
733
1094
|
var TableToolbar = class extends AbstractElementWithParent {
|
|
734
1095
|
constructor(getParentElement, formName, driver) {
|
|
735
1096
|
super(getParentElement, driver);
|
|
736
|
-
this.elementBy =
|
|
1097
|
+
this.elementBy = import_selenium_webdriver18.By.id(`${TABLE_TOOLBAR_CLASS}-${formName}`);
|
|
737
1098
|
}
|
|
738
1099
|
getTableToolbarElement = () => {
|
|
739
1100
|
return this.driver.findElement(this.elementBy);
|
|
740
1101
|
};
|
|
741
1102
|
async button(name) {
|
|
742
1103
|
const toolbar = await this.getTableToolbarElement();
|
|
743
|
-
const button = await toolbar.findElement(
|
|
1104
|
+
const button = await toolbar.findElement(import_selenium_webdriver18.By.id(`${TOOLBAR_BUTTON_CLASS}-${name}`));
|
|
744
1105
|
if (button) {
|
|
745
1106
|
return new TableToolbarButton(this.getTableToolbarElement, name, this.driver);
|
|
746
1107
|
}
|
|
@@ -752,7 +1113,7 @@ var TableToolbar = class extends AbstractElementWithParent {
|
|
|
752
1113
|
var ListForm = class extends AbstractForm {
|
|
753
1114
|
constructor(driver) {
|
|
754
1115
|
super(driver);
|
|
755
|
-
this.popupContainerBy =
|
|
1116
|
+
this.popupContainerBy = import_selenium_webdriver19.By.className(`popup form-inline-${this.formName}`);
|
|
756
1117
|
}
|
|
757
1118
|
/**
|
|
758
1119
|
* Находит таблицу
|
|
@@ -764,6 +1125,16 @@ var ListForm = class extends AbstractForm {
|
|
|
764
1125
|
table() {
|
|
765
1126
|
return new Table(this.getContainerElement, this.formName, this.driver);
|
|
766
1127
|
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Находит группу на лист форме по имени
|
|
1130
|
+
* @example
|
|
1131
|
+
* const formEdit = new MyForm();
|
|
1132
|
+
* //...
|
|
1133
|
+
* expect(await formEdit.group('Name');
|
|
1134
|
+
*/
|
|
1135
|
+
group(name) {
|
|
1136
|
+
return new FormGroup(this.getContainerElement, this.formName, name, this.driver);
|
|
1137
|
+
}
|
|
767
1138
|
/**
|
|
768
1139
|
* Находит таблицу
|
|
769
1140
|
* @example
|
|
@@ -800,6 +1171,14 @@ var LoginPage = class extends AbstractPage {
|
|
|
800
1171
|
usernameField = byTestId("loginField", "input");
|
|
801
1172
|
passwordField = byTestId("passwordField", "input");
|
|
802
1173
|
loginButton = byTestId("loginButton");
|
|
1174
|
+
async locate() {
|
|
1175
|
+
await super.locate();
|
|
1176
|
+
const login = await this.driver.findElement(this.usernameField);
|
|
1177
|
+
await waitElementIsVisible({
|
|
1178
|
+
element: login,
|
|
1179
|
+
driver: this.driver
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
803
1182
|
get path() {
|
|
804
1183
|
return LOGIN_PATH;
|
|
805
1184
|
}
|
|
@@ -837,5 +1216,6 @@ var LoginPage = class extends AbstractPage {
|
|
|
837
1216
|
createDriver,
|
|
838
1217
|
editorFactory,
|
|
839
1218
|
elementIsNotPresent,
|
|
840
|
-
signIn
|
|
1219
|
+
signIn,
|
|
1220
|
+
waitElementIsVisible
|
|
841
1221
|
});
|