Skip to content

Commit ac094f5

Browse files
committed
[tests] Stabilizing Public UI Tests
- Updated Kind: - kind v0.31.0 go1.25.5 linux/amd64 - Client Version: v1.35.0 - Tune up for Code Coverage v6.0.0 - Public UI Tests targeted: - Project test - Create Component test - Component Context Menu test - Operator Backed Service test - Log files included into the artifacts to be uploaded Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com>
1 parent b121800 commit ac094f5

File tree

9 files changed

+543
-95
lines changed

9 files changed

+543
-95
lines changed

.github/workflows/continuous-integration-workflow.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ jobs:
3030
steps:
3131
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
3232
- uses: actions/checkout@v6
33+
with:
34+
fetch-depth: 0
3335

3436
# Set up Node
3537
- name: Use Node.js ${{ matrix.node }}
@@ -59,7 +61,8 @@ jobs:
5961
if: (success() || failure()) && runner.os == 'Linux'
6062
uses: helm/kind-action@v1.14.0
6163
with:
62-
version: v0.24.0
64+
version: v0.31.0
65+
node_image: kindest/node:v1.34.0
6366

6467
- name: Configure cluster
6568
if: (success() || failure()) && runner.os == 'Linux'
@@ -105,6 +108,7 @@ jobs:
105108
with:
106109
name: artifacts-${{ matrix.os }}
107110
path: |
111+
/tmp/test-resources/settings/logs/**/*.log
108112
/tmp/test-resources/screenshots/**/*.png
109113
retention-days: 2
110114

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/explorer.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,26 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
183183
.then(result => (allTrue(result) ? `${contextValue}.can-delete` : contextValue));
184184
}
185185

186+
186187
// eslint-disable-next-line class-methods-use-this
187188
async getTreeItem(element: ExplorerItem): Promise<TreeItem> {
189+
try {
190+
return await this._getTreeItem(element);
191+
} catch (err) {
192+
// eslint-disable-next-line no-console
193+
console.error('getTreeItem failed:', err, element);
194+
195+
return {
196+
label: '⚠️ Broken item',
197+
tooltip: `${err}`,
198+
iconPath: new ThemeIcon('error'),
199+
collapsibleState: TreeItemCollapsibleState.None
200+
};
201+
}
202+
}
203+
204+
// eslint-disable-next-line class-methods-use-this
205+
async _getTreeItem(element: ExplorerItem): Promise<TreeItem> {
188206
if ('command' in element || ('label' in element && 'iconPath' in element)) {
189207
return element;
190208
}
@@ -474,7 +492,23 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
474492
}
475493

