@redhat-developer/page-objects 1.17.0 → 1.18.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/out/components/AbstractElement.d.ts +77 -1
- package/out/components/AbstractElement.js +169 -12
- package/out/components/ActionButtonElementDropdown.js +14 -2
- package/out/components/activityBar/ViewControl.js +5 -1
- package/out/components/bottomBar/Views.js +25 -12
- package/out/components/editor/ContentAssist.js +2 -1
- package/out/components/editor/EditorView.js +50 -9
- package/out/components/editor/ExtensionEditorDetailsSection.js +31 -7
- package/out/components/editor/SettingsEditor.js +110 -28
- package/out/components/editor/TextEditor.js +120 -25
- package/out/components/menu/ContextMenu.js +27 -6
- package/out/components/menu/MenuItem.js +14 -1
- package/out/components/menu/TitleBar.js +15 -3
- package/out/components/sidebar/ViewSection.js +14 -4
- package/out/components/sidebar/WelcomeContent.js +10 -2
- package/out/components/sidebar/debug/DebugView.js +10 -2
- package/out/components/sidebar/extensions/ExtensionsViewSection.js +20 -5
- package/out/components/sidebar/scm/NewScmView.js +53 -13
- package/out/components/sidebar/scm/ScmView.js +12 -4
- package/out/components/sidebar/tree/TreeSection.js +11 -3
- package/out/components/sidebar/tree/custom/CustomTreeSection.js +22 -6
- package/out/components/sidebar/tree/debug/WatchSection.js +5 -1
- package/out/components/sidebar/tree/default/DefaultTreeSection.js +9 -1
- package/out/components/workbench/Notification.js +10 -2
- package/out/components/workbench/NotificationsCenter.js +11 -3
- package/out/components/workbench/Workbench.js +14 -4
- package/out/components/workbench/input/Input.js +45 -16
- package/out/components/workbench/input/InputBox.js +20 -4
- package/out/components/workbench/input/QuickOpenBox.js +11 -3
- package/out/errors/ExTesterError.d.ts +112 -0
- package/out/errors/ExTesterError.js +201 -0
- package/out/index.d.ts +2 -0
- package/out/index.js +2 -0
- package/out/utils/WaitHelper.d.ts +202 -0
- package/out/utils/WaitHelper.js +465 -0
- package/package.json +4 -4
|
@@ -76,16 +76,12 @@ class SettingsEditor extends Editor_1.Editor {
|
|
|
76
76
|
}
|
|
77
77
|
async _getSettingItem(title = '', category = '') {
|
|
78
78
|
const count = await this.findElement(SettingsEditor.locators.SettingsEditor.itemCount);
|
|
79
|
-
|
|
80
|
-
await this.
|
|
81
|
-
await new Promise((res) => setTimeout(res, 1500));
|
|
79
|
+
// Wait for settings count to stabilize (loading complete)
|
|
80
|
+
await this.getWaitHelper().forCountStable(async () => {
|
|
82
81
|
const text = await count.getText();
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
return true;
|
|
88
|
-
});
|
|
82
|
+
const match = new RegExp(/\d+/).exec(text);
|
|
83
|
+
return match ? Number.parseInt(match[0], 10) : 0;
|
|
84
|
+
}, { timeout: 5000, stabilityInterval: 300, stableChecks: 2 });
|
|
89
85
|
let setting;
|
|
90
86
|
const items = await this.findElements(SettingsEditor.locators.SettingsEditor.itemRow);
|
|
91
87
|
for (const item of items) {
|
|
@@ -212,12 +208,20 @@ class ComboSetting extends Setting {
|
|
|
212
208
|
async setValue(value) {
|
|
213
209
|
const rows = await this.getOptions();
|
|
214
210
|
for (const row of rows) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
211
|
+
try {
|
|
212
|
+
if ((await row.getAttribute('class')).indexOf('disabled') < 0) {
|
|
213
|
+
const text = await row.getAttribute(SettingsEditor.locators.SettingsEditor.comboValue);
|
|
214
|
+
if (value === text) {
|
|
215
|
+
return await row.click();
|
|
216
|
+
}
|
|
219
217
|
}
|
|
220
218
|
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
throw e;
|
|
224
|
+
}
|
|
221
225
|
}
|
|
222
226
|
}
|
|
223
227
|
/**
|
|
@@ -228,7 +232,15 @@ class ComboSetting extends Setting {
|
|
|
228
232
|
const values = [];
|
|
229
233
|
const rows = await this.getOptions();
|
|
230
234
|
for (const row of rows) {
|
|
231
|
-
|
|
235
|
+
try {
|
|
236
|
+
values.push(await row.getAttribute(SettingsEditor.locators.SettingsEditor.comboValue));
|
|
237
|
+
}
|
|
238
|
+
catch (e) {
|
|
239
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
throw e;
|
|
243
|
+
}
|
|
232
244
|
}
|
|
233
245
|
return values;
|
|
234
246
|
}
|
|
@@ -348,10 +360,21 @@ class ArraySetting extends Setting {
|
|
|
348
360
|
* @returns string[]
|
|
349
361
|
*/
|
|
350
362
|
async getValues() {
|
|
351
|
-
const items = await this.getItems();
|
|
352
363
|
const values = [];
|
|
353
|
-
|
|
354
|
-
|
|
364
|
+
const listRows = await this.getRows();
|
|
365
|
+
for (const row of listRows) {
|
|
366
|
+
try {
|
|
367
|
+
const li = await row.findElement(SettingsEditor.locators.SettingsEditor.arrayRowValue);
|
|
368
|
+
values.push(await li.getText());
|
|
369
|
+
}
|
|
370
|
+
catch (e) {
|
|
371
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
372
|
+
// Item became stale during iteration (DOM updating), skip it
|
|
373
|
+
// The caller's retry logic will handle getting a consistent view
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
throw e;
|
|
377
|
+
}
|
|
355
378
|
}
|
|
356
379
|
return values;
|
|
357
380
|
}
|
|
@@ -363,9 +386,13 @@ class ArraySetting extends Setting {
|
|
|
363
386
|
// click 'Add Item' button
|
|
364
387
|
const button = await this.findElement(SettingsEditor.locators.SettingsEditor.arrayNewRow).findElement(SettingsEditor.locators.SettingsEditor.button);
|
|
365
388
|
await button.click();
|
|
366
|
-
|
|
367
|
-
// get item row switched to 'edit' mode
|
|
389
|
+
// Wait for edit row to appear in DOM
|
|
368
390
|
const list = await this.getListRootElement();
|
|
391
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
392
|
+
const rows = await list.findElements(SettingsEditor.locators.SettingsEditor.arrayEditRow);
|
|
393
|
+
return rows.length > 0;
|
|
394
|
+
}, { timeout: 2000, message: 'Edit row did not appear after clicking Add Item' });
|
|
395
|
+
// get item row switched to 'edit' mode
|
|
369
396
|
const editRow = await list.findElement(SettingsEditor.locators.SettingsEditor.arrayEditRow);
|
|
370
397
|
return new ArraySettingItem(editRow, this);
|
|
371
398
|
}
|
|
@@ -383,9 +410,13 @@ class ArraySetting extends Setting {
|
|
|
383
410
|
// click 'Edit Item' button
|
|
384
411
|
const edit = await toEdit.findElement(SettingsEditor.locators.SettingsEditor.arrayBtnConstructor('Edit Item'));
|
|
385
412
|
await edit.click();
|
|
386
|
-
|
|
387
|
-
// get item row switched to 'edit' mode
|
|
413
|
+
// Wait for edit row to appear in DOM
|
|
388
414
|
const list = await this.getListRootElement();
|
|
415
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
416
|
+
const rows = await list.findElements(SettingsEditor.locators.SettingsEditor.arrayEditRow);
|
|
417
|
+
return rows.length > 0;
|
|
418
|
+
}, { timeout: 2000, message: 'Edit row did not appear after clicking Edit Item' });
|
|
419
|
+
// get item row switched to 'edit' mode
|
|
389
420
|
const editRow = await list.findElement(SettingsEditor.locators.SettingsEditor.arrayEditRow);
|
|
390
421
|
return new ArraySettingItem(editRow, this);
|
|
391
422
|
}
|
|
@@ -409,9 +440,17 @@ class ArraySetting extends Setting {
|
|
|
409
440
|
}
|
|
410
441
|
else {
|
|
411
442
|
for (const row of listRows) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
443
|
+
try {
|
|
444
|
+
const li = await row.findElement(SettingsEditor.locators.SettingsEditor.arrayRowValue);
|
|
445
|
+
if ((await li.getText()) === item) {
|
|
446
|
+
return row;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
catch (e) {
|
|
450
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
throw e;
|
|
415
454
|
}
|
|
416
455
|
}
|
|
417
456
|
}
|
|
@@ -431,7 +470,11 @@ class ArraySettingItem extends AbstractElement_1.AbstractElement {
|
|
|
431
470
|
*/
|
|
432
471
|
async select() {
|
|
433
472
|
await this.click();
|
|
434
|
-
|
|
473
|
+
// Wait for selection state to be applied
|
|
474
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
475
|
+
const classAttr = await this.getAttribute('class');
|
|
476
|
+
return classAttr && (classAttr.includes('selected') || classAttr.includes('focused'));
|
|
477
|
+
}, { timeout: 1000, pollInterval: 50 });
|
|
435
478
|
}
|
|
436
479
|
/**
|
|
437
480
|
* Get item text value
|
|
@@ -456,7 +499,16 @@ class ArraySettingItem extends AbstractElement_1.AbstractElement {
|
|
|
456
499
|
await this.select();
|
|
457
500
|
const remove = await this.findElement(SettingsEditor.locators.SettingsEditor.arrayBtnConstructor('Remove Item'));
|
|
458
501
|
await remove.click();
|
|
459
|
-
|
|
502
|
+
// Wait for item to be removed from DOM
|
|
503
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
504
|
+
try {
|
|
505
|
+
await this.isDisplayed();
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
return true; // Element no longer exists
|
|
510
|
+
}
|
|
511
|
+
}, { timeout: 1000, pollInterval: 50 });
|
|
460
512
|
}
|
|
461
513
|
/**
|
|
462
514
|
* Click 'OK' button
|
|
@@ -465,7 +517,22 @@ class ArraySettingItem extends AbstractElement_1.AbstractElement {
|
|
|
465
517
|
async ok() {
|
|
466
518
|
const ok = await this.findElement(SettingsEditor.locators.SettingsEditor.arraySettingItem.btnConstructor('OK'));
|
|
467
519
|
await ok.click();
|
|
468
|
-
|
|
520
|
+
// Wait for edit mode to close - the edit row will be removed from DOM
|
|
521
|
+
await this.getWaitHelper()
|
|
522
|
+
.forCondition(async () => {
|
|
523
|
+
try {
|
|
524
|
+
await this.isDisplayed();
|
|
525
|
+
// Check if still in edit mode by looking for OK button
|
|
526
|
+
const okButtons = await this.findElements(SettingsEditor.locators.SettingsEditor.arraySettingItem.btnConstructor('OK'));
|
|
527
|
+
return okButtons.length === 0;
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
return true; // Element removed from DOM
|
|
531
|
+
}
|
|
532
|
+
}, { timeout: 2000, pollInterval: 100 })
|
|
533
|
+
.catch(() => {
|
|
534
|
+
/* Element may already be gone */
|
|
535
|
+
});
|
|
469
536
|
}
|
|
470
537
|
/**
|
|
471
538
|
* Click 'Cancel' button
|
|
@@ -474,7 +541,22 @@ class ArraySettingItem extends AbstractElement_1.AbstractElement {
|
|
|
474
541
|
async cancel() {
|
|
475
542
|
const cancel = await this.findElement(SettingsEditor.locators.SettingsEditor.arraySettingItem.btnConstructor('Cancel'));
|
|
476
543
|
await cancel.click();
|
|
477
|
-
|
|
544
|
+
// Wait for edit mode to close - the edit row will be removed from DOM
|
|
545
|
+
await this.getWaitHelper()
|
|
546
|
+
.forCondition(async () => {
|
|
547
|
+
try {
|
|
548
|
+
await this.isDisplayed();
|
|
549
|
+
// Check if still in edit mode by looking for Cancel button
|
|
550
|
+
const cancelButtons = await this.findElements(SettingsEditor.locators.SettingsEditor.arraySettingItem.btnConstructor('Cancel'));
|
|
551
|
+
return cancelButtons.length === 0;
|
|
552
|
+
}
|
|
553
|
+
catch {
|
|
554
|
+
return true; // Element removed from DOM
|
|
555
|
+
}
|
|
556
|
+
}, { timeout: 2000, pollInterval: 100 })
|
|
557
|
+
.catch(() => {
|
|
558
|
+
/* Element may already be gone */
|
|
559
|
+
});
|
|
478
560
|
}
|
|
479
561
|
}
|
|
480
562
|
exports.ArraySettingItem = ArraySettingItem;
|
|
@@ -130,7 +130,16 @@ class TextEditor extends Editor_1.Editor {
|
|
|
130
130
|
}
|
|
131
131
|
const inputarea = await self.findElement(TextEditor.locators.Editor.inputArea);
|
|
132
132
|
await inputarea.sendKeys(selenium_webdriver_1.Key.chord(TextEditor.ctlKey, 'a'), selenium_webdriver_1.Key.chord(TextEditor.ctlKey, 'c'));
|
|
133
|
-
|
|
133
|
+
// Wait for clipboard operation to complete
|
|
134
|
+
await self.getWaitHelper().forCondition(async () => {
|
|
135
|
+
try {
|
|
136
|
+
const currentClip = clipboard.readSync();
|
|
137
|
+
return currentClip !== originalClipboard || currentClip.length > 0;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}, { timeout: 2000, pollInterval: 50, message: 'Clipboard copy operation did not complete' });
|
|
134
143
|
const text = clipboard.readSync();
|
|
135
144
|
await inputarea.sendKeys(selenium_webdriver_1.Key.UP);
|
|
136
145
|
if (originalClipboard.length > 0) {
|
|
@@ -250,7 +259,11 @@ class TextEditor extends Editor_1.Editor {
|
|
|
250
259
|
}
|
|
251
260
|
actions = actions.keyUp(selenium_webdriver_1.Key.SHIFT);
|
|
252
261
|
await actions.perform();
|
|
253
|
-
|
|
262
|
+
// Wait for selection to be rendered
|
|
263
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
264
|
+
const selection = await this.findElements(TextEditor.locators.TextEditor.selection);
|
|
265
|
+
return selection.length > 0;
|
|
266
|
+
}, { timeout: 2000, pollInterval: 50, message: 'Text selection did not appear' });
|
|
254
267
|
}
|
|
255
268
|
/**
|
|
256
269
|
* Get the text that is currently selected as string
|
|
@@ -276,10 +289,18 @@ class TextEditor extends Editor_1.Editor {
|
|
|
276
289
|
else {
|
|
277
290
|
const inputarea = await this.findElement(TextEditor.locators.Editor.inputArea);
|
|
278
291
|
await inputarea.sendKeys(selenium_webdriver_1.Key.chord(TextEditor.ctlKey, 'c'));
|
|
279
|
-
await new Promise((res) => setTimeout(res, 500));
|
|
280
292
|
await inputarea.sendKeys(selenium_webdriver_1.Key.UP);
|
|
281
293
|
}
|
|
282
|
-
|
|
294
|
+
// Wait for clipboard operation to complete
|
|
295
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
296
|
+
try {
|
|
297
|
+
const currentClip = clipboard.readSync();
|
|
298
|
+
return currentClip !== originalClipboard;
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}, { timeout: 2000, pollInterval: 50, message: 'Copy operation did not complete' });
|
|
283
304
|
const text = clipboard.readSync();
|
|
284
305
|
if (originalClipboard.length > 0) {
|
|
285
306
|
clipboard.writeSync(originalClipboard);
|
|
@@ -334,7 +355,12 @@ class TextEditor extends Editor_1.Editor {
|
|
|
334
355
|
async setCursor(line, column, timeout = 2_500) {
|
|
335
356
|
const input = await new __1.Workbench().openCommandPrompt();
|
|
336
357
|
await input.setText(`:${line},${column}`);
|
|
337
|
-
|
|
358
|
+
// Wait for input to be processed - check for quick picks appearing
|
|
359
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
360
|
+
const picks = await input.getQuickPicks().catch(() => []);
|
|
361
|
+
return picks.length > 0;
|
|
362
|
+
}, { timeout: 1000, pollInterval: 50 });
|
|
363
|
+
await input.selectQuickPick(0);
|
|
338
364
|
await this.waitForCursorPositionAt(line, column, timeout);
|
|
339
365
|
}
|
|
340
366
|
/**
|
|
@@ -386,7 +412,8 @@ class TextEditor extends Editor_1.Editor {
|
|
|
386
412
|
}
|
|
387
413
|
await inputArea.getDriver().actions().clear();
|
|
388
414
|
await inputArea.sendKeys(lineKey);
|
|
389
|
-
|
|
415
|
+
// Minimal delay for key processing - this is a tight loop with position checking
|
|
416
|
+
await this.getWaitHelper().sleep(20);
|
|
390
417
|
}
|
|
391
418
|
}
|
|
392
419
|
/**
|
|
@@ -405,7 +432,8 @@ class TextEditor extends Editor_1.Editor {
|
|
|
405
432
|
}
|
|
406
433
|
await inputArea.getDriver().actions().clear();
|
|
407
434
|
await inputArea.sendKeys(columnKey);
|
|
408
|
-
|
|
435
|
+
// Minimal delay for key processing - this is a tight loop with position checking
|
|
436
|
+
await this.getWaitHelper().sleep(20);
|
|
409
437
|
if ((await this.getCoordinates())[0] !== coordinates[0]) {
|
|
410
438
|
throw new Error(`Column number ${column} is not accessible on line ${coordinates[0]}`);
|
|
411
439
|
}
|
|
@@ -538,7 +566,11 @@ class TextEditor extends Editor_1.Editor {
|
|
|
538
566
|
if (breakPoint.length > 0) {
|
|
539
567
|
if (this.breakPoints.indexOf(line) !== -1) {
|
|
540
568
|
await breakPoint[this.breakPoints.indexOf(line)].click();
|
|
541
|
-
|
|
569
|
+
// Wait for breakpoint to be removed
|
|
570
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
571
|
+
const remaining = await breakpointContainer.findElements(TextEditor.locators.TextEditor.breakpoint.generalSelector);
|
|
572
|
+
return remaining.length < breakPoint.length;
|
|
573
|
+
}, { timeout: 1000, pollInterval: 50 });
|
|
542
574
|
this.breakPoints.splice(this.breakPoints.indexOf(line), 1);
|
|
543
575
|
return false;
|
|
544
576
|
}
|
|
@@ -546,7 +578,11 @@ class TextEditor extends Editor_1.Editor {
|
|
|
546
578
|
const noBreak = await breakpointContainer.findElements(TextEditor.locators.TextEditor.debugHint);
|
|
547
579
|
if (noBreak.length > 0) {
|
|
548
580
|
await noBreak[0].click();
|
|
549
|
-
|
|
581
|
+
// Wait for breakpoint to be added
|
|
582
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
583
|
+
const added = await breakpointContainer.findElements(TextEditor.locators.TextEditor.breakpoint.generalSelector);
|
|
584
|
+
return added.length > breakPoint.length;
|
|
585
|
+
}, { timeout: 1000, pollInterval: 50 });
|
|
550
586
|
this.breakPoints.push(line);
|
|
551
587
|
return true;
|
|
552
588
|
}
|
|
@@ -587,8 +623,16 @@ class TextEditor extends Editor_1.Editor {
|
|
|
587
623
|
async getBreakpoint(line) {
|
|
588
624
|
const breakpoints = await this.getBreakpoints();
|
|
589
625
|
for (const breakpoint of breakpoints) {
|
|
590
|
-
|
|
591
|
-
|
|
626
|
+
try {
|
|
627
|
+
if ((await breakpoint.getLineNumber()) === line) {
|
|
628
|
+
return breakpoint;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
catch (e) {
|
|
632
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
throw e;
|
|
592
636
|
}
|
|
593
637
|
}
|
|
594
638
|
return undefined;
|
|
@@ -605,15 +649,23 @@ class TextEditor extends Editor_1.Editor {
|
|
|
605
649
|
: this;
|
|
606
650
|
const breakpointsSelectors = await breakpointContainer.findElements(breakpointLocators.generalSelector);
|
|
607
651
|
for (const breakpointSelector of breakpointsSelectors) {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
652
|
+
try {
|
|
653
|
+
let lineElement;
|
|
654
|
+
if ((0, compare_versions_1.satisfies)(TextEditor.versionInfo.version, '>=1.80.0')) {
|
|
655
|
+
const styleTopAttr = await breakpointSelector.getCssValue('top');
|
|
656
|
+
lineElement = await this.findElement(TextEditor.locators.TextEditor.marginArea).findElement(TextEditor.locators.TextEditor.lineElement(styleTopAttr));
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
lineElement = await breakpointSelector.findElement(TextEditor.locators.TextEditor.elementLevelBack);
|
|
660
|
+
}
|
|
661
|
+
breakpoints.push(new Breakpoint_1.Breakpoint(breakpointSelector, lineElement));
|
|
612
662
|
}
|
|
613
|
-
|
|
614
|
-
|
|
663
|
+
catch (e) {
|
|
664
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
throw e;
|
|
615
668
|
}
|
|
616
|
-
breakpoints.push(new Breakpoint_1.Breakpoint(breakpointSelector, lineElement));
|
|
617
669
|
}
|
|
618
670
|
return breakpoints;
|
|
619
671
|
}
|
|
@@ -626,7 +678,15 @@ class TextEditor extends Editor_1.Editor {
|
|
|
626
678
|
const widgets = await this.findElement(TextEditor.locators.TextEditor.contentWidgets);
|
|
627
679
|
const items = await widgets.findElements(TextEditor.locators.TextEditor.contentWidgetsElements);
|
|
628
680
|
for (const item of items) {
|
|
629
|
-
|
|
681
|
+
try {
|
|
682
|
+
lenses.push(await new CodeLens(item, this).wait());
|
|
683
|
+
}
|
|
684
|
+
catch (e) {
|
|
685
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
throw e;
|
|
689
|
+
}
|
|
630
690
|
}
|
|
631
691
|
return lenses;
|
|
632
692
|
}
|
|
@@ -640,10 +700,18 @@ class TextEditor extends Editor_1.Editor {
|
|
|
640
700
|
const lenses = await this.getCodeLenses();
|
|
641
701
|
if (typeof indexOrTitle === 'string') {
|
|
642
702
|
for (const lens of lenses) {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
703
|
+
try {
|
|
704
|
+
const title = await lens.getText();
|
|
705
|
+
const match = title.match(indexOrTitle);
|
|
706
|
+
if (match && match.length > 0) {
|
|
707
|
+
return lens;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
catch (e) {
|
|
711
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
throw e;
|
|
647
715
|
}
|
|
648
716
|
}
|
|
649
717
|
}
|
|
@@ -663,7 +731,33 @@ class Selection extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
663
731
|
}
|
|
664
732
|
async openContextMenu() {
|
|
665
733
|
const ed = this.getEnclosingElement();
|
|
666
|
-
|
|
734
|
+
// Selection elements can become stale easily. Retry with fresh element if needed.
|
|
735
|
+
let recoveredElement;
|
|
736
|
+
const maxRetries = 3;
|
|
737
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
738
|
+
try {
|
|
739
|
+
await this.getDriver()
|
|
740
|
+
.actions()
|
|
741
|
+
.contextClick(recoveredElement ?? this)
|
|
742
|
+
.perform();
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
catch (e) {
|
|
746
|
+
if (e.name === 'StaleElementReferenceError' && attempt < maxRetries - 1) {
|
|
747
|
+
// Re-fetch the selection element from the editor
|
|
748
|
+
const selections = await ed.findElements(TextEditor.locators.TextEditor.selection);
|
|
749
|
+
if (selections.length > 0) {
|
|
750
|
+
recoveredElement = selections[0];
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
throw e;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
throw e;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
667
761
|
const shadowRootHost = await ed.getEnclosingElement().findElements(TextEditor.locators.TextEditor.shadowRootHost);
|
|
668
762
|
if (shadowRootHost.length > 0) {
|
|
669
763
|
let shadowRoot;
|
|
@@ -858,7 +952,8 @@ class FindWidget extends AbstractElement_1.AbstractElement {
|
|
|
858
952
|
}
|
|
859
953
|
const btn = await element.findElement(FindWidget.locators.FindWidget.button(title));
|
|
860
954
|
await btn.click();
|
|
861
|
-
|
|
955
|
+
// Wait for button action to complete
|
|
956
|
+
await this.getWaitHelper().forStable(element, { timeout: 500 });
|
|
862
957
|
}
|
|
863
958
|
async setText(text, composite) {
|
|
864
959
|
const input = await composite.findElement(FindWidget.locators.FindWidget.input);
|
|
@@ -35,8 +35,16 @@ class ContextMenu extends __1.Menu {
|
|
|
35
35
|
try {
|
|
36
36
|
const items = await this.getItems();
|
|
37
37
|
for (const item of items) {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
try {
|
|
39
|
+
if ((await item.getLabel()) === name) {
|
|
40
|
+
return item;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
throw e;
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
}
|
|
@@ -52,9 +60,17 @@ class ContextMenu extends __1.Menu {
|
|
|
52
60
|
const items = [];
|
|
53
61
|
const elements = await this.findElements(ContextMenu.locators.ContextMenu.itemElement);
|
|
54
62
|
for (const element of elements) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
try {
|
|
64
|
+
const klass = await element.getAttribute('class');
|
|
65
|
+
if (klass.indexOf('disabled') < 0) {
|
|
66
|
+
items.push(await new ContextMenuItem(element, this).wait());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
throw e;
|
|
58
74
|
}
|
|
59
75
|
}
|
|
60
76
|
return items;
|
|
@@ -116,7 +132,12 @@ class ContextMenuItem extends __1.MenuItem {
|
|
|
116
132
|
}
|
|
117
133
|
async select() {
|
|
118
134
|
await this.click();
|
|
119
|
-
|
|
135
|
+
// Wait for click action to complete and potential submenu to appear
|
|
136
|
+
await this.getWaitHelper()
|
|
137
|
+
.forStable(this, { timeout: 1000 })
|
|
138
|
+
.catch(() => {
|
|
139
|
+
/* Element may be removed after click */
|
|
140
|
+
});
|
|
120
141
|
if (await this.isNesting()) {
|
|
121
142
|
return await new ContextMenu(this).wait();
|
|
122
143
|
}
|
|
@@ -32,7 +32,20 @@ class MenuItem extends AbstractElement_1.AbstractElement {
|
|
|
32
32
|
*/
|
|
33
33
|
async select() {
|
|
34
34
|
await this.click();
|
|
35
|
-
|
|
35
|
+
// Wait for click action to complete - menu may close after selection
|
|
36
|
+
await this.getWaitHelper()
|
|
37
|
+
.forCondition(async () => {
|
|
38
|
+
try {
|
|
39
|
+
// Check if element is still visible (menu might close)
|
|
40
|
+
return !(await this.isDisplayed());
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return true; // Element removed from DOM
|
|
44
|
+
}
|
|
45
|
+
}, { timeout: 1000, pollInterval: 50 })
|
|
46
|
+
.catch(() => {
|
|
47
|
+
/* Menu item may still be visible if it has submenu */
|
|
48
|
+
});
|
|
36
49
|
return undefined;
|
|
37
50
|
}
|
|
38
51
|
/**
|
|
@@ -50,8 +50,16 @@ class TitleBar extends Menu_1.Menu {
|
|
|
50
50
|
const items = [];
|
|
51
51
|
const elements = await this.findElements(TitleBar.locators.TitleBar.itemElement);
|
|
52
52
|
for (const element of elements) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
try {
|
|
54
|
+
if (await element.isDisplayed()) {
|
|
55
|
+
items.push(await new TitleBarItem(await element.getAttribute(TitleBar.locators.TitleBar.itemLabel), this).wait());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw e;
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
65
|
return items;
|
|
@@ -87,7 +95,11 @@ class TitleBarItem extends MenuItem_1.MenuItem {
|
|
|
87
95
|
await this.getDriver().actions().sendKeys(selenium_webdriver_1.Key.ESCAPE).perform();
|
|
88
96
|
}
|
|
89
97
|
await this.click();
|
|
90
|
-
|
|
98
|
+
// Wait for context menu to appear
|
|
99
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
100
|
+
const menus = await this.getDriver().findElements(TitleBar.locators.ContextMenu.constructor);
|
|
101
|
+
return menus.length > 0 && (await menus[0].isDisplayed());
|
|
102
|
+
}, { timeout: 2000, pollInterval: 50 });
|
|
91
103
|
return new __1.ContextMenu(this).wait();
|
|
92
104
|
}
|
|
93
105
|
}
|
|
@@ -50,7 +50,8 @@ class ViewSection extends AbstractElement_1.AbstractElement {
|
|
|
50
50
|
const collapseExpandButton = await header.findElement(ViewSection.locators.ViewSection.headerCollapseExpandButton);
|
|
51
51
|
await collapseExpandButton.click();
|
|
52
52
|
await this.getDriver().wait((0, __1.waitForAttributeValue)(header, ViewSection.locators.ViewSection.headerExpanded, 'true'), timeout);
|
|
53
|
-
|
|
53
|
+
// Wait for expand animation to complete
|
|
54
|
+
await this.getWaitHelper().forStable(this, { timeout: 1000 });
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
/**
|
|
@@ -66,7 +67,8 @@ class ViewSection extends AbstractElement_1.AbstractElement {
|
|
|
66
67
|
const collapseExpandButton = await header.findElement(ViewSection.locators.ViewSection.headerCollapseExpandButton);
|
|
67
68
|
await collapseExpandButton.click();
|
|
68
69
|
await this.getDriver().wait((0, __1.waitForAttributeValue)(header, ViewSection.locators.ViewSection.headerExpanded, 'false'), timeout);
|
|
69
|
-
|
|
70
|
+
// Wait for collapse animation to complete
|
|
71
|
+
await this.getWaitHelper().forStable(this, { timeout: 1000 });
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
/**
|
|
@@ -120,8 +122,16 @@ class ViewSection extends AbstractElement_1.AbstractElement {
|
|
|
120
122
|
async getAction(label) {
|
|
121
123
|
const actions = await this.getActions();
|
|
122
124
|
for (const action of actions) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
try {
|
|
126
|
+
if ((await action.getLabel()) === label) {
|
|
127
|
+
return action;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
throw e;
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
137
|
}
|
|
@@ -80,8 +80,16 @@ class WelcomeContentSection extends AbstractElement_1.AbstractElement {
|
|
|
80
80
|
async getButton(title) {
|
|
81
81
|
const buttons = await this.getButtons();
|
|
82
82
|
for (const btn of buttons) {
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
try {
|
|
84
|
+
if ((await btn.getTitle()) === title) {
|
|
85
|
+
return btn;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
throw e;
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
return undefined;
|
|
@@ -50,8 +50,16 @@ class DebugView extends SideBarView_1.SideBarView {
|
|
|
50
50
|
const configs = [];
|
|
51
51
|
const options = await combo.findElements(DebugView.locators.DebugView.launchOption);
|
|
52
52
|
for (const option of options) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
try {
|
|
54
|
+
if (await option.isEnabled()) {
|
|
55
|
+
configs.push(await option.getAttribute('value'));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw e;
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
65
|
return configs;
|