@redhat-developer/page-objects 1.20.0 → 1.22.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 +1 -1
- package/out/components/AbstractElement.js +3 -2
- package/out/components/ElementWithContextMenu.d.ts +11 -0
- package/out/components/ElementWithContextMenu.js +63 -15
- package/out/components/WebviewMixin.js +73 -7
- package/out/components/activityBar/ActionsControl.js +1 -1
- package/out/components/activityBar/ViewControl.d.ts +16 -0
- package/out/components/activityBar/ViewControl.js +45 -8
- package/out/components/bottomBar/AbstractViews.js +2 -2
- package/out/components/bottomBar/BottomBarPanel.js +26 -11
- package/out/components/bottomBar/ProblemsView.js +2 -2
- package/out/components/bottomBar/Views.js +1 -1
- package/out/components/editor/ContentAssist.d.ts +9 -1
- package/out/components/editor/ContentAssist.js +98 -20
- package/out/components/editor/CustomEditor.js +2 -2
- package/out/components/editor/EditorAction.js +1 -1
- package/out/components/editor/EditorView.d.ts +6 -0
- package/out/components/editor/EditorView.js +73 -3
- package/out/components/editor/SettingsEditor.d.ts +1 -0
- package/out/components/editor/SettingsEditor.js +20 -4
- package/out/components/editor/TextEditor.d.ts +4 -1
- package/out/components/editor/TextEditor.js +99 -62
- package/out/components/editor/WebView.js +6 -1
- package/out/components/menu/ContextMenu.d.ts +1 -1
- package/out/components/menu/ContextMenu.js +9 -6
- package/out/components/menu/Menu.js +3 -1
- package/out/components/menu/TitleBar.js +1 -1
- package/out/components/sidebar/ViewItem.js +1 -0
- package/out/components/sidebar/ViewSection.js +2 -2
- package/out/components/sidebar/ViewTitlePart.js +2 -2
- package/out/components/sidebar/debug/DebugView.d.ts +10 -0
- package/out/components/sidebar/debug/DebugView.js +45 -13
- package/out/components/sidebar/extensions/ExtensionsViewItem.js +1 -1
- package/out/components/sidebar/scm/NewScmView.js +1 -1
- package/out/components/sidebar/scm/ScmView.js +2 -2
- package/out/components/sidebar/tree/custom/CustomTreeItem.js +2 -1
- package/out/components/sidebar/tree/debug/CallStackItem.js +1 -1
- package/out/components/sidebar/tree/debug/WatchSectionItem.js +1 -1
- package/out/components/sidebar/tree/default/DefaultTreeItem.js +3 -3
- package/out/components/sidebar/tree/default/DefaultTreeSection.js +6 -0
- package/out/components/statusBar/StatusBar.js +2 -2
- package/out/components/workbench/DebugToolbar.js +1 -1
- package/out/components/workbench/Notification.js +3 -3
- package/out/components/workbench/NotificationsCenter.js +6 -1
- package/out/components/workbench/Workbench.js +1 -1
- package/out/components/workbench/input/Input.d.ts +18 -0
- package/out/components/workbench/input/Input.js +70 -2
- package/out/components/workbench/input/InputBox.js +2 -2
- package/out/components/workbench/input/QuickOpenBox.js +2 -2
- package/out/errors/ExTesterError.js +1 -1
- package/out/index.d.ts +3 -1
- package/out/index.js +33 -3
- package/out/locators/loader.d.ts +2 -1
- package/out/locators/loader.js +2 -2
- package/out/locators/locators.d.ts +5 -2
- package/out/locators/locators.js +28 -5
- package/out/utils/TimeoutConstants.d.ts +59 -0
- package/out/utils/TimeoutConstants.js +63 -0
- package/out/utils/WaitHelper.js +8 -2
- package/package.json +8 -6
|
@@ -68,6 +68,7 @@ class TreeItem extends ViewItem {
|
|
|
68
68
|
async expand() {
|
|
69
69
|
if ((await this.isExpandable()) && !(await this.isExpanded())) {
|
|
70
70
|
await (await this.findTwistie()).click();
|
|
71
|
+
await this.getDriver().wait(() => this.isExpanded(), 5000, 'Tree item did not expand within 5s');
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
/**
|
|
@@ -35,7 +35,7 @@ class ViewSection extends AbstractElement_1.AbstractElement {
|
|
|
35
35
|
*/
|
|
36
36
|
async getTitle() {
|
|
37
37
|
const title = await this.findElement(ViewSection.locators.ViewSection.title);
|
|
38
|
-
return await title.getAttribute(ViewSection.locators.ViewSection.titleText);
|
|
38
|
+
return (await title.getAttribute(ViewSection.locators.ViewSection.titleText));
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Expand the section if collapsed
|
|
@@ -186,7 +186,7 @@ class BaseViewPanelAction extends ActionButtonElementDropdown_1.ActionButtonElem
|
|
|
186
186
|
* Get label of the action button
|
|
187
187
|
*/
|
|
188
188
|
async getLabel() {
|
|
189
|
-
return await this.getAttribute(BaseViewPanelAction.locators.ViewSection.buttonLabel);
|
|
189
|
+
return (await this.getAttribute(BaseViewPanelAction.locators.ViewSection.buttonLabel));
|
|
190
190
|
}
|
|
191
191
|
/**
|
|
192
192
|
* Wait for the action button to be located within a given timeout.
|
|
@@ -42,7 +42,7 @@ class ViewTitlePart extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
42
42
|
const actions = [];
|
|
43
43
|
const elements = await this.findElements(ViewTitlePart.locators.ViewTitlePart.action);
|
|
44
44
|
for (const element of elements) {
|
|
45
|
-
const title = await element.getAttribute(ViewTitlePart.locators.ViewTitlePart.actionLabel);
|
|
45
|
+
const title = (await element.getAttribute(ViewTitlePart.locators.ViewTitlePart.actionLabel));
|
|
46
46
|
actions.push(await new TitleActionButton(TitleActionButton.locators.ViewTitlePart.actionConstructor(title), this).wait());
|
|
47
47
|
}
|
|
48
48
|
return actions;
|
|
@@ -68,7 +68,7 @@ class TitleActionButton extends AbstractElement_1.AbstractElement {
|
|
|
68
68
|
* Get title of the button
|
|
69
69
|
*/
|
|
70
70
|
async getTitle() {
|
|
71
|
-
return await this.getAttribute(TitleActionButton.locators.ViewTitlePart.actionLabel);
|
|
71
|
+
return (await this.getAttribute(TitleActionButton.locators.ViewTitlePart.actionLabel));
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
exports.TitleActionButton = TitleActionButton;
|
|
@@ -45,6 +45,16 @@ export declare class DebugView extends SideBarView {
|
|
|
45
45
|
* @param title title of the configuration to select
|
|
46
46
|
*/
|
|
47
47
|
selectLaunchConfiguration(title: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Opens the launch config dropdown overlay, waiting until it is visible.
|
|
50
|
+
* If it is already open (context-view-pointerBlock present) the click is skipped.
|
|
51
|
+
* @returns the context-view element to scope subsequent searches against
|
|
52
|
+
*/
|
|
53
|
+
private openLaunchDropdown;
|
|
54
|
+
/**
|
|
55
|
+
* Closes the launch config dropdown by sending Escape to the filter input that holds focus.
|
|
56
|
+
*/
|
|
57
|
+
private closeLaunchDropdown;
|
|
48
58
|
/**
|
|
49
59
|
* Start Debugging using the current launch configuration
|
|
50
60
|
*/
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.DebugView = void 0;
|
|
20
20
|
const compare_versions_1 = require("compare-versions");
|
|
21
|
+
const selenium_webdriver_1 = require("selenium-webdriver");
|
|
21
22
|
const SideBarView_1 = require("../SideBarView");
|
|
22
23
|
const DebugBreakpointSection_1 = require("../tree/debug/DebugBreakpointSection");
|
|
23
24
|
const DebugCallStackSection_1 = require("../tree/debug/DebugCallStackSection");
|
|
@@ -34,26 +35,22 @@ class DebugView extends SideBarView_1.SideBarView {
|
|
|
34
35
|
*/
|
|
35
36
|
async getLaunchConfiguration() {
|
|
36
37
|
if ((0, compare_versions_1.satisfies)(DebugView.versionInfo.version, '>=1.87.0') && process.platform !== 'darwin') {
|
|
37
|
-
throw Error(`DEPRECATED METHOD! The 'DebugView.getLaunchConfiguration' method is broken! Read more information in 'Known Issues > Limitations in testing with VS Code 1.87+' - https://github.com/microsoft/vscode/issues/206897.`);
|
|
38
|
+
throw new Error(`DEPRECATED METHOD! The 'DebugView.getLaunchConfiguration' method is broken! Read more information in 'Known Issues > Limitations in testing with VS Code 1.87+' - https://github.com/microsoft/vscode/issues/206897.`);
|
|
38
39
|
}
|
|
39
40
|
const action = await this.getTitlePart().findElement(DebugView.locators.DebugView.launchCombo);
|
|
40
|
-
|
|
41
|
-
return await combo.getAttribute(DebugView.locators.DebugView.launchSelectAttribute);
|
|
41
|
+
return await action.getText();
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* Get titles of all available launch configurations
|
|
45
45
|
* @returns Promise resolving to list of titles
|
|
46
46
|
*/
|
|
47
47
|
async getLaunchConfigurations() {
|
|
48
|
-
const
|
|
49
|
-
const combo = await action.findElement(DebugView.locators.DebugView.launchSelect);
|
|
48
|
+
const contextView = await this.openLaunchDropdown();
|
|
50
49
|
const configs = [];
|
|
51
|
-
const options = await
|
|
50
|
+
const options = await contextView.findElements(DebugView.locators.DebugView.launchOption);
|
|
52
51
|
for (const option of options) {
|
|
53
52
|
try {
|
|
54
|
-
|
|
55
|
-
configs.push(await option.getAttribute('value'));
|
|
56
|
-
}
|
|
53
|
+
configs.push((await option.getAttribute(DebugView.locators.DebugView.launchSelectAttribute)));
|
|
57
54
|
}
|
|
58
55
|
catch (e) {
|
|
59
56
|
if (e.name === 'StaleElementReferenceError') {
|
|
@@ -62,6 +59,7 @@ class DebugView extends SideBarView_1.SideBarView {
|
|
|
62
59
|
throw e;
|
|
63
60
|
}
|
|
64
61
|
}
|
|
62
|
+
await this.closeLaunchDropdown();
|
|
65
63
|
return configs;
|
|
66
64
|
}
|
|
67
65
|
async getVariablesSection() {
|
|
@@ -81,10 +79,44 @@ class DebugView extends SideBarView_1.SideBarView {
|
|
|
81
79
|
* @param title title of the configuration to select
|
|
82
80
|
*/
|
|
83
81
|
async selectLaunchConfiguration(title) {
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
const contextView = await this.openLaunchDropdown();
|
|
83
|
+
const option = await contextView.findElement(DebugView.locators.DebugView.optionByName(title));
|
|
84
|
+
// context-view-pointerBlock overlays the list and intercepts regular clicks —
|
|
85
|
+
// use JavaScript click to bypass it.
|
|
86
|
+
await this.getDriver().executeScript('arguments[0].click()', option);
|
|
87
|
+
// Wait for the overlay to be dismissed so subsequent operations are not blocked.
|
|
88
|
+
await this.getDriver()
|
|
89
|
+
.wait(selenium_webdriver_1.until.elementIsNotVisible(contextView), 2000)
|
|
90
|
+
.catch(() => {
|
|
91
|
+
// If already gone, that's fine.
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Opens the launch config dropdown overlay, waiting until it is visible.
|
|
96
|
+
* If it is already open (context-view-pointerBlock present) the click is skipped.
|
|
97
|
+
* @returns the context-view element to scope subsequent searches against
|
|
98
|
+
*/
|
|
99
|
+
async openLaunchDropdown() {
|
|
100
|
+
// context-view persists in the DOM between uses (display:none when closed).
|
|
101
|
+
// Only click to open if it is not currently visible.
|
|
102
|
+
const existingViews = await this.getDriver().findElements(DebugView.locators.ContextMenu.contextView);
|
|
103
|
+
const isOpen = existingViews.length > 0 && (await existingViews[0].isDisplayed());
|
|
104
|
+
if (!isOpen) {
|
|
105
|
+
const action = await this.getTitlePart().findElement(DebugView.locators.DebugView.launchCombo);
|
|
106
|
+
await action.click();
|
|
107
|
+
}
|
|
108
|
+
const contextView = await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(DebugView.locators.ContextMenu.contextView), 2000);
|
|
109
|
+
await this.getDriver().wait(selenium_webdriver_1.until.elementIsVisible(contextView), 2000);
|
|
110
|
+
// Wait until at least one option row is present inside the overlay
|
|
111
|
+
await this.getDriver().wait(async () => (await contextView.findElements(DebugView.locators.DebugView.launchOption)).length > 0, 2000);
|
|
112
|
+
return contextView;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Closes the launch config dropdown by sending Escape to the filter input that holds focus.
|
|
116
|
+
*/
|
|
117
|
+
async closeLaunchDropdown() {
|
|
118
|
+
const input = await this.getDriver().findElement(selenium_webdriver_1.By.className('action-list-filter-input'));
|
|
119
|
+
await input.sendKeys('\uE00C'); // Escape
|
|
88
120
|
}
|
|
89
121
|
/**
|
|
90
122
|
* Start Debugging using the current launch configuration
|
|
@@ -42,7 +42,7 @@ class ExtensionsViewItem extends ViewItem_1.ViewItem {
|
|
|
42
42
|
if (version.length > 0) {
|
|
43
43
|
return await version[0].getText();
|
|
44
44
|
}
|
|
45
|
-
const label = await this.getAttribute('aria-label');
|
|
45
|
+
const label = (await this.getAttribute('aria-label'));
|
|
46
46
|
const ver = label.split(',')[1].trim();
|
|
47
47
|
return ver;
|
|
48
48
|
}
|
|
@@ -64,7 +64,7 @@ class SingleScmProvider extends ScmView_1.ScmProvider {
|
|
|
64
64
|
const buttons = [];
|
|
65
65
|
if ((0, compare_versions_1.satisfies)(ScmView_1.ScmProvider.versionInfo.version, '>=1.93.0')) {
|
|
66
66
|
actions = await this.getProviderHeaderActions(view);
|
|
67
|
-
names = await Promise.all(actions.map(async (action) => await action.getAttribute(ScmView_1.ScmProvider.locators.ScmView.actionLabel)));
|
|
67
|
+
names = await Promise.all(actions.map(async (action) => (await action.getAttribute(ScmView_1.ScmProvider.locators.ScmView.actionLabel))));
|
|
68
68
|
}
|
|
69
69
|
else {
|
|
70
70
|
const titlePart = view.getTitlePart();
|
|
@@ -75,13 +75,13 @@ class ScmProvider extends AbstractElement_1.AbstractElement {
|
|
|
75
75
|
* Get title of the scm provider
|
|
76
76
|
*/
|
|
77
77
|
async getTitle() {
|
|
78
|
-
return await this.findElement(ScmProvider.locators.ScmView.providerTitle).getAttribute('innerHTML');
|
|
78
|
+
return (await this.findElement(ScmProvider.locators.ScmView.providerTitle).getAttribute('innerHTML'));
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Get type of the scm provider (e.g. Git)
|
|
82
82
|
*/
|
|
83
83
|
async getType() {
|
|
84
|
-
return await this.findElement(ScmProvider.locators.ScmView.providerType).getAttribute('innerHTML');
|
|
84
|
+
return (await this.findElement(ScmProvider.locators.ScmView.providerType).getAttribute('innerHTML'));
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
87
|
* Find an action button for the SCM provider by title and click it. (e.g 'Commit')
|
|
@@ -29,7 +29,8 @@ class CustomTreeItem extends ViewItem_1.TreeItem {
|
|
|
29
29
|
return await this.findElement(CustomTreeItem.locators.CustomTreeSection.itemLabel).getText();
|
|
30
30
|
}
|
|
31
31
|
async getTooltip() {
|
|
32
|
-
|
|
32
|
+
const resourceItem = await this.findElement(CustomTreeItem.locators.CustomTreeItem.tooltipElement);
|
|
33
|
+
return (await resourceItem.getAttribute(CustomTreeItem.locators.CustomTreeItem.tooltipAttribute));
|
|
33
34
|
}
|
|
34
35
|
async getDescription() {
|
|
35
36
|
return await this.findElement(CustomTreeItem.locators.CustomTreeItem.description).getText();
|
|
@@ -28,7 +28,7 @@ class CallStackItem extends CustomTreeItem_1.CustomTreeItem {
|
|
|
28
28
|
*/
|
|
29
29
|
async getLabel() {
|
|
30
30
|
const name = await this.findElement(CallStackItem.locators.CallStackItem.label);
|
|
31
|
-
return await name?.getAttribute('textContent');
|
|
31
|
+
return (await name?.getAttribute('textContent'));
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Get text of the Call Stack item.
|
|
@@ -28,7 +28,7 @@ class WatchSectionItem extends CustomTreeItem_1.CustomTreeItem {
|
|
|
28
28
|
*/
|
|
29
29
|
async getLabel() {
|
|
30
30
|
const name = await this.findElement(WatchSectionItem.locators.WatchSectionItem.label);
|
|
31
|
-
return await name?.getAttribute('textContent');
|
|
31
|
+
return (await name?.getAttribute('textContent'));
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Get value of the Watch section item.
|
|
@@ -35,10 +35,10 @@ class DefaultTreeItem extends ViewItem_1.TreeItem {
|
|
|
35
35
|
}
|
|
36
36
|
async getTooltip() {
|
|
37
37
|
const tooltip = await this.findElement(DefaultTreeItem.locators.DefaultTreeItem.tooltip);
|
|
38
|
-
return await tooltip.getAttribute(DefaultTreeItem.locators.DefaultTreeItem.labelAttribute);
|
|
38
|
+
return (await tooltip.getAttribute(DefaultTreeItem.locators.DefaultTreeItem.labelAttribute));
|
|
39
39
|
}
|
|
40
40
|
async isExpanded() {
|
|
41
|
-
const twistieClass = await this.findElement(DefaultTreeItem.locators.DefaultTreeItem.twistie).getAttribute('class');
|
|
41
|
+
const twistieClass = (await this.findElement(DefaultTreeItem.locators.DefaultTreeItem.twistie).getAttribute('class'));
|
|
42
42
|
return twistieClass.indexOf('collapsed') < 0;
|
|
43
43
|
}
|
|
44
44
|
async getChildren() {
|
|
@@ -47,7 +47,7 @@ class DefaultTreeItem extends ViewItem_1.TreeItem {
|
|
|
47
47
|
return items;
|
|
48
48
|
}
|
|
49
49
|
async isExpandable() {
|
|
50
|
-
const twistieClass = await this.findElement(DefaultTreeItem.locators.DefaultTreeItem.twistie).getAttribute('class');
|
|
50
|
+
const twistieClass = (await this.findElement(DefaultTreeItem.locators.DefaultTreeItem.twistie).getAttribute('class'));
|
|
51
51
|
return twistieClass.indexOf('collapsible') > -1;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -45,7 +45,13 @@ class DefaultTreeSection extends TreeSection_1.TreeSection {
|
|
|
45
45
|
const container = await this.findElement(DefaultTreeSection.locators.DefaultTreeSection.rowContainer);
|
|
46
46
|
await container.sendKeys(selenium_webdriver_1.Key.HOME);
|
|
47
47
|
let item = undefined;
|
|
48
|
+
const maxIterations = 500;
|
|
49
|
+
let iteration = 0;
|
|
48
50
|
do {
|
|
51
|
+
if (iteration++ >= maxIterations) {
|
|
52
|
+
console.warn(`findItem('${label}'): exceeded ${maxIterations} scroll iterations, giving up`);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
49
55
|
const temp = await container.findElements(DefaultTreeSection.locators.DefaultTreeItem.ctor(label));
|
|
50
56
|
if (temp.length > 0) {
|
|
51
57
|
const level = +(await temp[0].getAttribute(DefaultTreeSection.locators.ViewSection.level));
|
|
@@ -157,7 +157,7 @@ class StatusBar extends AbstractElement_1.AbstractElement {
|
|
|
157
157
|
async toggleNotificationsCentre(open) {
|
|
158
158
|
let visible = false;
|
|
159
159
|
try {
|
|
160
|
-
const klass = await this.enclosingItem.findElement(StatusBar.locators.StatusBar.notifications).getAttribute('class');
|
|
160
|
+
const klass = (await this.enclosingItem.findElement(StatusBar.locators.StatusBar.notifications).getAttribute('class'));
|
|
161
161
|
visible = klass.indexOf('visible') > -1;
|
|
162
162
|
}
|
|
163
163
|
catch (err) {
|
|
@@ -168,7 +168,7 @@ class StatusBar extends AbstractElement_1.AbstractElement {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
async getPartText(locator) {
|
|
171
|
-
return await this.findElement(locator).findElement(StatusBar.locators.StatusBar.aTag).getAttribute('innerHTML');
|
|
171
|
+
return (await this.findElement(locator).findElement(StatusBar.locators.StatusBar.aTag).getAttribute('innerHTML'));
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
exports.StatusBar = StatusBar;
|
|
@@ -42,7 +42,7 @@ class DebugToolbar extends AbstractElement_1.AbstractElement {
|
|
|
42
42
|
* Wait for the execution to pause at the next breakpoint
|
|
43
43
|
*/
|
|
44
44
|
async waitForBreakPoint(timeout = 10_000) {
|
|
45
|
-
let btn = await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(DebugToolbar.locators.DebugToolbar.button('continue')));
|
|
45
|
+
let btn = await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(DebugToolbar.locators.DebugToolbar.button('continue')), timeout);
|
|
46
46
|
await this.getDriver().wait(async () => {
|
|
47
47
|
try {
|
|
48
48
|
const enabled = await btn.isEnabled();
|
|
@@ -47,7 +47,7 @@ class Notification extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
47
47
|
* @returns Promise resolving to NotificationType
|
|
48
48
|
*/
|
|
49
49
|
async getType() {
|
|
50
|
-
const iconType = await (await this.findElement(Notification.locators.Notification.icon)).getAttribute('class');
|
|
50
|
+
const iconType = (await (await this.findElement(Notification.locators.Notification.icon)).getAttribute('class'));
|
|
51
51
|
if (iconType.indexOf('icon-info') > -1) {
|
|
52
52
|
return NotificationType.Info;
|
|
53
53
|
}
|
|
@@ -68,14 +68,14 @@ class Notification extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
68
68
|
throw Error(`DEPRECATED METHOD! For VS Code 1.88+ this method won't be working any more.`);
|
|
69
69
|
}
|
|
70
70
|
await this.expand();
|
|
71
|
-
return await (await this.findElement(Notification.locators.Notification.source)).getAttribute('title');
|
|
71
|
+
return (await (await this.findElement(Notification.locators.Notification.source)).getAttribute('title'));
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
74
|
* Find whether the notification has an active progress bar
|
|
75
75
|
* @returns Promise resolving to true/false
|
|
76
76
|
*/
|
|
77
77
|
async hasProgress() {
|
|
78
|
-
const klass = await (await this.findElement(Notification.locators.Notification.progress)).getAttribute('class');
|
|
78
|
+
const klass = (await (await this.findElement(Notification.locators.Notification.progress)).getAttribute('class'));
|
|
79
79
|
return klass.indexOf('done') < 0;
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
@@ -48,7 +48,12 @@ class NotificationsCenter extends AbstractElement_1.AbstractElement {
|
|
|
48
48
|
* @returns Promise resolving when the clear all button is pressed
|
|
49
49
|
*/
|
|
50
50
|
async clearAllNotifications() {
|
|
51
|
-
await this.findElement(NotificationsCenter.locators.NotificationsCenter.clear)
|
|
51
|
+
const btn = await this.findElement(NotificationsCenter.locators.NotificationsCenter.clear);
|
|
52
|
+
const classes = (await btn.getAttribute('class')) ?? '';
|
|
53
|
+
if (classes.includes('disabled')) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
await this.getDriver().executeScript('arguments[0].click()', btn);
|
|
52
57
|
}
|
|
53
58
|
/**
|
|
54
59
|
* Get all notifications of a given type
|
|
@@ -115,7 +115,7 @@ class Workbench extends AbstractElement_1.AbstractElement {
|
|
|
115
115
|
async openSettings() {
|
|
116
116
|
await this.executeCommand('Preferences: Open User Settings');
|
|
117
117
|
await new EditorView_1.EditorView().openEditor('Settings');
|
|
118
|
-
await Workbench.driver.wait(selenium_webdriver_1.until.elementLocated(Workbench.locators.Editor.constructor));
|
|
118
|
+
await Workbench.driver.wait(selenium_webdriver_1.until.elementLocated(Workbench.locators.Editor.constructor), 10_000);
|
|
119
119
|
// Wait for settings editor to fully load
|
|
120
120
|
const editor = new SettingsEditor_1.SettingsEditor();
|
|
121
121
|
await this.getWaitHelper().forStable(editor, { timeout: 2000 });
|
|
@@ -41,6 +41,24 @@ export declare abstract class Input extends AbstractElement {
|
|
|
41
41
|
* @returns Promise resolving when the input is confirmed
|
|
42
42
|
*/
|
|
43
43
|
confirm(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Confirm path selection for file/folder dialog.
|
|
46
|
+
*
|
|
47
|
+
* VS Code's file picker auto-navigates as text is typed: when a full path such as
|
|
48
|
+
* `/dir/file.txt` is in the input, the picker shows the parent directory contents
|
|
49
|
+
* with the filename filtered in the list. A single Enter press navigates into the
|
|
50
|
+
* matched list entry. A subsequent click on the OK button (or a second Enter) then
|
|
51
|
+
* confirms the selection and closes the dialog.
|
|
52
|
+
*
|
|
53
|
+
* When the path is not formatted to OS specifics there may first be a 'Select' step.
|
|
54
|
+
* See also https://github.com/redhat-developer/vscode-extension-tester/issues/1778
|
|
55
|
+
*/
|
|
56
|
+
confirmPath(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Best-effort check whether this input/picker widget is still displayed.
|
|
59
|
+
* A hidden, detached or stale widget counts as closed.
|
|
60
|
+
*/
|
|
61
|
+
private isPickerOpen;
|
|
44
62
|
/**
|
|
45
63
|
* Cancel the input field by pressing Escape
|
|
46
64
|
* @returns Promise resolving when the input is cancelled
|
|
@@ -31,7 +31,7 @@ class Input extends AbstractElement_1.AbstractElement {
|
|
|
31
31
|
*/
|
|
32
32
|
async getText() {
|
|
33
33
|
const input = await this.findElement(Input.locators.Input.inputBox).findElement(Input.locators.Input.input);
|
|
34
|
-
return await input.getAttribute('value');
|
|
34
|
+
return (await input.getAttribute('value'));
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Set (by selecting all and typing) text in the input field
|
|
@@ -75,7 +75,7 @@ class Input extends AbstractElement_1.AbstractElement {
|
|
|
75
75
|
* @returns Promise resolving to input placeholder
|
|
76
76
|
*/
|
|
77
77
|
async getPlaceHolder() {
|
|
78
|
-
return await this.findElement(Input.locators.Input.inputBox).findElement(Input.locators.Input.input).getAttribute('placeholder');
|
|
78
|
+
return (await this.findElement(Input.locators.Input.inputBox).findElement(Input.locators.Input.input).getAttribute('placeholder'));
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Confirm the input field by pressing Enter
|
|
@@ -86,6 +86,74 @@ class Input extends AbstractElement_1.AbstractElement {
|
|
|
86
86
|
await input.click();
|
|
87
87
|
await input.sendKeys(selenium_webdriver_1.Key.ENTER);
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Confirm path selection for file/folder dialog.
|
|
91
|
+
*
|
|
92
|
+
* VS Code's file picker auto-navigates as text is typed: when a full path such as
|
|
93
|
+
* `/dir/file.txt` is in the input, the picker shows the parent directory contents
|
|
94
|
+
* with the filename filtered in the list. A single Enter press navigates into the
|
|
95
|
+
* matched list entry. A subsequent click on the OK button (or a second Enter) then
|
|
96
|
+
* confirms the selection and closes the dialog.
|
|
97
|
+
*
|
|
98
|
+
* When the path is not formatted to OS specifics there may first be a 'Select' step.
|
|
99
|
+
* See also https://github.com/redhat-developer/vscode-extension-tester/issues/1778
|
|
100
|
+
*/
|
|
101
|
+
async confirmPath() {
|
|
102
|
+
// Step 1 — drive VS Code's file picker to navigate into the typed path.
|
|
103
|
+
// Sending Enter selects the highlighted entry in the suggestion list, which
|
|
104
|
+
// causes the picker to consume the directory portion and reveal the target file.
|
|
105
|
+
const inputEl = await this.findElement(Input.locators.Input.inputBox).findElement(Input.locators.Input.input);
|
|
106
|
+
await inputEl.sendKeys(selenium_webdriver_1.Key.ENTER);
|
|
107
|
+
// When the typed path uniquely resolves the target, the first Enter both
|
|
108
|
+
// navigates and confirms — the picker closes on its own and no second step
|
|
109
|
+
// is needed (attempting one would hit a hidden input).
|
|
110
|
+
if (!(await this.isPickerOpen())) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Step 2 — click the OK button to confirm and close the dialog.
|
|
114
|
+
// Use a JS click to bypass any overlay that may intercept a normal WebDriver click.
|
|
115
|
+
// Falls back to a second Enter if no matching button is found.
|
|
116
|
+
try {
|
|
117
|
+
const buttons = await this.findElements(selenium_webdriver_1.By.className('monaco-button'));
|
|
118
|
+
for (const btn of buttons) {
|
|
119
|
+
if (await btn.isDisplayed()) {
|
|
120
|
+
const label = ((await btn.getText()) || (await btn.getAttribute('aria-label')) || '').trim();
|
|
121
|
+
if (label === 'Select' || label === 'Ok' || label === 'OK') {
|
|
122
|
+
await Input.driver.executeScript('arguments[0].click()', btn);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
// ignore if button is not found or stale
|
|
130
|
+
}
|
|
131
|
+
if (!(await this.isPickerOpen())) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
await inputEl.sendKeys(selenium_webdriver_1.Key.ENTER);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
// The picker can close in the instant between the check above and the
|
|
139
|
+
// keystroke — a failure only matters while the picker is still open.
|
|
140
|
+
if (await this.isPickerOpen()) {
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Best-effort check whether this input/picker widget is still displayed.
|
|
147
|
+
* A hidden, detached or stale widget counts as closed.
|
|
148
|
+
*/
|
|
149
|
+
async isPickerOpen() {
|
|
150
|
+
try {
|
|
151
|
+
return await this.isDisplayed();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
89
157
|
/**
|
|
90
158
|
* Cancel the input field by pressing Escape
|
|
91
159
|
* @returns Promise resolving when the input is cancelled
|
|
@@ -42,7 +42,7 @@ class InputBox extends __1.Input {
|
|
|
42
42
|
return await this.findElement(InputBox.locators.InputBox.message).getText();
|
|
43
43
|
}
|
|
44
44
|
async hasProgress() {
|
|
45
|
-
const klass = await this.findElement(InputBox.locators.InputBox.progress).getAttribute('class');
|
|
45
|
+
const klass = (await this.findElement(InputBox.locators.InputBox.progress).getAttribute('class'));
|
|
46
46
|
return klass.indexOf('done') < 0;
|
|
47
47
|
}
|
|
48
48
|
async getQuickPicks() {
|
|
@@ -90,7 +90,7 @@ class InputBox extends __1.Input {
|
|
|
90
90
|
* @returns Promise resolving to notification message
|
|
91
91
|
*/
|
|
92
92
|
async hasError() {
|
|
93
|
-
const klass = await this.findElement(InputBox.locators.Input.inputBox).getAttribute('class');
|
|
93
|
+
const klass = (await this.findElement(InputBox.locators.Input.inputBox).getAttribute('class'));
|
|
94
94
|
return klass.indexOf('error') > -1;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
@@ -32,11 +32,11 @@ class QuickOpenBox extends __1.Input {
|
|
|
32
32
|
* Use when a quick open box is scheduled to appear.
|
|
33
33
|
*/
|
|
34
34
|
static async create() {
|
|
35
|
-
await QuickOpenBox.driver.wait(selenium_webdriver_1.until.elementLocated(QuickOpenBox.locators.QuickOpenBox.constructor));
|
|
35
|
+
await QuickOpenBox.driver.wait(selenium_webdriver_1.until.elementLocated(QuickOpenBox.locators.QuickOpenBox.constructor), 10_000);
|
|
36
36
|
return new QuickOpenBox().wait();
|
|
37
37
|
}
|
|
38
38
|
async hasProgress() {
|
|
39
|
-
const klass = await this.findElement(QuickOpenBox.locators.QuickOpenBox.progress).getAttribute('class');
|
|
39
|
+
const klass = (await this.findElement(QuickOpenBox.locators.QuickOpenBox.progress).getAttribute('class'));
|
|
40
40
|
return klass.indexOf('done') < 0;
|
|
41
41
|
}
|
|
42
42
|
async getQuickPicks() {
|
|
@@ -101,7 +101,7 @@ exports.ElementNotInteractableError = ElementNotInteractableError;
|
|
|
101
101
|
class StaleElementError extends ExTesterError {
|
|
102
102
|
constructor(message, context = {}) {
|
|
103
103
|
super(message, context);
|
|
104
|
-
this.name = '
|
|
104
|
+
this.name = 'StaleElementReferenceError';
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
exports.StaleElementError = StaleElementError;
|
package/out/index.d.ts
CHANGED
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import { WebDriver } from 'selenium-webdriver';
|
|
18
|
+
export { AbstractElement } from './components/AbstractElement';
|
|
18
19
|
export * from 'selenium-webdriver';
|
|
19
20
|
export * from './locators/locators';
|
|
20
21
|
export * from './errors/NullAttributeError';
|
|
21
22
|
export * from './errors/ExTesterError';
|
|
22
23
|
export * from './utils/WaitHelper';
|
|
24
|
+
export * from './utils/TimeoutConstants';
|
|
23
25
|
export * from './components/menu/Menu';
|
|
24
26
|
export * from './components/menu/MenuItem';
|
|
25
27
|
export * from './components/menu/TitleBar';
|
|
@@ -88,4 +90,4 @@ export * from './conditions/WaitForAttribute';
|
|
|
88
90
|
* @param driver WebDriver instance
|
|
89
91
|
* @param browserID identifier/name of the browser (i.e. vscode)
|
|
90
92
|
*/
|
|
91
|
-
export declare function initPageObjects(currentVersion: string, baseVersion: string, locatorFolder: string, driver: WebDriver, browserID: string): void;
|
|
93
|
+
export declare function initPageObjects(currentVersion: string, baseVersion: string, locatorFolder: string, driver: WebDriver, browserID: string, customLocatorsPath?: string): void;
|
package/out/index.js
CHANGED
|
@@ -26,19 +26,45 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
26
26
|
if (k2 === undefined) k2 = k;
|
|
27
27
|
o[k2] = m[k];
|
|
28
28
|
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
29
51
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
30
52
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
31
53
|
};
|
|
32
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.NotificationType = exports.Notification = exports.ScmChange = exports.ScmProvider = exports.ScmView = void 0;
|
|
55
|
+
exports.NotificationType = exports.Notification = exports.ScmChange = exports.ScmProvider = exports.ScmView = exports.AbstractElement = void 0;
|
|
34
56
|
exports.initPageObjects = initPageObjects;
|
|
57
|
+
const path = __importStar(require("node:path"));
|
|
35
58
|
const AbstractElement_1 = require("./components/AbstractElement");
|
|
36
59
|
const loader_1 = require("./locators/loader");
|
|
60
|
+
var AbstractElement_2 = require("./components/AbstractElement");
|
|
61
|
+
Object.defineProperty(exports, "AbstractElement", { enumerable: true, get: function () { return AbstractElement_2.AbstractElement; } });
|
|
37
62
|
__exportStar(require("selenium-webdriver"), exports);
|
|
38
63
|
__exportStar(require("./locators/locators"), exports);
|
|
39
64
|
__exportStar(require("./errors/NullAttributeError"), exports);
|
|
40
65
|
__exportStar(require("./errors/ExTesterError"), exports);
|
|
41
66
|
__exportStar(require("./utils/WaitHelper"), exports);
|
|
67
|
+
__exportStar(require("./utils/TimeoutConstants"), exports);
|
|
42
68
|
__exportStar(require("./components/menu/Menu"), exports);
|
|
43
69
|
__exportStar(require("./components/menu/MenuItem"), exports);
|
|
44
70
|
__exportStar(require("./components/menu/TitleBar"), exports);
|
|
@@ -112,8 +138,12 @@ __exportStar(require("./conditions/WaitForAttribute"), exports);
|
|
|
112
138
|
* @param driver WebDriver instance
|
|
113
139
|
* @param browserID identifier/name of the browser (i.e. vscode)
|
|
114
140
|
*/
|
|
115
|
-
function initPageObjects(currentVersion, baseVersion, locatorFolder, driver, browserID) {
|
|
116
|
-
|
|
141
|
+
function initPageObjects(currentVersion, baseVersion, locatorFolder, driver, browserID, customLocatorsPath) {
|
|
142
|
+
let locators = new loader_1.LocatorLoader(currentVersion, baseVersion, locatorFolder).loadLocators();
|
|
143
|
+
if (customLocatorsPath) {
|
|
144
|
+
const custom = require(path.resolve(customLocatorsPath));
|
|
145
|
+
locators = (0, loader_1.mergeLocators)(locators, custom);
|
|
146
|
+
}
|
|
117
147
|
AbstractElement_1.AbstractElement.init(locators, driver, browserID, currentVersion);
|
|
118
148
|
}
|
|
119
149
|
//# sourceMappingURL=index.js.map
|
package/out/locators/loader.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { Locators } from './locators';
|
|
17
|
+
import { Locators, LocatorDiff } from './locators';
|
|
18
18
|
/**
|
|
19
19
|
* Utility for loading locators for a given vscode version
|
|
20
20
|
*/
|
|
@@ -34,3 +34,4 @@ export declare class LocatorLoader {
|
|
|
34
34
|
*/
|
|
35
35
|
loadLocators(): Locators;
|
|
36
36
|
}
|
|
37
|
+
export declare function mergeLocators(original: Locators, diff: LocatorDiff): Locators;
|
package/out/locators/loader.js
CHANGED
|
@@ -53,6 +53,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
53
53
|
};
|
|
54
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
55
|
exports.LocatorLoader = void 0;
|
|
56
|
+
exports.mergeLocators = mergeLocators;
|
|
56
57
|
const fs = __importStar(require("fs-extra"));
|
|
57
58
|
const path = __importStar(require("path"));
|
|
58
59
|
const compare_versions_1 = require("compare-versions");
|
|
@@ -102,8 +103,7 @@ class LocatorLoader {
|
|
|
102
103
|
}
|
|
103
104
|
for (const version of versions) {
|
|
104
105
|
const diff = require(path.join(this.baseFolder, version)).diff;
|
|
105
|
-
|
|
106
|
-
this.locators = newLocators;
|
|
106
|
+
this.locators = mergeLocators(this.locators, diff);
|
|
107
107
|
}
|
|
108
108
|
return this.locators;
|
|
109
109
|
}
|