Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: added image checker extension installation tests #61

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.vscode
node_modules
test-results
output
15 changes: 12 additions & 3 deletions podman-desktop-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"icon": "icon.png",
"publisher": "redhat",
"license": "Apache-2.0",
"type": "module",
"engines": {
"podman-desktop": "^1.6.3"
"podman-desktop": "^1.14.0"
},
"main": "./dist/extension.js",
"contributes": {
Expand All @@ -16,16 +17,24 @@
"scripts": {
"build": "vite build",
"test": "vitest run --coverage --passWithNoTests",
"test:e2e:setup": "xvfb-maybe --auto-servernum --server-args='-screen 0 1280x960x24' --",
"test:e2e": "cross-env npm run test:e2e:setup npx playwright test ./tests/src",
"test:watch": "vitest watch --coverage --passWithNoTests",
"watch": "tsc -w"
},
"dependencies": {},
"devDependencies": {
"@playwright/test": "^1.49.0",
"@podman-desktop/api": "^1.6.3",
"@podman-desktop/tests-playwright": "next",
"@types/node": "^18",
"cross-env": "^7.0.3",
"electron": "^33.2.1",
"mkdirp": "^3.0.1",
"typescript": "5.3.3",
"vite": "^5.0.9",
"vitest": "^2.1.8",
"xvfb-maybe": "^0.2.1",
"zip-local": "^0.3.5"
}
},
"packageManager": "[email protected]+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447"
}
128 changes: 128 additions & 0 deletions podman-desktop-extension/tests/src/image-checker.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**********************************************************************
* 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 { NavigationBar } from '@podman-desktop/tests-playwright';
import {
expect as playExpect,
ExtensionCardPage,
RunnerOptions,
test,
} from '@podman-desktop/tests-playwright';
import { ImageCheckerExtensionPage } from './pages/image-checker-extension-page';
import { ImageCheckerImageDetailsPage } from './pages/image-checker-image-details-page';

let extensionInstalled = false;
let extensionCard: ExtensionCardPage;
const imageName = 'ghcr.io/redhat-developer/podman-desktop-image-checker-openshift-ext:latest';
const extensionLabel = 'redhat.openshift-checker';
const extensionLabelName = 'openshift-checker';
const activeExtensionStatus = 'ACTIVE';
const disabledExtensionStatus = 'DISABLED';
const imageToCheck = 'ghcr.io/linuxcontainers/alpine';
test.use({
runnerOptions: new RunnerOptions({ customFolder: 'image-checker-tests-pd', autoUpdate: false, autoCheckUpdates: false }),
});
test.beforeAll(async ({ runner, page, welcomePage }) => {
runner.setVideoAndTraceName('image-checker-e2e');
await welcomePage.handleWelcomePage(true);
extensionCard = new ExtensionCardPage(page, extensionLabelName, extensionLabel);
});

test.afterAll(async ({ runner }) => {
await runner.close();
});

test.describe.serial('Red Hat Image Checker extension installation', () => {
test('Check if extension is already installed', async ({ navigationBar }) => {
const extensions = await navigationBar.openExtensions();
if (await extensions.extensionIsInstalled(extensionLabel)) {
extensionInstalled = true;
}
});

test('Remove old version of the extension', async ({ navigationBar }) => {
test.skip(!extensionInstalled);
await removeExtension(navigationBar);
});

test('Extension can be installed from an OCI image', async ({ navigationBar }) => {
test.setTimeout(180000);
const extensions = await navigationBar.openExtensions();
await extensions.installExtensionFromOCIImage(imageName);
await playExpect(extensionCard.card).toBeVisible();
});

test('Extension is installed and active, extension card is present', async ({ navigationBar }) => {
const extensions = await navigationBar.openExtensions();
await playExpect
.poll(async () => await extensions.extensionIsInstalled(extensionLabel), { timeout: 60000 })
.toBeTruthy();
const extensionCard = await extensions.getInstalledExtension(extensionLabelName, extensionLabel);
await playExpect(extensionCard.status, `Extension status is: ${extensionCard.status}`).toHaveText(activeExtensionStatus);
});

test("Extension details show correct status, no error", async ({ page, navigationBar }) => {
const extensions = await navigationBar.openExtensions();
const extensionCard = await extensions.getInstalledExtension(extensionLabelName, extensionLabel);
await extensionCard.openExtensionDetails('Red Hat OpenShift Checker extension');
const detailsPage = new ImageCheckerExtensionPage(page);
await playExpect(detailsPage.heading).toBeVisible();
await playExpect(detailsPage.status).toHaveText(activeExtensionStatus);
const errorTab = detailsPage.tabs.getByRole('button', { name: 'Error' });
// we would like to propagate the error's stack trace into test failure message
let stackTrace = '';
if ((await errorTab.count()) > 0) {
await detailsPage.activateTab('Error');
stackTrace = await detailsPage.errorStackTrace.innerText();
}
await playExpect(errorTab, `Error Tab was present with stackTrace: ${stackTrace}`).not.toBeVisible();
});

test('Image Checker tab is present in Image Details Page', async ({ navigationBar }) => {
await imageCheckerTabPresent(navigationBar);
});

test('Extension can be removed', async ({ navigationBar }) => {
await removeExtension(navigationBar);
});
});

async function removeExtension(navigationBar: NavigationBar): Promise<void> {
const extensions = await navigationBar.openExtensions();
const extensionCard = await extensions.getInstalledExtension(extensionLabelName, extensionLabel);
await extensionCard.disableExtension();
await extensionCard.removeExtension();
await playExpect
.poll(async () => await extensions.extensionIsInstalled(extensionLabel), { timeout: 15000 })
.toBeFalsy();
}

async function imageCheckerTabPresent(navigationBar: NavigationBar) {
const imagesPage = await navigationBar.openImages();
await playExpect(imagesPage.heading).toBeVisible();

const pullImagePage = await imagesPage.openPullImage();
const updatedImages = await pullImagePage.pullImage(imageToCheck);

const exists = await updatedImages.waitForImageExists(imageToCheck);
playExpect(exists, `${imageToCheck} image not found in the image list`).toBeTruthy();

const imageDetailPage = await imagesPage.openImageDetails(imageToCheck);
const imageDetailsPage = new ImageCheckerImageDetailsPage(imageDetailPage.page, imageToCheck);
await playExpect(imageDetailsPage.imageCheckerTab).toBeVisible();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**********************************************************************
* 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 { ExtensionDetailsPage } from '@podman-desktop/tests-playwright';

export class ImageCheckerExtensionPage extends ExtensionDetailsPage {
constructor(page: Page) {
super(page, 'Red Hat OpenShift Checker extension');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**********************************************************************
* 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 { DetailsPage } from '@podman-desktop/tests-playwright';

export class ImageCheckerImageDetailsPage extends DetailsPage {
readonly imageCheckerTab: Locator;

constructor(page: Page, name: string) {
super(page, name);
this.imageCheckerTab = this.tabs.getByText('Check');
}
}
16 changes: 16 additions & 0 deletions podman-desktop-extension/tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"strictNullChecks": true,
"lib": [ "ES2020", "webworker" ],
"module": "esnext",
"target": "esnext",
"sourceMap": true,
"rootDir": "src",
"outDir": "dist",
"skipLibCheck": true,
"types": [ "node" ],
"allowSyntheticDefaultImports": true,
"moduleResolution": "Node",
"esModuleInterop": true
}
}
Loading
Loading