@redhat-developer/page-objects 1.17.0 → 1.18.1
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
|
@@ -65,7 +65,8 @@ class ExtensionsViewSection extends ViewSection_1.ViewSection {
|
|
|
65
65
|
throw err;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
// Wait for search to complete with a timeout to prevent hanging
|
|
69
|
+
await this.getDriver().wait(selenium_webdriver_1.until.elementIsNotVisible(progress), 30000);
|
|
69
70
|
const parent = this.enclosingItem;
|
|
70
71
|
const sectionTitle = this.getSectionForCategory(title);
|
|
71
72
|
const section = (await parent.getSection(sectionTitle));
|
|
@@ -75,8 +76,16 @@ class ExtensionsViewSection extends ViewSection_1.ViewSection {
|
|
|
75
76
|
}
|
|
76
77
|
const extensions = await section.getVisibleItems();
|
|
77
78
|
for (const extension of extensions) {
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
try {
|
|
80
|
+
if ((await extension.getTitle()) === title) {
|
|
81
|
+
return extension;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
throw e;
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
91
|
return undefined;
|
|
@@ -92,8 +101,14 @@ class ExtensionsViewSection extends ViewSection_1.ViewSection {
|
|
|
92
101
|
try {
|
|
93
102
|
await textField.findElement(ExtensionsViewSection.locators.ExtensionsViewSection.textField);
|
|
94
103
|
await searchField.sendKeys(selenium_webdriver_1.Key.chord(ExtensionsViewItem_1.ExtensionsViewItem.ctlKey, 'a'), selenium_webdriver_1.Key.BACK_SPACE);
|
|
95
|
-
|
|
96
|
-
|
|
104
|
+
// Add timeouts to prevent indefinite waits
|
|
105
|
+
try {
|
|
106
|
+
await this.getDriver().wait(selenium_webdriver_1.until.elementIsVisible(progress), 2000);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Progress indicator may not appear for quick operations
|
|
110
|
+
}
|
|
111
|
+
await this.getDriver().wait(selenium_webdriver_1.until.elementIsNotVisible(progress), 10000);
|
|
97
112
|
}
|
|
98
113
|
catch (err) {
|
|
99
114
|
// do nothing, the text field is empty
|
|
@@ -70,8 +70,16 @@ class SingleScmProvider extends ScmView_1.ScmProvider {
|
|
|
70
70
|
const titlePart = view.getTitlePart();
|
|
71
71
|
const elements = await titlePart.findElements(ScmView_1.ScmView.locators.ScmView.action);
|
|
72
72
|
for (const element of elements) {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
try {
|
|
74
|
+
const title = await element.getAttribute(ScmView_1.ScmView.locators.ScmView.actionLabel);
|
|
75
|
+
buttons.push(await new ViewTitlePart_1.TitleActionButton(ScmView_1.ScmView.locators.ScmView.actionConstructor(title), titlePart).wait());
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
throw e;
|
|
82
|
+
}
|
|
75
83
|
}
|
|
76
84
|
names = await Promise.all(buttons.map(async (button) => button.getTitle()));
|
|
77
85
|
}
|
|
@@ -108,9 +116,17 @@ class SingleScmProvider extends ScmView_1.ScmProvider {
|
|
|
108
116
|
const depth = +(await header.getAttribute('aria-level')) + 1;
|
|
109
117
|
const items = await this.findElements(NewScmView.locators.ScmView.itemLevel(depth));
|
|
110
118
|
for (const item of items) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
try {
|
|
120
|
+
const index = +(await item.getAttribute('data-index'));
|
|
121
|
+
if (index > startIndex && index <= startIndex + count) {
|
|
122
|
+
elements.push(item);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
throw e;
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
132
|
}
|
|
@@ -151,8 +167,16 @@ class MultiScmProvider extends ScmView_1.ScmProvider {
|
|
|
151
167
|
const headers = await this.enclosingItem.findElements(locator);
|
|
152
168
|
let header;
|
|
153
169
|
for (const item of headers) {
|
|
154
|
-
|
|
155
|
-
|
|
170
|
+
try {
|
|
171
|
+
if (+(await item.getAttribute('data-index')) > index) {
|
|
172
|
+
header = item;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
throw e;
|
|
156
180
|
}
|
|
157
181
|
}
|
|
158
182
|
if (!header) {
|
|
@@ -162,9 +186,17 @@ class MultiScmProvider extends ScmView_1.ScmProvider {
|
|
|
162
186
|
const depth = +(await header.getAttribute('aria-level')) + 1;
|
|
163
187
|
const items = await this.enclosingItem.findElements(NewScmView.locators.ScmView.itemLevel(depth));
|
|
164
188
|
for (const item of items) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
189
|
+
try {
|
|
190
|
+
const index = +(await item.getAttribute('data-index'));
|
|
191
|
+
if (index > startIndex && index <= startIndex + count) {
|
|
192
|
+
elements.push(item);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
throw e;
|
|
168
200
|
}
|
|
169
201
|
}
|
|
170
202
|
}
|
|
@@ -175,9 +207,17 @@ class MultiScmProvider extends ScmView_1.ScmProvider {
|
|
|
175
207
|
const rows = await this.enclosingItem.findElements(locator);
|
|
176
208
|
const index = +(await this.getAttribute('data-index'));
|
|
177
209
|
for (const row of rows) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
210
|
+
try {
|
|
211
|
+
if (+(await row.getAttribute('data-index')) > index) {
|
|
212
|
+
const count = await rows[0].findElement(ScmView_1.ScmChange.locators.ScmView.changeCount);
|
|
213
|
+
return +(await count.getText());
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
throw e;
|
|
181
221
|
}
|
|
182
222
|
}
|
|
183
223
|
return 0;
|
|
@@ -145,10 +145,18 @@ class ScmProvider extends AbstractElement_1.AbstractElement {
|
|
|
145
145
|
let i = -1;
|
|
146
146
|
elements = await this.findElements(ScmProvider.locators.ScmView.changeItem);
|
|
147
147
|
for (const [index, item] of elements.entries()) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
try {
|
|
149
|
+
const name = await item.findElement(ScmProvider.locators.ScmView.changeName);
|
|
150
|
+
if ((await name.getText()) === label) {
|
|
151
|
+
i = index + 1;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
throw e;
|
|
152
160
|
}
|
|
153
161
|
}
|
|
154
162
|
if (i < 0) {
|
|
@@ -57,9 +57,17 @@ class TreeSection extends ViewSection_1.ViewSection {
|
|
|
57
57
|
if (i + 1 < path.length) {
|
|
58
58
|
currentItem = undefined;
|
|
59
59
|
for (const item of items) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
try {
|
|
61
|
+
if ((await item.getLabel()) === path[i + 1]) {
|
|
62
|
+
currentItem = item;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
throw e;
|
|
63
71
|
}
|
|
64
72
|
}
|
|
65
73
|
}
|
|
@@ -42,8 +42,16 @@ class GenericCustomTreeSection extends TreeSection_1.TreeSection {
|
|
|
42
42
|
const container = await this.getContainer();
|
|
43
43
|
const elements = await container.findElements(CustomTreeSection.locators.CustomTreeSection.itemRow);
|
|
44
44
|
for (const element of elements) {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
try {
|
|
46
|
+
if (await element.isDisplayed()) {
|
|
47
|
+
items.push(new this.itemConstructor(element, this));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
throw e;
|
|
47
55
|
}
|
|
48
56
|
}
|
|
49
57
|
return items;
|
|
@@ -52,11 +60,19 @@ class GenericCustomTreeSection extends TreeSection_1.TreeSection {
|
|
|
52
60
|
const predicate = typeof labelOrPredicate === 'string' ? async (el) => (await el.getLabel()) === labelOrPredicate : labelOrPredicate;
|
|
53
61
|
const elements = await this.getVisibleItems();
|
|
54
62
|
for (const element of elements) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
try {
|
|
64
|
+
if (await predicate(element)) {
|
|
65
|
+
const level = +(await element.getAttribute(CustomTreeSection.locators.ViewSection.level));
|
|
66
|
+
if (maxLevel < 1 || level <= maxLevel) {
|
|
67
|
+
return element;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
73
|
+
continue;
|
|
59
74
|
}
|
|
75
|
+
throw e;
|
|
60
76
|
}
|
|
61
77
|
}
|
|
62
78
|
return undefined;
|
|
@@ -30,7 +30,11 @@ class WatchSection extends CustomTreeSection_1.GenericCustomTreeSection {
|
|
|
30
30
|
*/
|
|
31
31
|
async addItem(name) {
|
|
32
32
|
await (await this.getAction(WatchSection.locators.WatchSection.addExpression))?.click();
|
|
33
|
-
|
|
33
|
+
// Wait for input field to appear
|
|
34
|
+
await this.getWaitHelper().forCondition(async () => {
|
|
35
|
+
const inputs = await this.findElements(WatchSection.locators.WatchSection.input);
|
|
36
|
+
return inputs.length > 0;
|
|
37
|
+
}, { timeout: 3000, pollInterval: 100 });
|
|
34
38
|
const textInput = await this.findElement(WatchSection.locators.WatchSection.input);
|
|
35
39
|
await textInput.clear();
|
|
36
40
|
await textInput.sendKeys(name + selenium_webdriver_1.Key.ENTER);
|
|
@@ -28,7 +28,15 @@ class DefaultTreeSection extends TreeSection_1.TreeSection {
|
|
|
28
28
|
const items = [];
|
|
29
29
|
const elements = await this.findElements(DefaultTreeSection.locators.DefaultTreeSection.itemRow);
|
|
30
30
|
for (const element of elements) {
|
|
31
|
-
|
|
31
|
+
try {
|
|
32
|
+
items.push(await new DefaultTreeItem_1.DefaultTreeItem(element, this).wait());
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
throw e;
|
|
39
|
+
}
|
|
32
40
|
}
|
|
33
41
|
return items;
|
|
34
42
|
}
|
|
@@ -97,8 +97,16 @@ class Notification extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
97
97
|
const buttons = [];
|
|
98
98
|
const elements = await this.findElement(Notification.locators.Notification.actions).findElements(Notification.locators.Notification.action);
|
|
99
99
|
for (const button of elements) {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
try {
|
|
101
|
+
const title = await Notification.locators.Notification.actionLabel.value(button);
|
|
102
|
+
buttons.push(await new NotificationButton(Notification.locators.Notification.buttonConstructor(title), this).wait());
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
throw e;
|
|
109
|
+
}
|
|
102
110
|
}
|
|
103
111
|
return buttons;
|
|
104
112
|
}
|
|
@@ -61,9 +61,17 @@ class NotificationsCenter extends AbstractElement_1.AbstractElement {
|
|
|
61
61
|
const notifications = [];
|
|
62
62
|
const elements = await this.findElements(NotificationsCenter.locators.NotificationsCenter.row);
|
|
63
63
|
for (const element of elements) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
try {
|
|
65
|
+
const not = new Notification_1.CenterNotification(element);
|
|
66
|
+
if (type === Notification_1.NotificationType.Any || (await not.getType()) === type) {
|
|
67
|
+
notifications.push(await not.wait());
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
throw e;
|
|
67
75
|
}
|
|
68
76
|
}
|
|
69
77
|
return notifications;
|
|
@@ -88,7 +88,15 @@ class Workbench extends AbstractElement_1.AbstractElement {
|
|
|
88
88
|
}
|
|
89
89
|
const elements = await container.findElements(Workbench.locators.Workbench.notificationItem);
|
|
90
90
|
for (const element of elements) {
|
|
91
|
-
|
|
91
|
+
try {
|
|
92
|
+
notifications.push(await new Notification_1.StandaloneNotification(element).wait());
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
throw e;
|
|
99
|
+
}
|
|
92
100
|
}
|
|
93
101
|
return notifications;
|
|
94
102
|
}
|
|
@@ -105,11 +113,13 @@ class Workbench extends AbstractElement_1.AbstractElement {
|
|
|
105
113
|
* @returns promise that resolves to a SettingsEditor instance
|
|
106
114
|
*/
|
|
107
115
|
async openSettings() {
|
|
108
|
-
await this.executeCommand('
|
|
116
|
+
await this.executeCommand('Preferences: Open User Settings');
|
|
109
117
|
await new EditorView_1.EditorView().openEditor('Settings');
|
|
110
118
|
await Workbench.driver.wait(selenium_webdriver_1.until.elementLocated(Workbench.locators.Editor.constructor));
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
// Wait for settings editor to fully load
|
|
120
|
+
const editor = new SettingsEditor_1.SettingsEditor();
|
|
121
|
+
await this.getWaitHelper().forStable(editor, { timeout: 2000 });
|
|
122
|
+
return editor;
|
|
113
123
|
}
|
|
114
124
|
/**
|
|
115
125
|
* Open the VS Code command line prompt
|
|
@@ -50,7 +50,12 @@ class Input extends AbstractElement_1.AbstractElement {
|
|
|
50
50
|
}
|
|
51
51
|
const input = await this.findElement(Input.locators.Input.inputBox).findElement(Input.locators.Input.input);
|
|
52
52
|
await this.clear();
|
|
53
|
-
|
|
53
|
+
// Wait for clear operation to complete
|
|
54
|
+
await this.getWaitHelper()
|
|
55
|
+
.forCondition(async () => (await this.getText()).length === 0, { timeout: 1000, pollInterval: 50 })
|
|
56
|
+
.catch(() => {
|
|
57
|
+
/* Text may not be empty if clear didn't work fully */
|
|
58
|
+
});
|
|
54
59
|
if ((await this.getText()).length > 0) {
|
|
55
60
|
await input.sendKeys(selenium_webdriver_1.Key.END, selenium_webdriver_1.Key.chord(selenium_webdriver_1.Key.SHIFT, selenium_webdriver_1.Key.HOME));
|
|
56
61
|
}
|
|
@@ -152,21 +157,29 @@ class Input extends AbstractElement_1.AbstractElement {
|
|
|
152
157
|
while (!endReached) {
|
|
153
158
|
const picks = await this.getQuickPicks();
|
|
154
159
|
for (const pick of picks) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
try {
|
|
161
|
+
const lastRow = await this.findElements(Input.locators.DefaultTreeSection.lastRow);
|
|
162
|
+
if (lastRow.length > 0) {
|
|
163
|
+
endReached = true;
|
|
164
|
+
}
|
|
165
|
+
else if ((await pick.getAttribute('aria-posinset')) === (await pick.getAttribute('aria-setsize'))) {
|
|
166
|
+
endReached = true;
|
|
167
|
+
}
|
|
168
|
+
if (typeof indexOrText === 'string') {
|
|
169
|
+
const text = await pick.getLabel();
|
|
170
|
+
if (text.indexOf(indexOrText) > -1) {
|
|
171
|
+
return pick;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else if (indexOrText === pick.getIndex()) {
|
|
165
175
|
return pick;
|
|
166
176
|
}
|
|
167
177
|
}
|
|
168
|
-
|
|
169
|
-
|
|
178
|
+
catch (e) {
|
|
179
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
throw e;
|
|
170
183
|
}
|
|
171
184
|
}
|
|
172
185
|
if (!endReached) {
|
|
@@ -281,7 +294,15 @@ class QuickPickItem extends AbstractElement_1.AbstractElement {
|
|
|
281
294
|
const actions = [];
|
|
282
295
|
const elements = await this.findElements(Input.locators.Input.button);
|
|
283
296
|
for (const element of elements) {
|
|
284
|
-
|
|
297
|
+
try {
|
|
298
|
+
actions.push(await new QuickInputAction(element, this).wait());
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
throw e;
|
|
305
|
+
}
|
|
285
306
|
}
|
|
286
307
|
return actions;
|
|
287
308
|
}
|
|
@@ -293,8 +314,16 @@ class QuickPickItem extends AbstractElement_1.AbstractElement {
|
|
|
293
314
|
async getAction(label) {
|
|
294
315
|
const actions = await this.getActions();
|
|
295
316
|
for (const action of actions) {
|
|
296
|
-
|
|
297
|
-
|
|
317
|
+
try {
|
|
318
|
+
if ((await action.getLabel()) === label) {
|
|
319
|
+
return action;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (e) {
|
|
323
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
throw e;
|
|
298
327
|
}
|
|
299
328
|
}
|
|
300
329
|
}
|
|
@@ -51,8 +51,16 @@ class InputBox extends __1.Input {
|
|
|
51
51
|
.findElement(InputBox.locators.InputBox.rows)
|
|
52
52
|
.findElements(InputBox.locators.InputBox.row);
|
|
53
53
|
for (const element of elements) {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
try {
|
|
55
|
+
if (await element.isDisplayed()) {
|
|
56
|
+
picks.push(await new __1.QuickPickItem(+(await element.getAttribute('data-index')), this).wait());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
throw e;
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
return picks;
|
|
@@ -63,8 +71,16 @@ class InputBox extends __1.Input {
|
|
|
63
71
|
.findElement(InputBox.locators.InputBox.rows)
|
|
64
72
|
.findElements(InputBox.locators.InputBox.row);
|
|
65
73
|
for (const element of elements) {
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
try {
|
|
75
|
+
if (await element.isDisplayed()) {
|
|
76
|
+
picks.push(await new __1.QuickPickItem(+(await element.getAttribute('data-index')), this, true).wait());
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
throw e;
|
|
68
84
|
}
|
|
69
85
|
}
|
|
70
86
|
return picks;
|
|
@@ -44,9 +44,17 @@ class QuickOpenBox extends __1.Input {
|
|
|
44
44
|
const tree = await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(QuickOpenBox.locators.QuickOpenBox.quickList), 1000);
|
|
45
45
|
const elements = await tree.findElements(QuickOpenBox.locators.QuickOpenBox.row);
|
|
46
46
|
for (const element of elements) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
try {
|
|
48
|
+
const index = +(await element.getAttribute('aria-posinset'));
|
|
49
|
+
if (await element.isDisplayed()) {
|
|
50
|
+
picks.push(await new __1.QuickPickItem(index, this).wait());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (e.name === 'StaleElementReferenceError') {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
throw e;
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
return picks;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
3
|
+
* contributor license agreements. See the NOTICE file distributed with
|
|
4
|
+
* this work for additional information regarding copyright ownership.
|
|
5
|
+
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
6
|
+
* (the "License", destination); you may not use this file except in compliance with
|
|
7
|
+
* the License. You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Context information for debugging ExTester errors.
|
|
19
|
+
*/
|
|
20
|
+
export interface ErrorContext {
|
|
21
|
+
/** Name of the page object component (e.g., "TextEditor", "ActivityBar") */
|
|
22
|
+
component?: string;
|
|
23
|
+
/** The action being performed when the error occurred */
|
|
24
|
+
action?: string;
|
|
25
|
+
/** VS Code version being tested */
|
|
26
|
+
vscodeVersion?: string;
|
|
27
|
+
/** String representation of the locator used */
|
|
28
|
+
locator?: string;
|
|
29
|
+
/** Additional details about the element or operation */
|
|
30
|
+
details?: string;
|
|
31
|
+
/** The original error that caused this error, if any */
|
|
32
|
+
cause?: Error;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Base error class for all ExTester-specific errors.
|
|
36
|
+
* Provides rich context for debugging test failures.
|
|
37
|
+
*/
|
|
38
|
+
export declare class ExTesterError extends Error {
|
|
39
|
+
readonly context: ErrorContext;
|
|
40
|
+
readonly timestamp: Date;
|
|
41
|
+
constructor(message: string, context?: ErrorContext);
|
|
42
|
+
/**
|
|
43
|
+
* Get a detailed string representation of the error for logging.
|
|
44
|
+
*/
|
|
45
|
+
toDetailedString(): string;
|
|
46
|
+
toString(): string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Error thrown when an element cannot be found in the DOM.
|
|
50
|
+
*/
|
|
51
|
+
export declare class ElementNotFoundError extends ExTesterError {
|
|
52
|
+
constructor(message: string, context?: ErrorContext);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Error thrown when an element exists but is not visible.
|
|
56
|
+
*/
|
|
57
|
+
export declare class ElementNotVisibleError extends ExTesterError {
|
|
58
|
+
constructor(message: string, context?: ErrorContext);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Error thrown when an element cannot be interacted with (e.g., blocked, disabled).
|
|
62
|
+
*/
|
|
63
|
+
export declare class ElementNotInteractableError extends ExTesterError {
|
|
64
|
+
constructor(message: string, context?: ErrorContext);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Error thrown when an element reference has become stale (DOM was modified).
|
|
68
|
+
*/
|
|
69
|
+
export declare class StaleElementError extends ExTesterError {
|
|
70
|
+
constructor(message: string, context?: ErrorContext);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Error thrown when element recovery/reinitialization fails.
|
|
74
|
+
*/
|
|
75
|
+
export declare class ElementRecoveryError extends ExTesterError {
|
|
76
|
+
constructor(message: string, context?: ErrorContext);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Error thrown when a timeout occurs waiting for a condition.
|
|
80
|
+
*/
|
|
81
|
+
export declare class TimeoutError extends ExTesterError {
|
|
82
|
+
readonly timeoutMs: number;
|
|
83
|
+
constructor(message: string, timeoutMs: number, context?: ErrorContext);
|
|
84
|
+
toDetailedString(): string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Error thrown when a locator fails to match any elements.
|
|
88
|
+
*/
|
|
89
|
+
export declare class LocatorError extends ExTesterError {
|
|
90
|
+
constructor(message: string, context?: ErrorContext);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Error thrown for platform-specific limitations (e.g., macOS native dialogs).
|
|
94
|
+
*/
|
|
95
|
+
export declare class PlatformNotSupportedError extends ExTesterError {
|
|
96
|
+
readonly platform: string;
|
|
97
|
+
constructor(message: string, platform?: string, context?: ErrorContext);
|
|
98
|
+
toDetailedString(): string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Error thrown when an operation is not supported for the current VS Code version.
|
|
102
|
+
*/
|
|
103
|
+
export declare class VersionNotSupportedError extends ExTesterError {
|
|
104
|
+
readonly requiredVersion: string;
|
|
105
|
+
readonly currentVersion: string;
|
|
106
|
+
constructor(message: string, requiredVersion: string, currentVersion: string, context?: ErrorContext);
|
|
107
|
+
toDetailedString(): string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Utility to wrap native Selenium errors with ExTester context.
|
|
111
|
+
*/
|
|
112
|
+
export declare function wrapError(originalError: Error, context: ErrorContext): ExTesterError;
|