@redhat-developer/page-objects 1.13.0 → 1.14.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 +4 -2
- package/out/components/AbstractElement.js +20 -2
- package/out/components/ActionButtonElementDropdown.js +2 -0
- package/out/components/bottomBar/AbstractViews.js +22 -20
- package/out/components/bottomBar/Views.d.ts +2 -0
- package/out/components/bottomBar/Views.js +22 -8
- package/out/components/editor/Editor.d.ts +1 -0
- package/out/components/editor/Editor.js +10 -0
- package/out/components/editor/EditorView.d.ts +2 -1
- package/out/components/editor/EditorView.js +6 -3
- package/out/components/editor/SettingsEditor.d.ts +1 -0
- package/out/components/editor/SettingsEditor.js +15 -5
- package/out/components/editor/TextEditor.d.ts +2 -1
- package/out/components/editor/TextEditor.js +60 -49
- package/out/components/sidebar/debug/DebugView.js +1 -1
- package/out/locators/locators.d.ts +2 -0
- package/package.json +2 -2
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { WebElement, WebDriver, Locator } from 'selenium-webdriver';
|
|
18
18
|
import { Locators } from '../locators/locators';
|
|
19
19
|
/**
|
|
20
|
-
* Default wrapper for
|
|
20
|
+
* Default wrapper for webElement
|
|
21
21
|
*/
|
|
22
22
|
export declare abstract class AbstractElement extends WebElement {
|
|
23
23
|
static readonly ctlKey: string;
|
|
@@ -30,7 +30,7 @@ export declare abstract class AbstractElement extends WebElement {
|
|
|
30
30
|
protected enclosingItem: WebElement;
|
|
31
31
|
/**
|
|
32
32
|
* Constructs a new element from a Locator or an existing WebElement
|
|
33
|
-
* @param base WebDriver compatible Locator for the given element or a reference to an existing
|
|
33
|
+
* @param base WebDriver compatible Locator for the given element or a reference to an existing WebElement
|
|
34
34
|
* @param enclosingItem Locator or a WebElement reference to an element containing the element being constructed
|
|
35
35
|
* this will be used to narrow down the search for the underlying DOM element
|
|
36
36
|
*/
|
|
@@ -48,4 +48,6 @@ export declare abstract class AbstractElement extends WebElement {
|
|
|
48
48
|
*/
|
|
49
49
|
getEnclosingElement(): WebElement;
|
|
50
50
|
static init(locators: Locators, driver: WebDriver, browser: string, version: string): void;
|
|
51
|
+
withRecovery<T>(fn: (self: this) => Promise<T>): Promise<T>;
|
|
52
|
+
protected reinitialize(): Promise<this>;
|
|
51
53
|
}
|
|
@@ -19,7 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
exports.AbstractElement = void 0;
|
|
20
20
|
const selenium_webdriver_1 = require("selenium-webdriver");
|
|
21
21
|
/**
|
|
22
|
-
* Default wrapper for
|
|
22
|
+
* Default wrapper for webElement
|
|
23
23
|
*/
|
|
24
24
|
class AbstractElement extends selenium_webdriver_1.WebElement {
|
|
25
25
|
static ctlKey = process.platform === 'darwin' ? selenium_webdriver_1.Key.COMMAND : selenium_webdriver_1.Key.CONTROL;
|
|
@@ -29,7 +29,7 @@ class AbstractElement extends selenium_webdriver_1.WebElement {
|
|
|
29
29
|
enclosingItem;
|
|
30
30
|
/**
|
|
31
31
|
* Constructs a new element from a Locator or an existing WebElement
|
|
32
|
-
* @param base WebDriver compatible Locator for the given element or a reference to an existing
|
|
32
|
+
* @param base WebDriver compatible Locator for the given element or a reference to an existing WebElement
|
|
33
33
|
* @param enclosingItem Locator or a WebElement reference to an element containing the element being constructed
|
|
34
34
|
* this will be used to narrow down the search for the underlying DOM element
|
|
35
35
|
*/
|
|
@@ -80,6 +80,24 @@ class AbstractElement extends selenium_webdriver_1.WebElement {
|
|
|
80
80
|
AbstractElement.driver = driver;
|
|
81
81
|
AbstractElement.versionInfo = { version: version, browser: browser };
|
|
82
82
|
}
|
|
83
|
+
async withRecovery(fn) {
|
|
84
|
+
try {
|
|
85
|
+
return await fn(this);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
if (err.name === 'StaleElementReferenceError' ||
|
|
89
|
+
err.name === 'ElementNotInteractableError' ||
|
|
90
|
+
/element.*(detached|not interactable)/i.test(err.message)) {
|
|
91
|
+
const reinit = await this.reinitialize();
|
|
92
|
+
return await fn(reinit);
|
|
93
|
+
}
|
|
94
|
+
throw err;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async reinitialize() {
|
|
98
|
+
// Implement generic fallback if possible — otherwise force override in subclasses
|
|
99
|
+
throw new Error(`reinitialize() not implemented in ${this.constructor.name}`);
|
|
100
|
+
}
|
|
83
101
|
}
|
|
84
102
|
exports.AbstractElement = AbstractElement;
|
|
85
103
|
//# sourceMappingURL=AbstractElement.js.map
|
|
@@ -23,12 +23,14 @@ const selenium_webdriver_1 = require("selenium-webdriver");
|
|
|
23
23
|
class ActionButtonElementDropdown extends AbstractElement_1.AbstractElement {
|
|
24
24
|
async open() {
|
|
25
25
|
await this.click();
|
|
26
|
+
await this.getDriver().sleep(500);
|
|
26
27
|
const shadowRootHost = await this.enclosingItem.findElements(ActionButtonElementDropdown.locators.ContextMenu.shadowRootHost);
|
|
27
28
|
const actions = this.getDriver().actions();
|
|
28
29
|
await actions.clear();
|
|
29
30
|
if (shadowRootHost.length > 0) {
|
|
30
31
|
if ((await this.getAttribute('aria-expanded')) !== 'true') {
|
|
31
32
|
await this.click();
|
|
33
|
+
await this.getDriver().sleep(500);
|
|
32
34
|
}
|
|
33
35
|
const shadowRoot = await shadowRootHost[0].getShadowRoot();
|
|
34
36
|
return new ContextMenu_1.ContextMenu(await shadowRoot.findElement(selenium_webdriver_1.By.className('monaco-menu-container'))).wait();
|
|
@@ -50,7 +50,7 @@ class ChannelView extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
50
50
|
throw Error(`DEPRECATED METHOD! The 'ChannelView.getCurrentChannel' method is broken! Read more information in 'Known Issues > Limitations in testing with VS Code 1.87+' - https://github.com/microsoft/vscode/issues/206897.`);
|
|
51
51
|
}
|
|
52
52
|
const combo = await this.enclosingItem.findElement(ChannelView.locators.BottomBarViews.channelCombo);
|
|
53
|
-
return await combo.getAttribute(
|
|
53
|
+
return await combo.getAttribute(ChannelView.locators.OutputView.currentChannelAttribute);
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Select a channel using the selector combo
|
|
@@ -72,25 +72,27 @@ class TextView extends ChannelView {
|
|
|
72
72
|
* @returns Promise resolving to the view's text
|
|
73
73
|
*/
|
|
74
74
|
async getText() {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
75
|
+
return this.withRecovery(async (self) => {
|
|
76
|
+
const clipboard = (await import('clipboardy')).default;
|
|
77
|
+
let originalClipboard = '';
|
|
78
|
+
try {
|
|
79
|
+
originalClipboard = clipboard.readSync();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
// workaround issue https://github.com/redhat-developer/vscode-extension-tester/issues/835
|
|
83
|
+
// do not fail if clipboard is empty
|
|
84
|
+
}
|
|
85
|
+
const textarea = await self.findElement(ChannelView.locators.BottomBarViews.textArea);
|
|
86
|
+
await textarea.sendKeys(selenium_webdriver_1.Key.chord(TextView.ctlKey, 'a'));
|
|
87
|
+
await textarea.sendKeys(selenium_webdriver_1.Key.chord(TextView.ctlKey, 'c'));
|
|
88
|
+
const text = clipboard.readSync();
|
|
89
|
+
// workaround as we are getting "element click intercepted" during the send keys actions.
|
|
90
|
+
// await textarea.click();
|
|
91
|
+
if (originalClipboard.length > 0) {
|
|
92
|
+
clipboard.writeSync(originalClipboard);
|
|
93
|
+
}
|
|
94
|
+
return text;
|
|
95
|
+
});
|
|
94
96
|
}
|
|
95
97
|
/**
|
|
96
98
|
* Clear the text in the current channel
|
|
@@ -22,6 +22,7 @@ import { ElementWithContextMenu } from '../ElementWithContextMenu';
|
|
|
22
22
|
*/
|
|
23
23
|
export declare class OutputView extends TextView {
|
|
24
24
|
constructor(panel?: BottomBarPanel);
|
|
25
|
+
protected reinitialize(): Promise<this>;
|
|
25
26
|
/**
|
|
26
27
|
* Select a channel using the selector combo
|
|
27
28
|
* @param name name of the channel to open
|
|
@@ -34,6 +35,7 @@ export declare class OutputView extends TextView {
|
|
|
34
35
|
*/
|
|
35
36
|
export declare class DebugConsoleView extends ElementWithContextMenu {
|
|
36
37
|
constructor(panel?: BottomBarPanel);
|
|
38
|
+
protected reinitialize(): Promise<this>;
|
|
37
39
|
/**
|
|
38
40
|
* Clear the console of all text
|
|
39
41
|
*/
|
|
@@ -29,6 +29,11 @@ class OutputView extends AbstractViews_1.TextView {
|
|
|
29
29
|
super(OutputView.locators.OutputView.constructor, panel);
|
|
30
30
|
this.actionsLabel = OutputView.locators.OutputView.actionsLabel;
|
|
31
31
|
}
|
|
32
|
+
async reinitialize() {
|
|
33
|
+
const panel = this.enclosingItem;
|
|
34
|
+
const view = await panel.openOutputView();
|
|
35
|
+
return view;
|
|
36
|
+
}
|
|
32
37
|
/**
|
|
33
38
|
* Select a channel using the selector combo
|
|
34
39
|
* @param name name of the channel to open
|
|
@@ -46,6 +51,11 @@ class DebugConsoleView extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
46
51
|
constructor(panel = new __1.BottomBarPanel()) {
|
|
47
52
|
super(DebugConsoleView.locators.DebugConsoleView.constructor, panel);
|
|
48
53
|
}
|
|
54
|
+
async reinitialize() {
|
|
55
|
+
const panel = this.enclosingItem;
|
|
56
|
+
const view = await panel.openDebugConsoleView();
|
|
57
|
+
return view;
|
|
58
|
+
}
|
|
49
59
|
/**
|
|
50
60
|
* Clear the console of all text
|
|
51
61
|
*/
|
|
@@ -58,9 +68,11 @@ class DebugConsoleView extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
58
68
|
* @param expression expression in form of a string
|
|
59
69
|
*/
|
|
60
70
|
async setExpression(expression) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
await this.withRecovery(async (self) => {
|
|
72
|
+
const textarea = await self.findElement(DebugConsoleView.locators.BottomBarViews.textArea);
|
|
73
|
+
await textarea.sendKeys(selenium_webdriver_1.Key.chord(DebugConsoleView.ctlKey, 'a'));
|
|
74
|
+
await textarea.sendKeys(expression);
|
|
75
|
+
});
|
|
64
76
|
}
|
|
65
77
|
/**
|
|
66
78
|
* Evaluate an expression:
|
|
@@ -70,11 +82,13 @@ class DebugConsoleView extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
70
82
|
* @param expression expression to evaluate. To use existing contents of the debug console text area instead, don't define this argument
|
|
71
83
|
*/
|
|
72
84
|
async evaluateExpression(expression) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
await this.withRecovery(async (self) => {
|
|
86
|
+
const textarea = await self.findElement(DebugConsoleView.locators.BottomBarViews.textArea);
|
|
87
|
+
if (expression) {
|
|
88
|
+
await self.setExpression(expression);
|
|
89
|
+
}
|
|
90
|
+
await textarea.sendKeys(selenium_webdriver_1.Key.ENTER);
|
|
91
|
+
});
|
|
78
92
|
}
|
|
79
93
|
/**
|
|
80
94
|
* Create a content assist page object
|
|
@@ -22,6 +22,7 @@ import { WebElement, Locator } from 'selenium-webdriver';
|
|
|
22
22
|
*/
|
|
23
23
|
export declare abstract class Editor extends ElementWithContextMenu {
|
|
24
24
|
constructor(view?: EditorView | EditorGroup, base?: Locator | WebElement);
|
|
25
|
+
protected reinitialize(): Promise<this>;
|
|
25
26
|
/**
|
|
26
27
|
* Get title/name of the open editor
|
|
27
28
|
*/
|
|
@@ -26,6 +26,16 @@ class Editor extends ElementWithContextMenu_1.ElementWithContextMenu {
|
|
|
26
26
|
constructor(view = new __1.EditorView(), base = Editor.locators.Editor.constructor) {
|
|
27
27
|
super(base, view);
|
|
28
28
|
}
|
|
29
|
+
async reinitialize() {
|
|
30
|
+
const editorView = this.enclosingItem;
|
|
31
|
+
const title = await this.getTitle();
|
|
32
|
+
const reopened = await editorView.openEditor(title);
|
|
33
|
+
// Check if we got the same type back
|
|
34
|
+
if (!(reopened instanceof this.constructor)) {
|
|
35
|
+
throw new Error(`Reopened editor is not the same type as original.`);
|
|
36
|
+
}
|
|
37
|
+
return reopened;
|
|
38
|
+
}
|
|
29
39
|
/**
|
|
30
40
|
* Get title/name of the open editor
|
|
31
41
|
*/
|
|
@@ -92,9 +92,10 @@ export declare class EditorView extends AbstractElement {
|
|
|
92
92
|
* Get editor action of a select editor group, search by title or predicate
|
|
93
93
|
* @param predicateOrTitle title or predicate to be used in search process
|
|
94
94
|
* @param groupIndex zero based index of the editor group (leftmost group has index 0), default 0
|
|
95
|
+
* @param timeout timeout in milliseconds to wait for the action to appear, default 5000
|
|
95
96
|
* @returns promise resolving to EditorAction object if found, undefined otherwise
|
|
96
97
|
*/
|
|
97
|
-
getAction(predicateOrTitle: string | ((action: EditorAction) => boolean | PromiseLike<boolean>), groupIndex?: number): Promise<EditorAction | undefined>;
|
|
98
|
+
getAction(predicateOrTitle: string | ((action: EditorAction) => boolean | PromiseLike<boolean>), groupIndex?: number, timeout?: number): Promise<EditorAction | undefined>;
|
|
98
99
|
}
|
|
99
100
|
/**
|
|
100
101
|
* Page object representing an editor group
|
|
@@ -169,11 +169,14 @@ class EditorView extends AbstractElement_1.AbstractElement {
|
|
|
169
169
|
* Get editor action of a select editor group, search by title or predicate
|
|
170
170
|
* @param predicateOrTitle title or predicate to be used in search process
|
|
171
171
|
* @param groupIndex zero based index of the editor group (leftmost group has index 0), default 0
|
|
172
|
+
* @param timeout timeout in milliseconds to wait for the action to appear, default 5000
|
|
172
173
|
* @returns promise resolving to EditorAction object if found, undefined otherwise
|
|
173
174
|
*/
|
|
174
|
-
async getAction(predicateOrTitle, groupIndex = 0) {
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
async getAction(predicateOrTitle, groupIndex = 0, timeout = 5000) {
|
|
176
|
+
return this.getDriver().wait(async () => {
|
|
177
|
+
const group = await this.getEditorGroup(groupIndex);
|
|
178
|
+
return group.getAction(predicateOrTitle);
|
|
179
|
+
}, timeout, `Expected action - '${predicateOrTitle}' was not found.`);
|
|
177
180
|
}
|
|
178
181
|
}
|
|
179
182
|
exports.EditorView = EditorView;
|
|
@@ -25,6 +25,7 @@ import { EditorView, EditorGroup } from '../..';
|
|
|
25
25
|
export declare class SettingsEditor extends Editor {
|
|
26
26
|
private divider;
|
|
27
27
|
constructor(view?: EditorView | EditorGroup);
|
|
28
|
+
protected reinitialize(): Promise<this>;
|
|
28
29
|
/**
|
|
29
30
|
* Search for a setting with a particular title and category.
|
|
30
31
|
* Returns an appropriate Setting object if the label is found,
|
|
@@ -30,6 +30,14 @@ class SettingsEditor extends Editor_1.Editor {
|
|
|
30
30
|
constructor(view = new __1.EditorView()) {
|
|
31
31
|
super(view);
|
|
32
32
|
}
|
|
33
|
+
async reinitialize() {
|
|
34
|
+
const reopened = await new __1.Workbench().openSettings();
|
|
35
|
+
// Check if we got the same type back
|
|
36
|
+
if (!(reopened instanceof this.constructor)) {
|
|
37
|
+
throw new Error(`Reopened editor is not the same type as original.`);
|
|
38
|
+
}
|
|
39
|
+
return reopened;
|
|
40
|
+
}
|
|
33
41
|
/**
|
|
34
42
|
* Search for a setting with a particular title and category.
|
|
35
43
|
* Returns an appropriate Setting object if the label is found,
|
|
@@ -43,11 +51,13 @@ class SettingsEditor extends Editor_1.Editor {
|
|
|
43
51
|
* @returns Promise resolving to a Setting object if found, undefined otherwise
|
|
44
52
|
*/
|
|
45
53
|
async findSetting(title, ...categories) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
return this.withRecovery(async (self) => {
|
|
55
|
+
const category = categories.join(self.divider);
|
|
56
|
+
const searchBox = await self.findElement(SettingsEditor.locators.Editor.inputArea);
|
|
57
|
+
await searchBox.sendKeys(selenium_webdriver_1.Key.chord(SettingsEditor.ctlKey, 'a'));
|
|
58
|
+
await searchBox.sendKeys(`${category}>${title}`);
|
|
59
|
+
return await self._getSettingItem(title, category);
|
|
60
|
+
});
|
|
51
61
|
}
|
|
52
62
|
/**
|
|
53
63
|
* Search for a setting with a precise ID.
|
|
@@ -117,7 +117,7 @@ export declare class TextEditor extends Editor {
|
|
|
117
117
|
* @returns Selection page object
|
|
118
118
|
*/
|
|
119
119
|
getSelection(): Promise<Selection | undefined>;
|
|
120
|
-
openFindWidget(): Promise<FindWidget>;
|
|
120
|
+
openFindWidget(timeout?: number): Promise<FindWidget>;
|
|
121
121
|
/**
|
|
122
122
|
* Add the given text to the given coordinates
|
|
123
123
|
* @param line number of the line to type into
|
|
@@ -274,6 +274,7 @@ export declare class CodeLens extends AbstractElement {
|
|
|
274
274
|
*/
|
|
275
275
|
export declare class FindWidget extends AbstractElement {
|
|
276
276
|
constructor(element: WebElement, editor: TextEditor);
|
|
277
|
+
protected reinitialize(): Promise<this>;
|
|
277
278
|
/**
|
|
278
279
|
* Toggle between find and replace mode
|
|
279
280
|
* @param replace true for replace, false for find
|
|
@@ -83,57 +83,61 @@ class TextEditor extends Editor_1.Editor {
|
|
|
83
83
|
* @returns Promise resolving to ContentAssist object when opening, void otherwise
|
|
84
84
|
*/
|
|
85
85
|
async toggleContentAssist(open) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
catch (err) {
|
|
94
|
-
isHidden = true;
|
|
95
|
-
}
|
|
96
|
-
const inputarea = await this.findElement(TextEditor.locators.Editor.inputArea);
|
|
97
|
-
if (open) {
|
|
98
|
-
if (isHidden) {
|
|
99
|
-
await inputarea.sendKeys(selenium_webdriver_1.Key.chord(selenium_webdriver_1.Key.CONTROL, selenium_webdriver_1.Key.SPACE));
|
|
100
|
-
await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(TextEditor.locators.ContentAssist.constructor), 2000);
|
|
86
|
+
return this.withRecovery(async (self) => {
|
|
87
|
+
let isHidden = true;
|
|
88
|
+
try {
|
|
89
|
+
const assist = await self.findElement(TextEditor.locators.ContentAssist.constructor);
|
|
90
|
+
const klass = await assist.getAttribute('class');
|
|
91
|
+
const visibility = await assist.getCssValue('visibility');
|
|
92
|
+
isHidden = klass.indexOf('visible') < 0 || visibility === 'hidden';
|
|
101
93
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return assist.isLoaded();
|
|
105
|
-
}, 10000);
|
|
106
|
-
return assist;
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
if (!isHidden) {
|
|
110
|
-
await inputarea.sendKeys(selenium_webdriver_1.Key.ESCAPE);
|
|
94
|
+
catch (err) {
|
|
95
|
+
isHidden = true;
|
|
111
96
|
}
|
|
112
|
-
|
|
97
|
+
const inputarea = await self.findElement(TextEditor.locators.Editor.inputArea);
|
|
98
|
+
if (open) {
|
|
99
|
+
if (isHidden) {
|
|
100
|
+
await inputarea.sendKeys(selenium_webdriver_1.Key.chord(selenium_webdriver_1.Key.CONTROL, selenium_webdriver_1.Key.SPACE));
|
|
101
|
+
await self.getDriver().wait(selenium_webdriver_1.until.elementLocated(TextEditor.locators.ContentAssist.constructor), 2000);
|
|
102
|
+
}
|
|
103
|
+
const assist = await new __1.ContentAssist(self).wait();
|
|
104
|
+
await self.getDriver().wait(() => {
|
|
105
|
+
return assist.isLoaded();
|
|
106
|
+
}, 10000);
|
|
107
|
+
return assist;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if (!isHidden) {
|
|
111
|
+
await inputarea.sendKeys(selenium_webdriver_1.Key.ESCAPE);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
113
115
|
}
|
|
114
116
|
/**
|
|
115
117
|
* Get all text from the editor
|
|
116
118
|
* @returns Promise resolving to editor text
|
|
117
119
|
*/
|
|
118
120
|
async getText() {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
return this.withRecovery(async (self) => {
|
|
122
|
+
const clipboard = (await import('clipboardy')).default;
|
|
123
|
+
let originalClipboard = '';
|
|
124
|
+
try {
|
|
125
|
+
originalClipboard = clipboard.readSync();
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
// workaround issue https://github.com/redhat-developer/vscode-extension-tester/issues/835
|
|
129
|
+
// do not fail if clipboard is empty
|
|
130
|
+
}
|
|
131
|
+
const inputarea = await self.findElement(TextEditor.locators.Editor.inputArea);
|
|
132
|
+
await inputarea.sendKeys(selenium_webdriver_1.Key.chord(TextEditor.ctlKey, 'a'), selenium_webdriver_1.Key.chord(TextEditor.ctlKey, 'c'));
|
|
133
|
+
await new Promise((res) => setTimeout(res, 500));
|
|
134
|
+
const text = clipboard.readSync();
|
|
135
|
+
await inputarea.sendKeys(selenium_webdriver_1.Key.UP);
|
|
136
|
+
if (originalClipboard.length > 0) {
|
|
137
|
+
clipboard.writeSync(originalClipboard);
|
|
138
|
+
}
|
|
139
|
+
return text;
|
|
140
|
+
});
|
|
137
141
|
}
|
|
138
142
|
/**
|
|
139
143
|
* Replace the contents of the editor with a given text
|
|
@@ -166,9 +170,11 @@ class TextEditor extends Editor_1.Editor {
|
|
|
166
170
|
* @returns Promise resolving once the text is deleted
|
|
167
171
|
*/
|
|
168
172
|
async clearText() {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
return this.withRecovery(async (self) => {
|
|
174
|
+
const input = await self.findElement(TextEditor.locators.Editor.inputArea);
|
|
175
|
+
await input.sendKeys(selenium_webdriver_1.Key.chord(TextEditor.ctlKey, 'a'));
|
|
176
|
+
await input.sendKeys(selenium_webdriver_1.Key.BACK_SPACE);
|
|
177
|
+
});
|
|
172
178
|
}
|
|
173
179
|
/**
|
|
174
180
|
* Get text from a given line
|
|
@@ -291,12 +297,12 @@ class TextEditor extends Editor_1.Editor {
|
|
|
291
297
|
}
|
|
292
298
|
return new Selection(selection[0], this);
|
|
293
299
|
}
|
|
294
|
-
async openFindWidget() {
|
|
300
|
+
async openFindWidget(timeout = 2_000) {
|
|
295
301
|
const actions = this.getDriver().actions();
|
|
296
302
|
await actions.clear();
|
|
297
303
|
await actions.keyDown(TextEditor.ctlKey).sendKeys('f').keyUp(TextEditor.ctlKey).perform();
|
|
298
|
-
const widget = await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(TextEditor.locators.TextEditor.findWidget),
|
|
299
|
-
await this.getDriver().wait(selenium_webdriver_1.until.elementIsVisible(widget),
|
|
304
|
+
const widget = await this.getDriver().wait(selenium_webdriver_1.until.elementLocated(TextEditor.locators.TextEditor.findWidget), timeout);
|
|
305
|
+
await this.getDriver().wait(selenium_webdriver_1.until.elementIsVisible(widget), timeout);
|
|
300
306
|
return new FindWidget(widget, this);
|
|
301
307
|
}
|
|
302
308
|
/**
|
|
@@ -695,6 +701,11 @@ class FindWidget extends AbstractElement_1.AbstractElement {
|
|
|
695
701
|
constructor(element, editor) {
|
|
696
702
|
super(element, editor);
|
|
697
703
|
}
|
|
704
|
+
async reinitialize() {
|
|
705
|
+
const editor = this.enclosingItem;
|
|
706
|
+
const widgetElement = await editor.findElement(FindWidget.locators.TextEditor.findWidget);
|
|
707
|
+
return new this.constructor(widgetElement, editor);
|
|
708
|
+
}
|
|
698
709
|
/**
|
|
699
710
|
* Toggle between find and replace mode
|
|
700
711
|
* @param replace true for replace, false for find
|
|
@@ -38,7 +38,7 @@ class DebugView extends SideBarView_1.SideBarView {
|
|
|
38
38
|
}
|
|
39
39
|
const action = await this.getTitlePart().findElement(DebugView.locators.DebugView.launchCombo);
|
|
40
40
|
const combo = await action.findElement(DebugView.locators.DebugView.launchSelect);
|
|
41
|
-
return await combo.getAttribute(
|
|
41
|
+
return await combo.getAttribute(DebugView.locators.DebugView.launchSelectAttribute);
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* Get titles of all available launch configurations
|
|
@@ -98,6 +98,7 @@ export interface Locators {
|
|
|
98
98
|
constructor: By;
|
|
99
99
|
actionsLabel: string;
|
|
100
100
|
optionByName: (name: string) => By;
|
|
101
|
+
currentChannelAttribute: string;
|
|
101
102
|
};
|
|
102
103
|
WebviewView: {
|
|
103
104
|
iframe: By;
|
|
@@ -445,6 +446,7 @@ export interface Locators {
|
|
|
445
446
|
DebugView: {
|
|
446
447
|
launchCombo: By;
|
|
447
448
|
launchSelect: By;
|
|
449
|
+
launchSelectAttribute: string;
|
|
448
450
|
launchOption: By;
|
|
449
451
|
optionByName: (name: string) => By;
|
|
450
452
|
startButton: By;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redhat-developer/page-objects",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.1",
|
|
4
4
|
"description": "Page Object API implementation for a VS Code editor used by ExTester framework.",
|
|
5
5
|
"main": "out/index.js",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"selenium-webdriver": ">=4.6.1",
|
|
48
48
|
"typescript": ">=4.6.2"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "f7c20839e93f93fdfe96e56a53c55b3d2c7fde92"
|
|
51
51
|
}
|