@theia/playwright 1.23.0-next.26
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/LICENSE +642 -0
- package/README.md +53 -0
- package/package.json +43 -0
- package/src/theia-about-dialog.ts +26 -0
- package/src/theia-app.ts +136 -0
- package/src/theia-context-menu.ts +42 -0
- package/src/theia-dialog.ts +113 -0
- package/src/theia-editor.ts +73 -0
- package/src/theia-explorer-view.ts +229 -0
- package/src/theia-main-menu.ts +54 -0
- package/src/theia-menu-item.ts +62 -0
- package/src/theia-menu.ts +96 -0
- package/src/theia-notification-indicator.ts +49 -0
- package/src/theia-notification-overlay.ts +94 -0
- package/src/theia-page-object.ts +29 -0
- package/src/theia-preference-view.ts +226 -0
- package/src/theia-problem-indicator.ts +44 -0
- package/src/theia-problem-view.ts +30 -0
- package/src/theia-quick-command-palette.ts +75 -0
- package/src/theia-rename-dialog.ts +36 -0
- package/src/theia-status-bar.ts +44 -0
- package/src/theia-status-indicator.ts +79 -0
- package/src/theia-text-editor.ts +168 -0
- package/src/theia-toggle-bottom-indicator.ts +25 -0
- package/src/theia-tree-node.ts +60 -0
- package/src/theia-view.ts +177 -0
- package/src/theia-workspace.ts +65 -0
- package/src/util.ts +72 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { ElementHandle } from '@playwright/test';
|
|
18
|
+
import { TheiaApp } from './theia-app';
|
|
19
|
+
import { TheiaView } from './theia-view';
|
|
20
|
+
|
|
21
|
+
const TheiaSettingsViewData = {
|
|
22
|
+
tabSelector: '#shell-tab-settings_widget',
|
|
23
|
+
viewSelector: '#settings_widget'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const PreferenceIds = {
|
|
27
|
+
Explorer: {
|
|
28
|
+
AutoReveal: 'explorer.autoReveal'
|
|
29
|
+
},
|
|
30
|
+
DiffEditor: {
|
|
31
|
+
MaxComputationTime: 'diffEditor.maxComputationTime'
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const DefaultPreferences = {
|
|
36
|
+
Explorer: {
|
|
37
|
+
AutoReveal: {
|
|
38
|
+
Enabled: true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
DiffEditor: {
|
|
42
|
+
MaxComputationTime: '5000'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export enum TheiaPreferenceScope {
|
|
47
|
+
User = 'User',
|
|
48
|
+
Workspace = 'Workspace'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class TheiaPreferenceView extends TheiaView {
|
|
52
|
+
public customTimeout?: number;
|
|
53
|
+
|
|
54
|
+
constructor(app: TheiaApp) {
|
|
55
|
+
super(TheiaSettingsViewData, app);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async open(preferenceScope = TheiaPreferenceScope.Workspace): Promise<TheiaView> {
|
|
59
|
+
await this.app.quickCommandPalette.trigger('Preferences: Open Settings (UI)');
|
|
60
|
+
await this.waitForVisible();
|
|
61
|
+
await this.openPreferenceScope(preferenceScope);
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected getScopeSelector(scope: TheiaPreferenceScope): string {
|
|
66
|
+
return `li.preferences-scope-tab div.p-TabBar-tabLabel:has-text("${scope}")`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async openPreferenceScope(scope: TheiaPreferenceScope): Promise<void> {
|
|
70
|
+
await this.activate();
|
|
71
|
+
const scopeTab = await this.page.waitForSelector(this.getScopeSelector(scope));
|
|
72
|
+
await scopeTab.click();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async getBooleanPreferenceById(preferenceId: string): Promise<boolean> {
|
|
76
|
+
const element = await this.findPreferenceEditorById(preferenceId);
|
|
77
|
+
return element.isChecked();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async getBooleanPreferenceByPath(sectionTitle: string, name: string): Promise<boolean> {
|
|
81
|
+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
|
|
82
|
+
return this.getBooleanPreferenceById(preferenceId);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async setBooleanPreferenceById(preferenceId: string, value: boolean): Promise<void> {
|
|
86
|
+
const element = await this.findPreferenceEditorById(preferenceId);
|
|
87
|
+
return value ? element.check() : element.uncheck();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async setBooleanPreferenceByPath(sectionTitle: string, name: string, value: boolean): Promise<void> {
|
|
91
|
+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
|
|
92
|
+
return this.setBooleanPreferenceById(preferenceId, value);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async getStringPreferenceById(preferenceId: string): Promise<string> {
|
|
96
|
+
const element = await this.findPreferenceEditorById(preferenceId);
|
|
97
|
+
return element.evaluate(e => (e as HTMLInputElement).value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async getStringPreferenceByPath(sectionTitle: string, name: string): Promise<string> {
|
|
101
|
+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
|
|
102
|
+
return this.getStringPreferenceById(preferenceId);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async setStringPreferenceById(preferenceId: string, value: string): Promise<void> {
|
|
106
|
+
const element = await this.findPreferenceEditorById(preferenceId);
|
|
107
|
+
return element.fill(value);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async setStringPreferenceByPath(sectionTitle: string, name: string, value: string): Promise<void> {
|
|
111
|
+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
|
|
112
|
+
return this.setStringPreferenceById(preferenceId, value);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async waitForModified(preferenceId: string): Promise<void> {
|
|
116
|
+
await this.activate();
|
|
117
|
+
const viewElement = await this.viewElement();
|
|
118
|
+
await viewElement?.waitForSelector(`${this.getPreferenceGutterSelector(preferenceId)}.theia-mod-item-modified`, { timeout: this.customTimeout });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async resetStringPreferenceById(preferenceId: string): Promise<void> {
|
|
122
|
+
const resetPreferenceButton = await this.findPreferenceResetButton(preferenceId);
|
|
123
|
+
if (!resetPreferenceButton) {
|
|
124
|
+
// preference not modified
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const previousValue = await this.getStringPreferenceById(preferenceId);
|
|
128
|
+
const selector = this.getPreferenceEditorSelector(preferenceId);
|
|
129
|
+
const done = await resetPreferenceButton.click();
|
|
130
|
+
await this.page.waitForFunction(data => {
|
|
131
|
+
const element = document.querySelector(data.selector);
|
|
132
|
+
if (!element) {
|
|
133
|
+
throw new Error(`Could not find preference element with id "${data.preferenceId}"`);
|
|
134
|
+
}
|
|
135
|
+
const value = (element as HTMLInputElement).value;
|
|
136
|
+
return value !== data.previousValue;
|
|
137
|
+
}, { preferenceId, selector, previousValue, done }, { timeout: this.customTimeout });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async resetStringPreferenceByPath(sectionTitle: string, name: string): Promise<void> {
|
|
141
|
+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
|
|
142
|
+
return this.resetStringPreferenceById(preferenceId);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async resetBooleanPreferenceById(preferenceId: string): Promise<void> {
|
|
146
|
+
const resetPreferenceButton = await this.findPreferenceResetButton(preferenceId);
|
|
147
|
+
if (!resetPreferenceButton) {
|
|
148
|
+
// preference not modified
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const previousValue = await this.getBooleanPreferenceById(preferenceId);
|
|
152
|
+
const selector = this.getPreferenceEditorSelector(preferenceId);
|
|
153
|
+
const done = await resetPreferenceButton.click();
|
|
154
|
+
await this.page.waitForFunction(data => {
|
|
155
|
+
const element = document.querySelector(data.selector);
|
|
156
|
+
if (!element) {
|
|
157
|
+
throw new Error(`Could not find preference element with id "${data.preferenceId}"`);
|
|
158
|
+
}
|
|
159
|
+
const value = (element as HTMLInputElement).checked;
|
|
160
|
+
return value !== data.previousValue;
|
|
161
|
+
}, { preferenceId, selector, previousValue, done }, { timeout: this.customTimeout });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async resetBooleanPreferenceByPath(sectionTitle: string, name: string): Promise<void> {
|
|
165
|
+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
|
|
166
|
+
return this.resetBooleanPreferenceById(preferenceId);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private async findPreferenceId(sectionTitle: string, name: string): Promise<string> {
|
|
170
|
+
const viewElement = await this.viewElement();
|
|
171
|
+
const sectionElement = await viewElement?.$(`xpath=//li[contains(@class, 'settings-section-title') and text() = '${sectionTitle}']/..`);
|
|
172
|
+
|
|
173
|
+
const firstPreferenceAfterSection = await sectionElement?.$(`xpath=following-sibling::li[div/text() = '${name}'][1]`);
|
|
174
|
+
const preferenceId = await firstPreferenceAfterSection?.getAttribute('data-pref-id');
|
|
175
|
+
if (!preferenceId) {
|
|
176
|
+
throw new Error(`Could not find preference id for "${sectionTitle}" > (...) > "${name}"`);
|
|
177
|
+
}
|
|
178
|
+
return preferenceId;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private async findPreferenceEditorById(preferenceId: string): Promise<ElementHandle<SVGElement | HTMLElement>> {
|
|
182
|
+
const viewElement = await this.viewElement();
|
|
183
|
+
const element = await viewElement?.waitForSelector(this.getPreferenceEditorSelector(preferenceId), { timeout: this.customTimeout });
|
|
184
|
+
if (!element) {
|
|
185
|
+
throw new Error(`Could not find element with preference id "${preferenceId}"`);
|
|
186
|
+
}
|
|
187
|
+
return element;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private getPreferenceSelector(preferenceId: string): string {
|
|
191
|
+
return `li[data-pref-id="${preferenceId}"]`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private getPreferenceEditorSelector(preferenceId: string): string {
|
|
195
|
+
return `${this.getPreferenceSelector(preferenceId)} input`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private getPreferenceGutterSelector(preferenceId: string): string {
|
|
199
|
+
return `${this.getPreferenceSelector(preferenceId)} .pref-context-gutter`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private async findPreferenceResetButton(preferenceId: string): Promise<ElementHandle<SVGElement | HTMLElement> | undefined> {
|
|
203
|
+
await this.activate();
|
|
204
|
+
const viewElement = await this.viewElement();
|
|
205
|
+
const gutter = await viewElement?.waitForSelector(`${this.getPreferenceGutterSelector(preferenceId)}`, { timeout: this.customTimeout });
|
|
206
|
+
if (!gutter) {
|
|
207
|
+
throw new Error(`Could not determine modified state for element with preference id "${preferenceId}"`);
|
|
208
|
+
}
|
|
209
|
+
const isModified = await gutter.evaluate(e => e.classList.contains('theia-mod-item-modified'));
|
|
210
|
+
if (!isModified) {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const settingsContextMenuBtn = await viewElement?.waitForSelector(`${this.getPreferenceSelector(preferenceId)} .settings-context-menu-btn`);
|
|
215
|
+
if (!settingsContextMenuBtn) {
|
|
216
|
+
throw new Error(`Could not find context menu button for element with preference id "${preferenceId}"`);
|
|
217
|
+
}
|
|
218
|
+
await settingsContextMenuBtn.click();
|
|
219
|
+
const resetPreferenceButton = await this.page.waitForSelector('li[data-command="preferences:reset"]');
|
|
220
|
+
if (!resetPreferenceButton) {
|
|
221
|
+
throw new Error(`Could not find menu entry to reset preference with id "${preferenceId}"`);
|
|
222
|
+
}
|
|
223
|
+
return resetPreferenceButton;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { ElementHandle } from '@playwright/test';
|
|
18
|
+
import { TheiaStatusIndicator } from './theia-status-indicator';
|
|
19
|
+
|
|
20
|
+
const PROBLEM_ICON = 'codicon-error';
|
|
21
|
+
|
|
22
|
+
export class TheiaProblemIndicator extends TheiaStatusIndicator {
|
|
23
|
+
|
|
24
|
+
async isVisible(): Promise<boolean> {
|
|
25
|
+
const handle = await super.getElementHandleByIcon(PROBLEM_ICON);
|
|
26
|
+
return !!handle && handle.isVisible();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async numberOfProblems(): Promise<number> {
|
|
30
|
+
const spans = await this.getSpans();
|
|
31
|
+
return spans ? +await spans[1].innerText() : -1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async numberOfWarnings(): Promise<number> {
|
|
35
|
+
const spans = await this.getSpans();
|
|
36
|
+
return spans ? +await spans[3].innerText() : -1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected async getSpans(): Promise<ElementHandle[] | undefined> {
|
|
40
|
+
const handle = await super.getElementHandleByIcon(PROBLEM_ICON);
|
|
41
|
+
return handle?.$$('span');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { TheiaApp } from './theia-app';
|
|
18
|
+
import { TheiaView } from './theia-view';
|
|
19
|
+
|
|
20
|
+
const TheiaProblemsViewData = {
|
|
21
|
+
tabSelector: '#shell-tab-problems',
|
|
22
|
+
viewSelector: '#problems',
|
|
23
|
+
viewName: 'Problems'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export class TheiaProblemsView extends TheiaView {
|
|
27
|
+
constructor(app: TheiaApp) {
|
|
28
|
+
super(TheiaProblemsViewData, app);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { ElementHandle } from '@playwright/test';
|
|
18
|
+
import { TheiaPageObject } from './theia-page-object';
|
|
19
|
+
import { USER_KEY_TYPING_DELAY } from './util';
|
|
20
|
+
|
|
21
|
+
export class TheiaQuickCommandPalette extends TheiaPageObject {
|
|
22
|
+
|
|
23
|
+
selector = '.quick-input-widget';
|
|
24
|
+
|
|
25
|
+
async open(): Promise<void> {
|
|
26
|
+
await this.page.keyboard.press('Control+Shift+p');
|
|
27
|
+
await this.page.waitForSelector(this.selector);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async isOpen(): Promise<boolean> {
|
|
31
|
+
try {
|
|
32
|
+
await this.page.waitForSelector(this.selector, { timeout: 5000 });
|
|
33
|
+
} catch (err) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async trigger(...commandName: string[]): Promise<void> {
|
|
40
|
+
for (const command of commandName) {
|
|
41
|
+
await this.triggerSingleCommand(command);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected async triggerSingleCommand(commandName: string): Promise<void> {
|
|
46
|
+
if (!await this.isOpen()) {
|
|
47
|
+
this.open();
|
|
48
|
+
}
|
|
49
|
+
let selected = await this.selectedCommand();
|
|
50
|
+
while (!(await selected?.getAttribute('aria-label') === commandName)) {
|
|
51
|
+
await this.page.keyboard.press('ArrowDown');
|
|
52
|
+
selected = await this.selectedCommand();
|
|
53
|
+
}
|
|
54
|
+
await this.page.keyboard.press('Enter');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async type(command: string): Promise<void> {
|
|
58
|
+
if (!await this.isOpen()) {
|
|
59
|
+
this.open();
|
|
60
|
+
}
|
|
61
|
+
const input = await this.page.waitForSelector(`${this.selector} .monaco-inputbox .input`);
|
|
62
|
+
if (input != null) {
|
|
63
|
+
await input.focus();
|
|
64
|
+
await input.type(command, { delay: USER_KEY_TYPING_DELAY });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected async selectedCommand(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
|
69
|
+
const command = await this.page.waitForSelector(this.selector);
|
|
70
|
+
if (!command) {
|
|
71
|
+
throw new Error('No selected command found!');
|
|
72
|
+
}
|
|
73
|
+
return command.$('.monaco-list-row.focused');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { TheiaDialog } from './theia-dialog';
|
|
18
|
+
import { USER_KEY_TYPING_DELAY } from './util';
|
|
19
|
+
|
|
20
|
+
export class TheiaRenameDialog extends TheiaDialog {
|
|
21
|
+
|
|
22
|
+
async enterNewName(newName: string): Promise<void> {
|
|
23
|
+
const inputField = await this.page.waitForSelector(`${this.blockSelector} .theia-input`);
|
|
24
|
+
await inputField.press('Control+a');
|
|
25
|
+
await inputField.type(newName, { delay: USER_KEY_TYPING_DELAY });
|
|
26
|
+
await this.page.waitForTimeout(USER_KEY_TYPING_DELAY);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async confirm(): Promise<void> {
|
|
30
|
+
if (!await this.validationResult()) {
|
|
31
|
+
throw new Error(`Unexpected validation error in TheiaRenameDialog: '${await this.getValidationText()}`);
|
|
32
|
+
}
|
|
33
|
+
await this.clickMainButton();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { ElementHandle } from '@playwright/test';
|
|
18
|
+
|
|
19
|
+
import { TheiaApp } from './theia-app';
|
|
20
|
+
import { TheiaPageObject } from './theia-page-object';
|
|
21
|
+
import { TheiaStatusIndicator } from './theia-status-indicator';
|
|
22
|
+
|
|
23
|
+
export class TheiaStatusBar extends TheiaPageObject {
|
|
24
|
+
|
|
25
|
+
selector = 'div#theia-statusBar';
|
|
26
|
+
|
|
27
|
+
protected async statusBarElementHandle(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
|
28
|
+
return this.page.$(this.selector);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async statusIndicator<T extends TheiaStatusIndicator>(statusIndicatorFactory: { new(app: TheiaApp): T }): Promise<T> {
|
|
32
|
+
return new statusIndicatorFactory(this.app);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async waitForVisible(): Promise<void> {
|
|
36
|
+
await this.page.waitForSelector(this.selector, { state: 'visible' });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async isVisible(): Promise<boolean> {
|
|
40
|
+
const statusBar = await this.statusBarElementHandle();
|
|
41
|
+
return !!statusBar && statusBar.isVisible();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { ElementHandle } from '@playwright/test';
|
|
18
|
+
import { TheiaPageObject } from './theia-page-object';
|
|
19
|
+
|
|
20
|
+
export class TheiaStatusIndicator extends TheiaPageObject {
|
|
21
|
+
|
|
22
|
+
protected elementSpanSelector = '#theia-statusBar .element span';
|
|
23
|
+
|
|
24
|
+
protected async getElementHandle(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
|
25
|
+
return this.page.$(this.elementSpanSelector);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async waitForVisible(): Promise<void> {
|
|
29
|
+
await this.page.waitForSelector(this.elementSpanSelector);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protected getSelectorByTitle(title: string): string {
|
|
33
|
+
return `.element[title="${title}"]`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async getElementHandleByTitle(title: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
|
37
|
+
// Fetch element via title in case status elements exist without a dedicated Codicon icon
|
|
38
|
+
return this.page.$(this.getSelectorByTitle(title));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected getSelectorByIcon(icon: string): string {
|
|
42
|
+
return `${this.elementSpanSelector}.codicon.${icon}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getElementHandleByIcon(iconClass: string | string[], titleContain = ''): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
|
46
|
+
const icons = Array.isArray(iconClass) ? iconClass : [iconClass];
|
|
47
|
+
for (const icon of icons) {
|
|
48
|
+
const span = await this.page.$(this.getSelectorByIcon(icon));
|
|
49
|
+
if (span) {
|
|
50
|
+
const parent = await span.$('..');
|
|
51
|
+
if (titleContain === '') {
|
|
52
|
+
return parent;
|
|
53
|
+
} else {
|
|
54
|
+
const parentTitle = await parent?.getAttribute('title');
|
|
55
|
+
if (parentTitle?.includes(titleContain)) { return parent; }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw new Error('Cannot find indicator');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async waitForVisibleByTitle(title: string, waitForDetached = false): Promise<void> {
|
|
63
|
+
await this.page.waitForSelector(this.getSelectorByTitle(title), waitForDetached ? { state: 'detached' } : {});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async waitForVisibleByIcon(icon: string, waitForDetached = false): Promise<void> {
|
|
67
|
+
await this.page.waitForSelector(this.getSelectorByIcon(icon), waitForDetached ? { state: 'detached' } : {});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async isVisible(icon: string | string[], titleContain = ''): Promise<boolean> {
|
|
71
|
+
try {
|
|
72
|
+
const element = await this.getElementHandleByIcon(icon, titleContain);
|
|
73
|
+
return !!element && element.isVisible();
|
|
74
|
+
} catch (err) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|