Skip to content

Commit

Permalink
e2e tests added
Browse files Browse the repository at this point in the history
Signed-off-by: xbabalov <tbabalov@redhat.com>
  • Loading branch information
xbabalov committed Oct 8, 2024
1 parent ff2e86f commit a9c5baf
Show file tree
Hide file tree
Showing 8 changed files with 1,274 additions and 777 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ package-lock.json
redhat-sandbox.cdix
test-resources
yarn-error.log
coverage
coverage
tests/**/output
test-results
15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"icon": "icon.png",
"publisher": "redhat",
"license": "Apache-2.0",
"type": "module",
"engines": {
"podman-desktop": "^1.10.0"
},
Expand Down Expand Up @@ -61,29 +62,37 @@
"watch": "vite build -w",
"format:check": "prettier --check \"**/*.ts\" \"scripts/*.js\"",
"format:fix": "prettier --write \"**/*.ts\" \"scripts/*.js\"",
"test": "vitest run --coverage"
"test": "vitest run --coverage",
"test:e2e:setup": "xvfb-maybe --auto-servernum --server-args='-screen 0 1280x960x24' --",
"test:e2e": "npm run test:e2e:setup npx playwright test tests/src"
},
"dependencies": {
"@kubernetes/client-node": "^0.22.0",
"@podman-desktop/api": "^1.12.0",
"fs-extra": "^11.2.0",
"got": "^14.4.2",
"js-yaml": "^4.1.0"
"js-yaml": "^4.1.0",
"node-fetch": "^2.6.1"
},
"devDependencies": {
"7zip-min": "^1.4.5",
"@playwright/test": "^1.47.1",
"@podman-desktop/tests-playwright": "next",
"@types/fs-extra": "^11.0.4",
"@types/node": "^20.16.10",
"@vitest/coverage-v8": "^2.0.5",
"7zip-min": "^1.4.5",
"byline": "^5.0.0",
"copyfiles": "^2.4.1",
"cross-env": "7.0.3",
"electron": "^32.1.1",
"jsdom": "^25.0.1",
"mkdirp": "^3.0.1",
"prettier": "^3.3.3",
"typescript": "^5.6.2",
"vite": "^5.4.8",
"vitest": "^2.0.5",
"vscode-uri": "^3.0.8",
"xvfb-maybe": "^0.2.1",
"zip-local": "^0.3.5"
}
}
41 changes: 41 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**********************************************************************
* 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 { defineConfig, devices } from '@playwright/test';

export default defineConfig({
outputDir: 'tests/output/',
workers: 1,
timeout: 60000,

reporter: [
['list'],
['junit', { outputFile: 'tests/output/junit-results.xml' }],
['json', { outputFile: 'tests/output/json-results.json' }],
['html', { open: 'never', outputFolder: 'tests/playwright/output/html-results' }],
],

projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
},
},
],
});
164 changes: 164 additions & 0 deletions tests/src/developer-sandbox.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/**********************************************************************
* 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 { ResourcesPage, expect as playExpect, ExtensionCardPage, RunnerOptions, test, AuthenticationPage } from '@podman-desktop/tests-playwright';
import { DeveloperSandboxPage } from './model/pages/developer-sandbox-page';

let extensionInstalled = false;
let extensionCard: ExtensionCardPage;
const imageName = 'ghcr.io/redhat-developer/podman-desktop-sandbox-ext:latest';
const extensionLabel = 'redhat.redhat-sandbox';
const extensionLabelName = 'redhat-sandbox';
const extensionResourceLabel = 'redhat.sandbox';
const extensionProvider = 'Developer Sandbox Provider';
const activeExtensionStatus = 'ACTIVE';
const disabledExtensionStatus = 'DISABLED';
const activeConnectionStatus = 'RUNNING';
const skipInstallation = process.env.SKIP_INSTALLATION ? process.env.SKIP_INSTALLATION : false;

test.use({
runnerOptions: new RunnerOptions({ customFolder: 'sandbox-tests-pd', autoUpdate: false, autoCheckUpdates: false }),
});
test.beforeAll(async ({ runner, page, welcomePage }) => {
runner.setVideoAndTraceName('sandbox-e2e');
await welcomePage.handleWelcomePage(true);
extensionCard = new ExtensionCardPage(page, extensionLabelName, extensionLabel);
});

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

test.describe.serial('Red Hat Developer Sandbox extension verification', () => {
test.describe.serial('Red Hat Developer Sandbox extension installation', () => {
// PR check builds extension locally and so it is available already
test('Go to extensions and check if extension is already installed', async ({ navigationBar }) => {
const extensions = await navigationBar.openExtensions();
if (await extensions.extensionIsInstalled(extensionLabel)) {
extensionInstalled = true;
}
});

// we want to skip removing of the extension when we are running tests from PR check
test('Uninstall previous version of sandbox extension', async ({ navigationBar }) => {
test.skip(!extensionInstalled);
test.setTimeout(60000);
await removeExtension(navigationBar);
});

// we want to install extension from OCI image (usually using latest tag) after new code was added to the codebase
// and extension was published already
test('Extension can be installed using OCI image', async ({ navigationBar }) => {
test.skip(extensionInstalled && !skipInstallation);
test.setTimeout(200000);
const extensions = await navigationBar.openExtensions();
await extensions.installExtensionFromOCIImage(imageName);
await playExpect(extensionCard.card).toBeVisible();
});

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

test('Extension\'s 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 Sandbox extension');
const details = new DeveloperSandboxPage(page);
await playExpect(details.heading).toBeVisible();
await playExpect(details.status).toHaveText(activeExtensionStatus);
const errorTab = details.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 details.activateTab('Error');
stackTrace = await details.errorStackTrace.innerText();
}
await playExpect(errorTab, `Error Tab was present with stackTrace: ${stackTrace}`).not.toBeVisible();
});

test('Developer Sandbox is available in Resources Page', async ({ navigationBar }) => {
playExpect(await isSandboxInResources(navigationBar)).toBeTruthy();
});

test('Developer Sandbox is available in Dashboard', async ({ navigationBar }) => {
playExpect(await isSandboxInDashboard(navigationBar)).toBeTruthy();
});
});

test.describe.serial('Developer Sandbox extension handling', () => {
test('Extension can be disabled', async ({ navigationBar }) => {
const extensions = await navigationBar.openExtensions();
playExpect(await extensions.extensionIsInstalled(extensionLabel)).toBeTruthy();
const extensionCard = await extensions.getInstalledExtension(extensionLabelName, extensionLabel);
await playExpect(extensionCard.status).toHaveText(activeExtensionStatus);
await extensionCard.disableExtension();
await playExpect(extensionCard.status).toHaveText(disabledExtensionStatus);

playExpect(await isSandboxInResources(navigationBar)).toBeFalsy();
playExpect(await isSandboxInDashboard(navigationBar)).toBeFalsy();
});

test('Extension can be re-enabled correctly', async ({ navigationBar }) => {
const extensions = await navigationBar.openExtensions();
playExpect(await extensions.extensionIsInstalled(extensionLabel)).toBeTruthy();
const extensionCard = await extensions.getInstalledExtension(extensionLabelName, extensionLabel);
await playExpect(extensionCard.status).toHaveText(disabledExtensionStatus);
await extensionCard.enableExtension();
await playExpect(extensionCard.status).toHaveText(activeExtensionStatus);

playExpect(await isSandboxInResources(navigationBar)).toBeTruthy();
playExpect(await isSandboxInDashboard(navigationBar)).toBeTruthy();
});
});

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

async function removeExtension(navBar: NavigationBar): Promise<void> {
const extensions = await navBar.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 isSandboxInResources(navigationBar: NavigationBar) {
const settingsBar = await navigationBar.openSettings();
const resourcesPage = await settingsBar.openTabPage(ResourcesPage);
const sandboxResourceCard = resourcesPage.featuredProviderResources.getByRole('region', {
name: extensionResourceLabel,
});
const createButton = sandboxResourceCard.getByRole('button', { name: 'Create new Developer Sandbox' });
return (await sandboxResourceCard.isVisible() && await createButton.isVisible());
}

async function isSandboxInDashboard(navigationBar: NavigationBar){
const dashboardPage = await navigationBar.openDashboard();
const sandboxProviderCard = dashboardPage.content.getByRole('region', { name: extensionProvider });
const sandboxStatus = sandboxProviderCard.getByLabel('Connection Status Label');
return (await sandboxProviderCard.isVisible() && (await sandboxStatus.innerText()) === activeConnectionStatus);
}
26 changes: 26 additions & 0 deletions tests/src/model/pages/developer-sandbox-page.ts
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 DeveloperSandboxPage extends ExtensionDetailsPage {
constructor(page: Page) {
super(page, 'Red Hat OpenShift Sandbox extension');
}
}
16 changes: 16 additions & 0 deletions tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"strictNullChecks": true,
"lib": [ "ES2017", "webworker" ],
"module": "esnext",
"target": "esnext",
"sourceMap": true,
"rootDir": "src",
"outDir": "dist",
"skipLibCheck": true,
"types": [ "node" ],
"allowSyntheticDefaultImports": true,
"moduleResolution": "Node",
"esModuleInterop": true
}
}
5 changes: 5 additions & 0 deletions vitest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ const config = {
globals: true,
coverage: {
include: ['**/*.ts'],
exclude: ['tests/**', '**/builtin/**',
'**/node_modules/**',
'**/dist/**',
'**/.{idea,git,cache,output,temp,cdix}/**',
'**/{.electron-builder,babel,changelog,docusaurus,jest,postcss,prettier,rollup,svelte,tailwind,vite,vitest*,webpack}.config.*',],
},
},
resolve: {
Expand Down
Loading

0 comments on commit a9c5baf

Please sign in to comment.