Skip to content

Commit d255d95

Browse files
authored
feat(test): add pw fixtures (podman-desktop#8745)
* feat(test): add pw fixtures Signed-off-by: Vladimir Lazar <[email protected]>
1 parent 0c8574c commit d255d95

19 files changed

+275
-382
lines changed

playwright.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { defineConfig, devices } from '@playwright/test';
2121
export default defineConfig({
2222
outputDir: 'tests/playwright/output/',
2323
workers: 1,
24+
timeout: 60000,
2425

2526
reporter: [
2627
['list'],

tests/playwright/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export * from './runner/podman-desktop-runner';
2222
export * from './setupFiles/setup-registry';
2323
export type { RunnerTestContext } from './testContext/runner-test-context';
2424
export * from './utility/cleanup';
25+
export * from './utility/fixtures';
2526
export * from './utility/operations';
2627
export * from './utility/platform';
2728
export * from './utility/wait';

tests/playwright/src/runner/podman-desktop-runner.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,27 @@ export class PodmanDesktopRunner {
4343
private _autoUpdate: boolean;
4444
private _autoCheckUpdate: boolean;
4545

46-
constructor({
46+
private static _instance: PodmanDesktopRunner | undefined;
47+
48+
static async getInstance({
49+
profile = '',
50+
customFolder = 'podman-desktop',
51+
autoUpdate = true,
52+
autoCheckUpdate = true,
53+
}: {
54+
profile?: string;
55+
customFolder?: string;
56+
autoUpdate?: boolean;
57+
autoCheckUpdate?: boolean;
58+
} = {}): Promise<PodmanDesktopRunner> {
59+
if (!PodmanDesktopRunner._instance) {
60+
PodmanDesktopRunner._instance = new PodmanDesktopRunner({ profile, customFolder, autoUpdate, autoCheckUpdate });
61+
await PodmanDesktopRunner._instance.start();
62+
}
63+
return PodmanDesktopRunner._instance;
64+
}
65+
66+
private constructor({
4767
profile = '',
4868
customFolder = 'podman-desktop',
4969
autoUpdate = true,
@@ -63,7 +83,8 @@ export class PodmanDesktopRunner {
6383

6484
public async start(): Promise<Page> {
6585
if (this.isRunning()) {
66-
throw Error('Podman Desktop is already running');
86+
console.log('Podman Desktop is already running');
87+
return this.getPage();
6788
}
6889

6990
try {
@@ -215,6 +236,7 @@ export class PodmanDesktopRunner {
215236
}
216237
}
217238
this._running = false;
239+
PodmanDesktopRunner._instance = undefined;
218240

219241
if (this._videoAndTraceName) {
220242
const videoPath = join(this._testOutput, 'videos', `${this._videoAndTraceName}.webm`);

tests/playwright/src/specs/compose-onboarding-smoke.spec.ts

+20-30
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
***********************************************************************/
1818

1919
import type { Page } from '@playwright/test';
20-
import { expect as playExpect, test } from '@playwright/test';
2120

2221
import { CLIToolsPage } from '../model/pages/cli-tools-page';
2322
import { ComposeLocalInstallPage } from '../model/pages/compose-onboarding/compose-local-install-page';
@@ -27,43 +26,34 @@ import { ComposeWideInstallPage } from '../model/pages/compose-onboarding/compos
2726
import { ResourceCliCardPage } from '../model/pages/resource-cli-card-page';
2827
import { ResourcesPage } from '../model/pages/resources-page';
2928
import { SettingsBar } from '../model/pages/settings-bar';
30-
import { WelcomePage } from '../model/pages/welcome-page';
31-
import { NavigationBar } from '../model/workbench/navigation';
32-
import { PodmanDesktopRunner } from '../runner/podman-desktop-runner';
29+
import type { NavigationBar } from '../model/workbench/navigation';
30+
import { expect as playExpect, test } from '../utility/fixtures';
3331
import { isCI, isLinux } from '../utility/platform';
3432

3533
const RESOURCE_NAME: string = 'Compose';
3634

37-
let pdRunner: PodmanDesktopRunner;
38-
let page: Page;
39-
let navBar: NavigationBar;
4035
let composeVersion: string;
4136
// property that will make sure that on linux we can run only partial tests, by default this is turned off
4237
const composePartialInstallation = process.env.COMPOSE_PARTIAL_INSTALL ? process.env.COMPOSE_PARTIAL_INSTALL : false;
4338

4439
test.skip(!!isCI && isLinux, 'Tests suite should not run on Linux platform');
4540

46-
test.beforeAll(async () => {
47-
pdRunner = new PodmanDesktopRunner();
48-
page = await pdRunner.start();
41+
test.beforeAll(async ({ pdRunner, welcomePage }) => {
4942
pdRunner.setVideoAndTraceName('compose-onboarding-e2e');
50-
51-
const welcomePage = new WelcomePage(page);
5243
await welcomePage.handleWelcomePage(true);
53-
navBar = new NavigationBar(page);
5444
});
5545

56-
test.afterAll(async () => {
46+
test.afterAll(async ({ pdRunner }) => {
5747
await pdRunner.close();
5848
});
5949

6050
test.describe.serial('Compose onboarding workflow verification @smoke', () => {
61-
test.afterEach(async () => {
62-
await navBar.openDashboard();
51+
test.afterEach(async ({ navigationBar }) => {
52+
await navigationBar.openDashboard();
6353
});
6454

65-
test('Compose onboarding button Setup is available', async () => {
66-
await navBar.openSettings();
55+
test('Compose onboarding button Setup is available', async ({ page, navigationBar }) => {
56+
await navigationBar.openSettings();
6757
const settingsBar = new SettingsBar(page);
6858
const resourcesPage = await settingsBar.openTabPage(ResourcesPage);
6959

@@ -77,8 +67,8 @@ test.describe.serial('Compose onboarding workflow verification @smoke', () => {
7767
).toBeVisible({ timeout: 10000 });
7868
});
7969

80-
test('Can enter Compose onboarding', async () => {
81-
const onboardingPage = await openComposeOnboarding(page);
70+
test('Can enter Compose onboarding', async ({ page, navigationBar }) => {
71+
const onboardingPage = await openComposeOnboarding(page, navigationBar);
8272

8373
await playExpect(onboardingPage.heading).toBeVisible();
8474

@@ -89,8 +79,8 @@ test.describe.serial('Compose onboarding workflow verification @smoke', () => {
8979
composeVersion = await onboardingVersionPage.getVersion();
9080
});
9181

92-
test('Can install Compose locally', async () => {
93-
const onboardingPage = await openComposeOnboarding(page);
82+
test('Can install Compose locally', async ({ page, navigationBar }) => {
83+
const onboardingPage = await openComposeOnboarding(page, navigationBar);
9484
await onboardingPage.nextStepButton.click();
9585

9686
const onboardigLocalPage = new ComposeLocalInstallPage(page);
@@ -105,8 +95,8 @@ test.describe.serial('Compose onboarding workflow verification @smoke', () => {
10595
await skipOkButton.click();
10696
});
10797

108-
test('Can resume Compose onboarding and it can be canceled', async () => {
109-
await openComposeOnboarding(page);
98+
test('Can resume Compose onboarding and it can be canceled', async ({ page, navigationBar }) => {
99+
await openComposeOnboarding(page, navigationBar);
110100
const onboardingLocalPage = new ComposeLocalInstallPage(page);
111101

112102
await playExpect(onboardingLocalPage.onboardingStatusMessage).toHaveText('Compose successfully Downloaded');
@@ -119,10 +109,10 @@ test.describe.serial('Compose onboarding workflow verification @smoke', () => {
119109
await skipOkButton.click();
120110
});
121111

122-
test('Can install Compose system-wide', async () => {
112+
test('Can install Compose system-wide', async ({ page, navigationBar }) => {
123113
test.skip(!!composePartialInstallation, 'Partial installation of Compose is enabled');
124114

125-
const onboardingPage = await openComposeOnboarding(page);
115+
const onboardingPage = await openComposeOnboarding(page, navigationBar);
126116
await onboardingPage.nextStepButton.click();
127117

128118
const onboardingWidePage = new ComposeWideInstallPage(page);
@@ -136,10 +126,10 @@ test.describe.serial('Compose onboarding workflow verification @smoke', () => {
136126
await playExpect(resourcesPage.heading).toBeVisible();
137127
});
138128

139-
test('Verify Compose was installed', async () => {
129+
test('Verify Compose was installed', async ({ page, navigationBar }) => {
140130
test.skip(!!composePartialInstallation, 'Partial installation of Compose is enabled');
141131

142-
await navBar.openSettings();
132+
await navigationBar.openSettings();
143133
const settingsBar = new SettingsBar(page);
144134
const resourcesPage = await settingsBar.openTabPage(ResourcesPage);
145135
await playExpect.poll(async () => await resourcesPage.resourceCardIsVisible(RESOURCE_NAME)).toBeTruthy();
@@ -154,8 +144,8 @@ test.describe.serial('Compose onboarding workflow verification @smoke', () => {
154144
});
155145
});
156146

157-
async function openComposeOnboarding(page: Page): Promise<ComposeOnboardingPage> {
158-
await navBar.openSettings();
147+
async function openComposeOnboarding(page: Page, navigationBar: NavigationBar): Promise<ComposeOnboardingPage> {
148+
await navigationBar.openSettings();
159149
const settingsBar = new SettingsBar(page);
160150
const resourcesPage = await settingsBar.openTabPage(ResourcesPage);
161151
await playExpect(resourcesPage.heading).toBeVisible();

tests/playwright/src/specs/container-smoke.spec.ts

+14-38
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,24 @@
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
1818

19-
import type { Page } from '@playwright/test';
20-
import { expect as playExpect, test } from '@playwright/test';
21-
2219
import { ContainerState } from '../model/core/states';
2320
import type { ContainerInteractiveParams } from '../model/core/types';
2421
import { ContainersPage } from '../model/pages/containers-page';
2522
import { ImageDetailsPage } from '../model/pages/image-details-page';
2623
import type { ImagesPage } from '../model/pages/images-page';
27-
import { WelcomePage } from '../model/pages/welcome-page';
2824
import { NavigationBar } from '../model/workbench/navigation';
29-
import { PodmanDesktopRunner } from '../runner/podman-desktop-runner';
25+
import { expect as playExpect, test } from '../utility/fixtures';
3026
import { deleteContainer, deleteImage } from '../utility/operations';
3127
import { waitForPodmanMachineStartup, waitWhile } from '../utility/wait';
3228

33-
let pdRunner: PodmanDesktopRunner;
34-
let page: Page;
3529
const imageToPull = 'ghcr.io/linuxcontainers/alpine';
3630
const imageTag = 'latest';
3731
const containerToRun = 'alpine-container';
3832
const containerList = ['first', 'second', 'third'];
3933
const containerStartParams: ContainerInteractiveParams = { attachTerminal: false };
4034

41-
test.beforeAll(async () => {
42-
pdRunner = new PodmanDesktopRunner();
43-
page = await pdRunner.start();
35+
test.beforeAll(async ({ pdRunner, welcomePage, page }) => {
4436
pdRunner.setVideoAndTraceName('containers-e2e');
45-
const welcomePage = new WelcomePage(page);
4637
await welcomePage.handleWelcomePage(true);
4738
await waitForPodmanMachineStartup(page);
4839
// wait giving a time to podman desktop to load up
@@ -65,7 +56,7 @@ test.beforeAll(async () => {
6556
}
6657
});
6758

68-
test.afterAll(async () => {
59+
test.afterAll(async ({ pdRunner, page }) => {
6960
test.setTimeout(90000);
7061

7162
try {
@@ -83,29 +74,25 @@ test.afterAll(async () => {
8374
test.describe.serial('Verification of container creation workflow @smoke', () => {
8475
test.describe.configure({ retries: 2 });
8576

86-
test(`Pulling of '${imageToPull}:${imageTag}' image`, async () => {
77+
test(`Pulling of '${imageToPull}:${imageTag}' image`, async ({ navigationBar }) => {
8778
test.setTimeout(90000);
8879

89-
const navigationBar = new NavigationBar(page);
9080
let images = await navigationBar.openImages();
9181
const pullImagePage = await images.openPullImage();
9282
images = await pullImagePage.pullImage(imageToPull, imageTag);
9383

9484
await playExpect.poll(async () => await images.waitForImageExists(imageToPull)).toBeTruthy();
9585
});
9686

97-
test(`Start a container '${containerToRun}' from image`, async () => {
98-
const navigationBar = new NavigationBar(page);
87+
test(`Start a container '${containerToRun}' from image`, async ({ navigationBar }) => {
9988
let images = await navigationBar.openImages();
10089
const imageDetails = await images.openImageDetails(imageToPull);
10190
const runImage = await imageDetails.openRunImage();
102-
await pdRunner.screenshot('containers-run-image.png');
10391
const containers = await runImage.startContainer(containerToRun, containerStartParams);
10492
await playExpect(containers.header).toBeVisible();
10593
await playExpect
10694
.poll(async () => await containers.containerExists(containerToRun), { timeout: 10000 })
10795
.toBeTruthy();
108-
await pdRunner.screenshot('containers-container-exists.png');
10996
const containerDetails = await containers.openContainersDetails(containerToRun);
11097
await playExpect
11198
.poll(async () => await containerDetails.getState(), { timeout: 10000 })
@@ -115,8 +102,7 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
115102
playExpect(await images.getCurrentStatusOfImage(imageToPull)).toBe('USED');
116103
});
117104

118-
test('Test navigation between pages', async () => {
119-
const navigationBar = new NavigationBar(page);
105+
test('Test navigation between pages', async ({ navigationBar }) => {
120106
const containers = await navigationBar.openContainers();
121107

122108
const containersDetails = await containers.openContainersDetails(containerToRun);
@@ -129,14 +115,12 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
129115
await containersDetails.closeButton.click();
130116
await playExpect(containers.heading).toBeVisible();
131117
});
132-
test('Open a container details', async () => {
133-
const navigationBar = new NavigationBar(page);
118+
test('Open a container details', async ({ navigationBar }) => {
134119
const containers = await navigationBar.openContainers();
135120
const containersDetails = await containers.openContainersDetails(containerToRun);
136121
await playExpect(containersDetails.heading).toBeVisible();
137122
await playExpect(containersDetails.heading).toContainText(containerToRun);
138123
// test state of container in summary tab
139-
await pdRunner.screenshot('containers-container-details.png');
140124
const containerState = await containersDetails.getState();
141125
playExpect(containerState).toContain(ContainerState.Running);
142126
// check Logs output
@@ -149,8 +133,7 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
149133
await containersDetails.activateTab('Terminal');
150134
// TODO: After updating of accessibility of various element in containers pages, we can extend test
151135
});
152-
test('Redirecting to image details from a container details', async () => {
153-
const navigationBar = new NavigationBar(page);
136+
test('Redirecting to image details from a container details', async ({ page, navigationBar }) => {
154137
const containers = await navigationBar.openContainers();
155138
const containersDetails = await containers.openContainersDetails(containerToRun);
156139
await playExpect(containersDetails.heading).toBeVisible();
@@ -161,8 +144,7 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
161144
await playExpect(imageDetails.heading).toBeVisible();
162145
await playExpect(imageDetails.heading).toContainText(imageToPull);
163146
});
164-
test('Stopping a container from Container details', async () => {
165-
const navigationBar = new NavigationBar(page);
147+
test('Stopping a container from Container details', async ({ navigationBar }) => {
166148
const containers = await navigationBar.openContainers();
167149
const containersDetails = await containers.openContainersDetails(containerToRun);
168150
await playExpect(containersDetails.heading).toBeVisible();
@@ -178,8 +160,7 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
178160
await playExpect(startButton).toBeVisible();
179161
});
180162

181-
test(`Start a container from the Containers page`, async () => {
182-
const navigationBar = new NavigationBar(page);
163+
test(`Start a container from the Containers page`, async ({ navigationBar }) => {
183164
const containers = await navigationBar.openContainers();
184165
const containersDetails = await containers.openContainersDetails(containerToRun);
185166
await playExpect(containersDetails.heading).toBeVisible();
@@ -196,8 +177,7 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
196177
.toContain(ContainerState.Running);
197178
});
198179

199-
test(`Stop a container from the Containers page`, async () => {
200-
const navigationBar = new NavigationBar(page);
180+
test(`Stop a container from the Containers page`, async ({ navigationBar }) => {
201181
const containers = await navigationBar.openContainers();
202182
const containersDetails = await containers.openContainersDetails(containerToRun);
203183
await playExpect(containersDetails.heading).toBeVisible();
@@ -214,8 +194,7 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
214194
.toContain(ContainerState.Exited);
215195
});
216196

217-
test('Deleting a container from Container details', async () => {
218-
const navigationBar = new NavigationBar(page);
197+
test('Deleting a container from Container details', async ({ navigationBar }) => {
219198
const containers = await navigationBar.openContainers();
220199
const containersDetails = await containers.openContainersDetails(containerToRun);
221200
await playExpect(containersDetails.heading).toContainText(containerToRun);
@@ -224,9 +203,8 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
224203
await playExpect.poll(async () => await containersPage.containerExists(containerToRun)).toBeFalsy();
225204
});
226205

227-
test(`Deleting a container from the Containers page`, async () => {
206+
test(`Deleting a container from the Containers page`, async ({ navigationBar }) => {
228207
//re-start the container from an image
229-
const navigationBar = new NavigationBar(page);
230208
let images = await navigationBar.openImages();
231209
const imageDetails = await images.openImageDetails(imageToPull);
232210
const runImage = await imageDetails.openRunImage();
@@ -235,7 +213,6 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
235213
await playExpect
236214
.poll(async () => await containers.containerExists(containerToRun), { timeout: 10000 })
237215
.toBeTruthy();
238-
await pdRunner.screenshot('containers-container-exists.png');
239216
const containerDetails = await containers.openContainersDetails(containerToRun);
240217
await playExpect
241218
.poll(async () => await containerDetails.getState(), { timeout: 10000 })
@@ -253,10 +230,9 @@ test.describe.serial('Verification of container creation workflow @smoke', () =>
253230
.toBeFalsy();
254231
});
255232

256-
test('Prune containers', async () => {
233+
test('Prune containers', async ({ page, navigationBar }) => {
257234
test.setTimeout(120000);
258235

259-
const navigationBar = new NavigationBar(page);
260236
//Start 3 containers
261237
for (const container of containerList) {
262238
const images = await navigationBar.openImages();

0 commit comments

Comments
 (0)