mirror of
https://github.com/podman-desktop/podman-desktop
synced 2026-04-21 09:37:22 +00:00
chore(test): refactoring of runner factory class (#17045)
* chore(test): refactoring of runner factory class
This commit is contained in:
parent
a0191823a1
commit
0eaf131dd6
5 changed files with 63 additions and 41 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -16,3 +16,4 @@ yarn.lock
|
||||||
extensions/podman/assets/
|
extensions/podman/assets/
|
||||||
extensions-extra/
|
extensions-extra/
|
||||||
__mocks__/@podman-desktop/api.ts
|
__mocks__/@podman-desktop/api.ts
|
||||||
|
contexts/meta/
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,9 @@ import type { ElectronApplication, JSHandle, Page } from '@playwright/test';
|
||||||
import { _electron as electron } from '@playwright/test';
|
import { _electron as electron } from '@playwright/test';
|
||||||
import type { BrowserWindow } from 'electron';
|
import type { BrowserWindow } from 'electron';
|
||||||
|
|
||||||
|
import { Runner } from '/@/runner/podman-desktop-runner';
|
||||||
import { RunnerFactory } from '/@/runner/runner-factory';
|
import { RunnerFactory } from '/@/runner/runner-factory';
|
||||||
|
import type { RunnerOptions } from '/@/runner/runner-options';
|
||||||
import { Runner } from './podman-desktop-runner';
|
|
||||||
import type { RunnerOptions } from './runner-options';
|
|
||||||
|
|
||||||
type WindowState = {
|
type WindowState = {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
|
|
|
||||||
|
|
@ -15,42 +15,58 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
/** biome-ignore-all lint/complexity/noStaticOnlyClass: <Singleton pattern> */
|
||||||
import { ChromeDevToolsProtocolRunner } from '/@/runner/chrome-dev-tools-protocol-runner';
|
import { ChromeDevToolsProtocolRunner } from '/@/runner/chrome-dev-tools-protocol-runner';
|
||||||
import { ElectronRunner } from '/@/runner/electron-runner';
|
import { ElectronRunner } from '/@/runner/electron-runner';
|
||||||
import type { Runner } from '/@/runner/podman-desktop-runner';
|
import type { Runner } from '/@/runner/podman-desktop-runner';
|
||||||
import { RunnerOptions } from '/@/runner/runner-options';
|
import { RunnerOptions } from '/@/runner/runner-options';
|
||||||
|
|
||||||
export class RunnerFactory {
|
export class RunnerFactory {
|
||||||
protected static _instance: Runner | undefined;
|
private static _instance: Runner | undefined;
|
||||||
|
private static _initializing: Promise<Runner> | undefined;
|
||||||
|
|
||||||
static async getInstance({
|
static async getInstance(runnerOptions?: RunnerOptions): Promise<Runner> {
|
||||||
runnerOptions = new RunnerOptions(),
|
if (RunnerFactory._instance) return RunnerFactory._instance;
|
||||||
}: {
|
if (RunnerFactory._initializing) return RunnerFactory._initializing;
|
||||||
runnerOptions?: RunnerOptions;
|
|
||||||
} = {}): Promise<Runner> {
|
RunnerFactory._initializing = RunnerFactory.create(runnerOptions ?? new RunnerOptions());
|
||||||
if (!this._instance) {
|
try {
|
||||||
const pdArgs = process.env.PODMAN_DESKTOP_ARGS;
|
RunnerFactory._instance = await RunnerFactory._initializing;
|
||||||
const pdBinary = process.env.PODMAN_DESKTOP_BINARY;
|
return RunnerFactory._instance;
|
||||||
const debugPort = process.env.DEBUGGING_PORT;
|
} finally {
|
||||||
if (
|
RunnerFactory._initializing = undefined;
|
||||||
(pdArgs && !pdBinary && !debugPort) ||
|
|
||||||
(pdBinary && !pdArgs && !debugPort) ||
|
|
||||||
(!pdArgs && !pdBinary && !debugPort)
|
|
||||||
) {
|
|
||||||
this._instance = new ElectronRunner({ runnerOptions });
|
|
||||||
} else if (pdBinary && debugPort) {
|
|
||||||
this._instance = new ChromeDevToolsProtocolRunner({ runnerOptions });
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
'Allowed combinations are standalone PODMAN_DESKTOP_ARGS or PODMAN_DESKTOP_BINARY or neither of them for electron runner. Or PODMAN_DESKTOP_BINARY and DEBUGGING_PORT for CDP runner...',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await this._instance.start();
|
|
||||||
}
|
}
|
||||||
return this._instance;
|
}
|
||||||
|
|
||||||
|
private static async create(runnerOptions: RunnerOptions): Promise<Runner> {
|
||||||
|
const runner = RunnerFactory.resolveRunner(runnerOptions);
|
||||||
|
await runner.start();
|
||||||
|
return runner;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resolveRunner(runnerOptions: RunnerOptions): Runner {
|
||||||
|
const pdArgs = process.env.PODMAN_DESKTOP_ARGS;
|
||||||
|
const pdBinary = process.env.PODMAN_DESKTOP_BINARY;
|
||||||
|
const debugPort = process.env.DEBUGGING_PORT;
|
||||||
|
|
||||||
|
if (pdArgs && pdBinary) {
|
||||||
|
throw new Error('PODMAN_DESKTOP_ARGS and PODMAN_DESKTOP_BINARY are mutually exclusive');
|
||||||
|
}
|
||||||
|
if (pdArgs && debugPort) {
|
||||||
|
throw new Error('DEBUGGING_PORT requires PODMAN_DESKTOP_BINARY, not PODMAN_DESKTOP_ARGS');
|
||||||
|
}
|
||||||
|
if (debugPort && !pdBinary) {
|
||||||
|
throw new Error('DEBUGGING_PORT requires PODMAN_DESKTOP_BINARY to be set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdBinary && debugPort) {
|
||||||
|
return new ChromeDevToolsProtocolRunner({ runnerOptions });
|
||||||
|
}
|
||||||
|
return new ElectronRunner({ runnerOptions });
|
||||||
}
|
}
|
||||||
|
|
||||||
static dispose(): void {
|
static dispose(): void {
|
||||||
this._instance = undefined;
|
RunnerFactory._instance = undefined;
|
||||||
|
RunnerFactory._initializing = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,18 +116,24 @@ test.describe
|
||||||
await playExpect(imagesPage.heading).toBeVisible({ timeout: 5_000 });
|
await playExpect(imagesPage.heading).toBeVisible({ timeout: 5_000 });
|
||||||
await navigationBar.goBack(); // Now on Containers with forward available
|
await navigationBar.goBack(); // Now on Containers with forward available
|
||||||
await playExpect(containerPage.heading).toBeVisible({ timeout: 5_000 });
|
await playExpect(containerPage.heading).toBeVisible({ timeout: 5_000 });
|
||||||
// Simulate trackpad swipe left (deltaX > 30 for forward)
|
|
||||||
await page.evaluate(() => {
|
|
||||||
const event = new WheelEvent('wheel', {
|
|
||||||
deltaX: 50, // > 30 threshold for forward navigation
|
|
||||||
deltaY: 0,
|
|
||||||
bubbles: true,
|
|
||||||
});
|
|
||||||
document.body.dispatchEvent(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verify navigation to Images
|
const forwardButton = page.getByRole('button', { name: 'Forward (hold for history)' });
|
||||||
await playExpect(imagesPage.heading).toBeVisible({ timeout: 5_000 });
|
await playExpect(forwardButton).toBeEnabled({ timeout: 5_000 });
|
||||||
|
|
||||||
|
// The app has a 500ms swipe cooldown (NavigationButtons.handleWheel) that may
|
||||||
|
// still be active from the previous trackpad-swipe-left test. Poll the dispatch
|
||||||
|
// so the event is retried once the cooldown expires.
|
||||||
|
await playExpect
|
||||||
|
.poll(
|
||||||
|
async () => {
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.body.dispatchEvent(new WheelEvent('wheel', { deltaX: 50, deltaY: 0, bubbles: true }));
|
||||||
|
});
|
||||||
|
return imagesPage.heading.isVisible();
|
||||||
|
},
|
||||||
|
{ timeout: 5_000 },
|
||||||
|
)
|
||||||
|
.toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Navigation shortcuts blocked when focus in input field', async ({ navigationBar, page }) => {
|
test('Navigation shortcuts blocked when focus in input field', async ({ navigationBar, page }) => {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export type FixtureOptions = {
|
||||||
export const test = base.extend<TestFixtures & FixtureOptions>({
|
export const test = base.extend<TestFixtures & FixtureOptions>({
|
||||||
runnerOptions: [new RunnerOptions(), { option: true }],
|
runnerOptions: [new RunnerOptions(), { option: true }],
|
||||||
runner: async ({ runnerOptions }, use) => {
|
runner: async ({ runnerOptions }, use) => {
|
||||||
const runner = await RunnerFactory.getInstance({ runnerOptions });
|
const runner = await RunnerFactory.getInstance(runnerOptions);
|
||||||
await use(runner);
|
await use(runner);
|
||||||
},
|
},
|
||||||
page: async ({ runner }, use) => {
|
page: async ({ runner }, use) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue