diff --git a/.github/workflows/e2e-main.yaml b/.github/workflows/e2e-main.yaml index 9f782421408..2036e937646 100644 --- a/.github/workflows/e2e-main.yaml +++ b/.github/workflows/e2e-main.yaml @@ -92,6 +92,7 @@ jobs: env: PODMANDESKTOP_CI_BOT_TOKEN: ${{ secrets.PODMANDESKTOP_CI_BOT_TOKEN }} TEST_PODMAN_MACHINE: 'true' + SKIP_KIND_INSTALL: 'true' run: yarn test:e2e - uses: actions/upload-artifact@v4 diff --git a/tests/playwright/src/index.ts b/tests/playwright/src/index.ts index 3e13d774149..9b3e3125f0e 100644 --- a/tests/playwright/src/index.ts +++ b/tests/playwright/src/index.ts @@ -61,3 +61,4 @@ export * from './model/pages/settings-bar'; export * from './model/pages/settings-page'; export * from './model/pages/welcome-page'; export * from './model/workbench/navigation'; +export * from './model/workbench/status-bar'; diff --git a/tests/playwright/src/model/pages/resources-page.ts b/tests/playwright/src/model/pages/resources-page.ts index 102b1296376..7a90bd48516 100644 --- a/tests/playwright/src/model/pages/resources-page.ts +++ b/tests/playwright/src/model/pages/resources-page.ts @@ -25,6 +25,7 @@ export class ResourcesPage extends SettingsPage { readonly featuredProviderResources: Locator; readonly podmanResources: Locator; readonly composeResources: Locator; + readonly kindResources: Locator; constructor(page: Page) { super(page, 'Resources'); @@ -32,5 +33,6 @@ export class ResourcesPage extends SettingsPage { this.featuredProviderResources = this.content.getByRole('region', { name: 'Featured Provider Resources' }); this.podmanResources = this.featuredProviderResources.getByRole('region', { name: 'podman', exact: true }); this.composeResources = this.featuredProviderResources.getByRole('region', { name: 'Compose', exact: true }); + this.kindResources = this.featuredProviderResources.getByRole('region', { name: 'kind', exact: true }); } } diff --git a/tests/playwright/src/model/workbench/status-bar.ts b/tests/playwright/src/model/workbench/status-bar.ts new file mode 100644 index 00000000000..fc815fadd75 --- /dev/null +++ b/tests/playwright/src/model/workbench/status-bar.ts @@ -0,0 +1,40 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import type { Locator, Page } from '@playwright/test'; + +import { handleConfirmationDialog } from '../../utility/operations'; +import { BasePage } from '../pages/base-page'; + +export class StatusBar extends BasePage { + readonly kindInstallationButton: Locator; + + constructor(page: Page) { + super(page); + this.kindInstallationButton = this.page.getByTitle( + 'Kind not found on your system, click to download and install it', + ); + } + + public async installKindCLI(): Promise { + await this.kindInstallationButton.click(); + await handleConfirmationDialog(this.page, 'Kind'); + await handleConfirmationDialog(this.page, 'Kind'); + await handleConfirmationDialog(this.page, 'Kind', true, 'OK'); + } +} diff --git a/tests/playwright/src/specs/kind.spec.ts b/tests/playwright/src/specs/kind.spec.ts new file mode 100644 index 00000000000..ede72feb64c --- /dev/null +++ b/tests/playwright/src/specs/kind.spec.ts @@ -0,0 +1,87 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import { type Page } from '@playwright/test'; +import { expect as playExpect } from '@playwright/test'; +import { afterAll, beforeAll, beforeEach, describe, test } from 'vitest'; + +import { ExtensionsPage } from '../model/pages/extensions-page'; +import { ResourcesPage } from '../model/pages/resources-page'; +import { WelcomePage } from '../model/pages/welcome-page'; +import { NavigationBar } from '../model/workbench/navigation'; +import { StatusBar } from '../model/workbench/status-bar'; +import { PodmanDesktopRunner } from '../runner/podman-desktop-runner'; +import type { RunnerTestContext } from '../testContext/runner-test-context'; +import { waitForPodmanMachineStartup } from '../utility/wait'; + +let pdRunner: PodmanDesktopRunner; +let page: Page; +let navigationBar: NavigationBar; +let resourcesPage: ResourcesPage; +let statusBar: StatusBar; +const extensionLabel: string = 'podman-desktop.kind'; +const skipKindInstallation = process.env.SKIP_KIND_INSTALL ? process.env.SKIP_KIND_INSTALL : false; + +beforeAll(async () => { + pdRunner = new PodmanDesktopRunner(); + page = await pdRunner.start(); + pdRunner.setVideoAndTraceName('kind-e2e'); + const welcomePage = new WelcomePage(page); + await welcomePage.handleWelcomePage(true); + await waitForPodmanMachineStartup(page); + navigationBar = new NavigationBar(page); + resourcesPage = new ResourcesPage(page); + statusBar = new StatusBar(page); +}); + +beforeEach(async ctx => { + ctx.pdRunner = pdRunner; +}); + +afterAll(async () => { + await pdRunner.close(); +}); + +describe('Kind End-to-End Tests', async () => { + test.skipIf(skipKindInstallation)('Install Kind CLI', async () => { + await navigationBar.openSettings(); + await playExpect(resourcesPage.kindResources).not.toBeVisible(); + await statusBar.installKindCLI(); + await playExpect(statusBar.kindInstallationButton).not.toBeVisible(); + }); + test('Verify that Kind CLI is installed', async () => { + await navigationBar.openSettings(); + await playExpect(resourcesPage.kindResources).toBeVisible(); + }); + test('Kind extension lifecycle', async () => { + const extensionsPage = new ExtensionsPage(page); + await navigationBar.openExtensions(); + const kindExtension = await extensionsPage.getInstalledExtension('Kind extension', extensionLabel); + await playExpect + .poll(async () => await extensionsPage.extensionIsInstalled(extensionLabel), { timeout: 10000 }) + .toBeTruthy(); + await playExpect(kindExtension.status).toHaveText('ACTIVE'); + await kindExtension.disableExtension(); + await navigationBar.openSettings(); + await playExpect(resourcesPage.kindResources).not.toBeVisible(); + await navigationBar.openExtensions(); + await kindExtension.enableExtension(); + await navigationBar.openSettings(); + await playExpect(resourcesPage.kindResources).toBeVisible(); + }); +}); diff --git a/tests/playwright/src/utility/operations.ts b/tests/playwright/src/utility/operations.ts index f4ae0556b85..5adb3303f55 100644 --- a/tests/playwright/src/utility/operations.ts +++ b/tests/playwright/src/utility/operations.ts @@ -147,11 +147,15 @@ export async function handleConfirmationDialog( page: Page, dialogTitle = 'Confirmation', confirm = true, + confirmationButton = 'Yes', + cancelButton = 'Cancel', ): Promise { // wait for dialog to appear using waitFor const dialog = page.getByRole('dialog', { name: dialogTitle, exact: true }); await dialog.waitFor({ state: 'visible', timeout: 3000 }); - const button = confirm ? dialog.getByRole('button', { name: 'Yes' }) : dialog.getByRole('button', { name: 'Cancel' }); + const button = confirm + ? dialog.getByRole('button', { name: confirmationButton }) + : dialog.getByRole('button', { name: cancelButton }); await button.click(); }