Skip to content

Commit e916fe8

Browse files
authored
chore(test): simplifying and extracting test logic, refactor (#3078)
Signed-off-by: Tibor Dancs <[email protected]>
1 parent 89fe6b3 commit e916fe8

15 files changed

+224
-67
lines changed

tests/playwright/playwright.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { defineConfig, devices } from '@playwright/test';
2121
export default defineConfig({
2222
outputDir: './output/',
2323
workers: 1,
24+
timeout: 60_000,
2425

2526
reporter: [
2627
['list'],

tests/playwright/src/ai-lab-extension.spec.ts

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
1818

19-
import type { Locator, Page } from '@playwright/test';
19+
import type { Locator } from '@playwright/test';
2020
import type { NavigationBar, ExtensionsPage } from '@podman-desktop/tests-playwright';
2121
import {
2222
expect as playExpect,
@@ -26,24 +26,26 @@ import {
2626
waitForPodmanMachineStartup,
2727
isLinux,
2828
} from '@podman-desktop/tests-playwright';
29-
import { AILabPage } from './model/ai-lab-page';
29+
import type { AILabDashboardPage } from './model/ai-lab-dashboard-page';
3030
import type { AILabRecipesCatalogPage } from './model/ai-lab-recipes-catalog-page';
31-
import { AILabExtensionDetailsPage } from './model/podman-extension-ai-lab-details-page';
3231
import type { AILabCatalogPage } from './model/ai-lab-catalog-page';
33-
import { handleWebview } from './utils/webviewHandler';
3432
import type { AILabServiceDetailsPage } from './model/ai-lab-service-details-page';
3533
import type { AILabPlaygroundsPage } from './model/ai-lab-playgrounds-page';
3634
import type { AILabPlaygroundDetailsPage } from './model/ai-lab-playground-details-page';
35+
import {
36+
getExtensionCard,
37+
getExtensionVersion,
38+
openAILabExtensionDetails,
39+
reopenAILabDashboard,
40+
waitForExtensionToInitialize,
41+
} from './utils/aiLabHandler';
3742

3843
const AI_LAB_EXTENSION_OCI_IMAGE =
3944
process.env.EXTENSION_OCI_IMAGE ?? 'ghcr.io/containers/podman-desktop-extension-ai-lab:nightly';
4045
const AI_LAB_EXTENSION_PREINSTALLED: boolean = process.env.EXTENSION_PREINSTALLED === 'true';
41-
const AI_LAB_CATALOG_EXTENSION_LABEL: string = 'redhat.ai-lab';
42-
const AI_LAB_CATALOG_EXTENSION_NAME: string = 'Podman AI Lab extension';
4346
const AI_LAB_CATALOG_STATUS_ACTIVE: string = 'ACTIVE';
4447

45-
let webview: Page;
46-
let aiLabPage: AILabPage;
48+
let aiLabPage: AILabDashboardPage;
4749
const runnerOptions = {
4850
customFolder: 'ai-lab-tests-pd',
4951
aiLabModelUploadDisabled: isWindows ? true : false,
@@ -86,36 +88,20 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
8688
});
8789

8890
test('Extension (card) is installed, present and active', async ({ navigationBar }) => {
89-
const extensions = await navigationBar.openExtensions();
90-
await playExpect
91-
.poll(async () => await extensions.extensionIsInstalled(AI_LAB_CATALOG_EXTENSION_LABEL), { timeout: 30000 })
92-
.toBeTruthy();
93-
const extensionCard = await extensions.getInstalledExtension(
94-
AI_LAB_CATALOG_EXTENSION_NAME,
95-
AI_LAB_CATALOG_EXTENSION_LABEL,
96-
);
91+
await waitForExtensionToInitialize(navigationBar);
92+
const extensionCard = await getExtensionCard(navigationBar);
9793
await playExpect(extensionCard.status).toHaveText(AI_LAB_CATALOG_STATUS_ACTIVE);
9894
});
9995

100-
test(`Extension's details show correct status, no error`, async ({ page, navigationBar }) => {
101-
const extensions = await navigationBar.openExtensions();
102-
const extensionCard = await extensions.getInstalledExtension('ai-lab', AI_LAB_CATALOG_EXTENSION_LABEL);
103-
await extensionCard.openExtensionDetails(AI_LAB_CATALOG_EXTENSION_NAME);
104-
const details = new AILabExtensionDetailsPage(page);
105-
await playExpect(details.heading).toBeVisible();
106-
await playExpect(details.status).toHaveText(AI_LAB_CATALOG_STATUS_ACTIVE);
107-
const errorTab = details.tabs.getByRole('button', { name: 'Error' });
108-
// we would like to propagate the error's stack trace into test failure message
109-
let stackTrace = '';
110-
if ((await errorTab.count()) > 0) {
111-
await details.activateTab('Error');
112-
stackTrace = await details.errorStackTrace.innerText();
113-
}
114-
await playExpect(errorTab, `Error Tab was present with stackTrace: ${stackTrace}`).not.toBeVisible();
96+
test(`Extension's details show correct status, no error`, async ({ navigationBar }) => {
97+
const aiLabExtensionDetailsPage = await openAILabExtensionDetails(navigationBar);
98+
await aiLabExtensionDetailsPage.waitForLoad();
99+
await aiLabExtensionDetailsPage.checkIsActive(AI_LAB_CATALOG_STATUS_ACTIVE);
100+
await aiLabExtensionDetailsPage.checkForErrors();
115101
});
116-
test(`Verify AI Lab extension is installed`, async ({ runner, page, navigationBar }) => {
117-
[page, webview] = await handleWebview(runner, page, navigationBar);
118-
aiLabPage = new AILabPage(page, webview);
102+
103+
test(`Verify AI Lab is accessible`, async ({ runner, page, navigationBar }) => {
104+
aiLabPage = await reopenAILabDashboard(runner, page, navigationBar);
119105
await aiLabPage.navigationBar.waitForLoad();
120106
});
121107
});
@@ -127,11 +113,8 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
127113
test.beforeAll(
128114
'Get AI Lab extension version and open AI Lab navigation bar',
129115
async ({ page, runner, navigationBar }) => {
130-
const extensions = await navigationBar.openExtensions();
131-
extensionVersion = await extensions.getInstalledExtensionVersion('ai-lab', AI_LAB_CATALOG_EXTENSION_LABEL);
132-
133-
[page, webview] = await handleWebview(runner, page, navigationBar);
134-
aiLabPage = new AILabPage(page, webview);
116+
extensionVersion = await getExtensionVersion(navigationBar);
117+
aiLabPage = await reopenAILabDashboard(runner, page, navigationBar);
135118
await aiLabPage.navigationBar.waitForLoad();
136119
},
137120
);
@@ -227,8 +210,7 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
227210
let catalogPage: AILabCatalogPage;
228211

229212
test.beforeEach(`Open AI Lab Catalog`, async ({ runner, page, navigationBar }) => {
230-
[page, webview] = await handleWebview(runner, page, navigationBar);
231-
aiLabPage = new AILabPage(page, webview);
213+
aiLabPage = await reopenAILabDashboard(runner, page, navigationBar);
232214
await aiLabPage.navigationBar.waitForLoad();
233215

234216
catalogPage = await aiLabPage.navigationBar.openCatalog();
@@ -270,8 +252,7 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
270252
);
271253

272254
test.beforeAll(`Open AI Lab Catalog`, async ({ runner, page, navigationBar }) => {
273-
[page, webview] = await handleWebview(runner, page, navigationBar);
274-
aiLabPage = new AILabPage(page, webview);
255+
aiLabPage = await reopenAILabDashboard(runner, page, navigationBar);
275256
await aiLabPage.navigationBar.waitForLoad();
276257

277258
catalogPage = await aiLabPage.navigationBar.openCatalog();
@@ -362,8 +343,7 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
362343
const systemPrompt = 'Always respond with: "Hello, I am Chat Bot"';
363344

364345
test.beforeAll(`Open AI Lab Catalog`, async ({ runner, page, navigationBar }) => {
365-
[page, webview] = await handleWebview(runner, page, navigationBar);
366-
aiLabPage = new AILabPage(page, webview);
346+
aiLabPage = await reopenAILabDashboard(runner, page, navigationBar);
367347
await aiLabPage.navigationBar.waitForLoad();
368348

369349
catalogPage = await aiLabPage.navigationBar.openCatalog();
@@ -447,8 +427,7 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
447427
let recipesCatalogPage: AILabRecipesCatalogPage;
448428

449429
test.beforeEach(`Open Recipes Catalog`, async ({ runner, page, navigationBar }) => {
450-
[page, webview] = await handleWebview(runner, page, navigationBar);
451-
aiLabPage = new AILabPage(page, webview);
430+
aiLabPage = await reopenAILabDashboard(runner, page, navigationBar);
452431
await aiLabPage.navigationBar.waitForLoad();
453432

454433
recipesCatalogPage = await aiLabPage.navigationBar.openRecipesCatalog();

tests/playwright/src/model/ai-lab-catalog-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import type { Locator, Page } from '@playwright/test';
2020
import { expect as playExpect } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
22-
import { handleConfirmationDialog } from '@podman-desktop/tests-playwright';
22+
import { handleConfirmationDialog, podmanAILabExtension } from '@podman-desktop/tests-playwright';
2323
import { AILabCreatingModelServicePage } from './ai-lab-creating-model-service-page';
2424

2525
export class AILabCatalogPage extends AILabBasePage {
@@ -84,7 +84,7 @@ export class AILabCatalogPage extends AILabBasePage {
8484
await deleteButton.focus();
8585
await deleteButton.click();
8686
await this.page.waitForTimeout(1_000);
87-
await handleConfirmationDialog(this.page, 'Podman AI Lab', true, 'Confirm');
87+
await handleConfirmationDialog(this.page, podmanAILabExtension.extensionName, true, 'Confirm');
8888
}
8989

9090
async isModelDownloaded(modelName: string): Promise<boolean> {

tests/playwright/src/model/ai-lab-page.ts renamed to tests/playwright/src/model/ai-lab-dashboard-page.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { expect as playExpect } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
2222
import { AILabNavigationBar } from './ai-lab-navigation-bar';
2323

24-
export class AILabPage extends AILabBasePage {
24+
export class AILabDashboardPage extends AILabBasePage {
2525
readonly navigationBar: AILabNavigationBar;
2626

2727
constructor(page: Page, webview: Page) {

tests/playwright/src/model/ai-lab-model-service-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import { expect as playExpect } from '@playwright/test';
2020
import type { Locator, Page } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
22-
import { handleConfirmationDialog } from '@podman-desktop/tests-playwright';
22+
import { handleConfirmationDialog, podmanAILabExtension } from '@podman-desktop/tests-playwright';
2323
import { AILabCreatingModelServicePage } from './ai-lab-creating-model-service-page';
2424

2525
export class AiModelServicePage extends AILabBasePage {
@@ -59,7 +59,7 @@ export class AiModelServicePage extends AILabBasePage {
5959
await playExpect(this.deleteSelectedItems).toBeEnabled();
6060
await this.deleteSelectedItems.click();
6161

62-
await handleConfirmationDialog(this.page, 'Podman AI Lab', true, 'Confirm');
62+
await handleConfirmationDialog(this.page, podmanAILabExtension.extensionName, true, 'Confirm');
6363
}
6464

6565
async getCurrentModelCount(): Promise<number> {

tests/playwright/src/model/ai-lab-navigation-bar.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ import { AiModelServicePage } from './ai-lab-model-service-page';
2525
import { AILabCatalogPage } from './ai-lab-catalog-page';
2626
import { AILabPlaygroundsPage } from './ai-lab-playgrounds-page';
2727
import { AILabLocalServerPage } from './ai-lab-local-server-page';
28+
import { AILabDashboardPage } from './ai-lab-dashboard-page';
2829

2930
export class AILabNavigationBar extends AILabBasePage {
3031
readonly navigationBar: Locator;
32+
readonly dashboardButton: Locator;
3133
readonly recipesCatalogButton: Locator;
3234
readonly runningAppsButton: Locator;
3335
readonly catalogButton: Locator;
@@ -39,6 +41,7 @@ export class AILabNavigationBar extends AILabBasePage {
3941
constructor(page: Page, webview: Page) {
4042
super(page, webview, undefined);
4143
this.navigationBar = this.webview.getByRole('navigation', { name: 'PreferencesNavigation' });
44+
this.dashboardButton = this.navigationBar.getByRole('link', { name: 'Dashboard', exact: true });
4245
this.recipesCatalogButton = this.navigationBar.getByRole('link', { name: 'Recipe Catalog', exact: true });
4346
this.runningAppsButton = this.navigationBar.getByRole('link', { name: 'Running' });
4447
this.catalogButton = this.navigationBar.getByRole('link', { name: 'Catalog', exact: true });
@@ -52,6 +55,12 @@ export class AILabNavigationBar extends AILabBasePage {
5255
await playExpect(this.navigationBar).toBeVisible();
5356
}
5457

58+
async openDashboard(): Promise<AILabDashboardPage> {
59+
await playExpect(this.dashboardButton).toBeEnabled();
60+
await this.dashboardButton.click();
61+
return new AILabDashboardPage(this.page, this.webview);
62+
}
63+
5564
async openRecipesCatalog(): Promise<AILabRecipesCatalogPage> {
5665
await playExpect(this.recipesCatalogButton).toBeEnabled();
5766
await this.recipesCatalogButton.click();

tests/playwright/src/model/ai-lab-playground-details-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { expect as playExpect } from '@playwright/test';
2020
import type { Locator, Page } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
2222
import { AILabPlaygroundsPage } from './ai-lab-playgrounds-page';
23-
import { handleConfirmationDialog } from '@podman-desktop/tests-playwright';
23+
import { handleConfirmationDialog, podmanAILabExtension } from '@podman-desktop/tests-playwright';
2424

2525
export class AILabPlaygroundDetailsPage extends AILabBasePage {
2626
readonly name: string;
@@ -73,7 +73,7 @@ export class AILabPlaygroundDetailsPage extends AILabBasePage {
7373
async deletePlayground(): Promise<AILabPlaygroundsPage> {
7474
await playExpect(this.deletePlaygroundButton).toBeEnabled();
7575
await this.deletePlaygroundButton.click();
76-
await handleConfirmationDialog(this.page, 'Podman AI Lab', true, 'Confirm');
76+
await handleConfirmationDialog(this.page, podmanAILabExtension.extensionName, true, 'Confirm');
7777
return new AILabPlaygroundsPage(this.page, this.webview);
7878
}
7979

tests/playwright/src/model/ai-lab-playgrounds-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import type { Locator, Page } from '@playwright/test';
2020
import { expect as playExpect } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
22-
import { handleConfirmationDialog } from '@podman-desktop/tests-playwright';
22+
import { handleConfirmationDialog, podmanAILabExtension } from '@podman-desktop/tests-playwright';
2323
import { AILabPlaygroundDetailsPage } from './ai-lab-playground-details-page';
2424

2525
export class AILabPlaygroundsPage extends AILabBasePage {
@@ -60,7 +60,7 @@ export class AILabPlaygroundsPage extends AILabBasePage {
6060
const deleteButton = playgroundRow.getByRole('button', { name: 'Delete conversation', exact: true });
6161
await playExpect(deleteButton).toBeEnabled();
6262
await deleteButton.click();
63-
await handleConfirmationDialog(this.page, 'Podman AI Lab', true, 'Confirm');
63+
await handleConfirmationDialog(this.page, podmanAILabExtension.extensionName, true, 'Confirm');
6464
return this;
6565
}
6666

tests/playwright/src/model/ai-lab-running-apps-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import { expect as playExpect } from '@playwright/test';
2020
import type { Locator, Page } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
22-
import { handleConfirmationDialog } from '@podman-desktop/tests-playwright';
22+
import { handleConfirmationDialog, podmanAILabExtension } from '@podman-desktop/tests-playwright';
2323

2424
export class AiRunningAppsPage extends AILabBasePage {
2525
constructor(page: Page, webview: Page) {
@@ -66,7 +66,7 @@ export class AiRunningAppsPage extends AILabBasePage {
6666
await playExpect(deleteButton).toBeVisible();
6767
await deleteButton.click();
6868

69-
await handleConfirmationDialog(this.page, 'Podman AI Lab', true, 'Confirm');
69+
await handleConfirmationDialog(this.page, podmanAILabExtension.extensionName, true, 'Confirm');
7070
}
7171

7272
async appExists(appName: string): Promise<boolean> {

tests/playwright/src/model/ai-lab-service-details-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { expect as playExpect } from '@playwright/test';
2020
import type { Locator, Page } from '@playwright/test';
2121
import { AILabBasePage } from './ai-lab-base-page';
2222
import { AiModelServicePage } from './ai-lab-model-service-page';
23-
import { handleConfirmationDialog } from '@podman-desktop/tests-playwright';
23+
import { handleConfirmationDialog, podmanAILabExtension } from '@podman-desktop/tests-playwright';
2424

2525
export class AILabServiceDetailsPage extends AILabBasePage {
2626
readonly endpointURL: Locator;
@@ -47,7 +47,7 @@ export class AILabServiceDetailsPage extends AILabBasePage {
4747
async deleteService(): Promise<AiModelServicePage> {
4848
await playExpect(this.deleteServiceButton).toBeEnabled();
4949
await this.deleteServiceButton.click();
50-
await handleConfirmationDialog(this.page, 'Podman AI Lab', true, 'Confirm');
50+
await handleConfirmationDialog(this.page, podmanAILabExtension.extensionName, true, 'Confirm');
5151
return new AiModelServicePage(this.page, this.webview);
5252
}
5353

0 commit comments

Comments
 (0)