476494
// eslint-disable-next-line class-methods-use-this
495+
477496
async getChildren(element?: ExplorerItem): Promise<ExplorerItem[]> {
497+
try {
498+
return await this._getChildren(element);
499+
} catch (err) {
500+
// eslint-disable-next-line no-console
501+
console.error('getChildren failed:', err);
502+
503+
return [{
504+
label: '⚠️ Error loading tree',
505+
tooltip: String(err),
506+
iconPath: new ThemeIcon('error')
507+
}];
508+
}
509+
}
510+
511+
async _getChildren(element?: ExplorerItem): Promise<ExplorerItem[]> {
478512
let result: ExplorerItem[] = [];
479513
// don't show Open In Developer Dashboard if not openshift cluster
480514
const isOpenshiftCluster = await isOpenShiftCluster(this.executionContext);

test/ui/common/conditions.ts

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import {
1111
NotificationType,
1212
ViewItem,
1313
ViewSection,
14+
VSBrowser,
1415
WebDriver,
1516
WelcomeContentSection,
16-
Workbench,
17+
Workbench
1718
} from 'vscode-extension-tester';
1819

1920
export async function waitForInputUpdate(
@@ -97,6 +98,61 @@ export async function itemExists(
9798
);
9899
}
99100

101+
export async function stabilizeComponentsView(getSection: () => Promise<ViewSection>, timeout = 20000): Promise<ViewSection> {
102+
const result = await VSBrowser.instance.driver.wait(async () => {
103+
try {
104+
let section = await getSection();
105+
106+
await section.expand();
107+
await new Promise(res => setTimeout(res, 300));
108+
109+
section = await getSection();
110+
111+
// ---- try tree mode ----
112+
try {
113+
const items = await section.getVisibleItems();
114+
await Promise.all(items.map(i => i.getText()));
115+
return section;
116+
} catch {
117+
// ---- fallback: welcome content mode ----
118+
try {
119+
const welcome = await section.findWelcomeContent();
120+
const buttons = await welcome.getButtons();
121+
if (buttons) {
122+
return section;
123+
}
124+
} catch {
125+
return false;
126+
}
127+
}
128+
129+
return false;
130+
131+
} catch {
132+
return false;
133+
}
134+
}, timeout, 'Components view did not stabilize');
135+
136+
return result as ViewSection;
137+
}
138+
139+
export async function waitForItem(getSection: () => Promise<ViewSection>, label: string, timeout = 15000) {
140+
return VSBrowser.instance.driver.wait(async () => {
141+
try {
142+
const section = await getSection();
143+
const item = await section.findItem(label);
144+
return item ?? false;
145+
} catch {
146+
return false;
147+
}
148+
}, timeout, `Item "${label}" not found within ${timeout}ms`) as Promise<ViewItem>;
149+
}
150+
151+
export async function waitForItemStable(getSection: () => Promise<ViewSection>, label: string, timeout = 15000) {
152+
await stabilizeComponentsView(getSection);
153+
return waitForItem(getSection, label, timeout);
154+
}
155+
100156
export async function itemDoesNotExist(
101157
title: string,
102158
view: ViewSection,
@@ -191,3 +247,30 @@ export async function webViewIsOpened(name: string, driver: WebDriver, timeout =
191247
}
192248
}, timeout);
193249
}
250+
251+
export async function step<T>(name: string, fn: () => Promise<T>): Promise<T> {
252+
const callSiteStack = new Error(`Step: ${name}`).stack;
253+
try {
254+
return await fn();
255+
} catch (err) {
256+
const error = err as Error;
257+
error.message = `Step failed: ${name}\n${error.message}`;
258+
if (error.stack && callSiteStack) {
259+
error.stack =
260+
`${error.stack}\n\n--- Step call site ---\n${callSiteStack}`;
261+
}
262+
throw error;
263+
}
264+
}
265+
266+
export async function debugClick(element, name: string) {
267+
try {
268+
await element.click();
269+
} catch (e) {
270+
/* eslint-disable no-console */
271+
console.error(`Failed to click: ${name}`);
272+
console.error(await element.getAttribute('outerHTML'));
273+
/* eslint-enable no-console */
274+
throw e;
275+
}
276+
}

test/ui/common/ui/webview/newComponentWebViewEditor.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See LICENSE file in the project root for license information.
44
*-----------------------------------------------------------------------------------------------*/
55
import { By, Key, WebElement, WebView } from 'vscode-extension-tester';
6+
import { debugClick } from '../../conditions';
67
import { WebViewForm } from './WebViewForm';
78

89
//TODO: Add support for create from git page and from local codebase page
@@ -160,7 +161,8 @@ export class GitProjectPage extends Page {
160161
public async clickContinueButton(): Promise<void> {
161162
await this.enterWebView(async (webView) => {
162163
const button = await this.continueButtonExists(webView);
163-
await button.click();
164+
// await button.click();
165+
await debugClick(button, 'Continue');
164166
});
165167
}
166168

@@ -202,14 +204,16 @@ export class LocalCodeBasePage extends Page {
202204
public async clickSelectFolderButton(): Promise<void> {
203205
await this.enterWebView(async (webView) => {
204206
const button = await this.getSelectFolderButton(webView);
205-
await button.click();
207+
// await button.click();
208+
await debugClick(button, 'Select Folder');
206209
});
207210
}
208211

209212
public async clickCreateComponent(): Promise<void> {
210213
await this.enterWebView(async (webView) => {
211214
const button = await this.createButtonExists(webView);
212-
await button.click();
215+
// await button.click();
216+
await debugClick(button, 'Create Component');
213217
});
214218
}
215219

0 commit comments

Comments
 (0)