diff --git a/frontend/e2e/pages/web-terminal-config-page.ts b/frontend/e2e/pages/web-terminal-config-page.ts new file mode 100644 index 00000000000..a32b606dc65 --- /dev/null +++ b/frontend/e2e/pages/web-terminal-config-page.ts @@ -0,0 +1,99 @@ +import type { Locator } from '@playwright/test'; + +import BasePage from './base-page'; + +export class WebTerminalConfigPage extends BasePage { + private readonly configSection = this.page.getByTestId('web-terminal form-section'); + private readonly incrementButton = this.page.locator( + '[data-test="Increment"], [data-test-id="Increment"]', + ); + private readonly selectToggle = this.page.getByTestId('console-select-menu-toggle'); + private readonly imageInput = this.page.getByTestId('web-terminal-image'); + private readonly timeoutCheckbox = this.page.getByTestId('timeout-value-checkbox'); + private readonly imageCheckbox = this.page.getByTestId('image-value-checkbox'); + private readonly saveButton = this.page.getByTestId('save-button'); + private readonly successAlert = this.page.getByTestId('success-alert'); + + async navigateToWebTerminalConfig(): Promise { + await this.goTo('/k8s/cluster/operator.openshift.io~v1~Console/cluster'); + await this.waitForLoadingComplete(10_000); + const customizeButton = this.page.locator('button', { hasText: 'Customize' }); + await customizeButton + .first() + .waitFor({ state: 'visible', timeout: 30_000 }) + .catch(() => {}); + if (await customizeButton.first().isVisible()) { + await this.robustClick(customizeButton.first()); + } else { + const actionsMenu = this.page.locator( + '[data-test="actions-menu-button"], [data-test-id="actions-menu-button"]', + ); + await this.robustClick(actionsMenu); + const customizeAction = this.page.locator('[data-test-action="Customize"]:not([disabled])'); + await this.robustClick(customizeAction); + } + await this.waitForLoadingComplete(10_000); + await this.clickWebTerminalTab(); + } + + async clickWebTerminalTab(): Promise { + const tab = this.page + .locator('[role="presentation"]') + .filter({ hasText: 'Web Terminal' }) + .first(); + await this.robustClick(tab); + await this.waitForLoadingComplete(5_000); + } + + async incrementTimeout(): Promise { + await this.robustClick(this.incrementButton); + } + + async selectTimeoutUnit(unit: string): Promise { + await this.robustClick(this.selectToggle); + const option = this.page.getByTestId('console-select-item').filter({ hasText: unit }); + await this.robustClick(option); + } + + async setImageValue(image: string): Promise { + await this.imageInput.fill(image); + } + + async checkPersistCheckboxes(): Promise { + await this.timeoutCheckbox.check(); + await this.imageCheckbox.check(); + } + + async uncheckPersistCheckboxes(): Promise { + await this.timeoutCheckbox.uncheck(); + await this.imageCheckbox.uncheck(); + } + + async clickSaveButton(): Promise { + await this.robustClick(this.saveButton); + } + + getConfigSection(): Locator { + return this.configSection; + } + + getSuccessAlert(): Locator { + return this.successAlert; + } + + getImageInput(): Locator { + return this.imageInput; + } + + getSelectToggle(): Locator { + return this.selectToggle; + } + + getTimeoutCheckbox(): Locator { + return this.timeoutCheckbox; + } + + getImageCheckbox(): Locator { + return this.imageCheckbox; + } +} diff --git a/frontend/e2e/pages/web-terminal-page.ts b/frontend/e2e/pages/web-terminal-page.ts new file mode 100644 index 00000000000..171bde0940e --- /dev/null +++ b/frontend/e2e/pages/web-terminal-page.ts @@ -0,0 +1,200 @@ +import type { Locator } from '@playwright/test'; + +import BasePage from './base-page'; + +export class WebTerminalPage extends BasePage { + private readonly terminalIcon = this.page.locator( + 'button[data-tour-id="tour-cloud-shell-button"]', + ); + private readonly terminalContainer = this.page.locator('.co-cloudshell-terminal__container'); + private readonly terminalWindow = this.page.locator('div.xterm-screen>div.xterm-rows'); + private readonly addTabButton = this.page.locator( + '[data-test="multi-tab-terminal"] [aria-label="Add new tab"]', + ); + private readonly closeTabButtons = this.page.locator('[aria-label="Close terminal tab"]'); + private readonly tabsList = this.page.locator('[data-test="multi-tab-terminal"] ul'); + private readonly drawerCloseButton = this.page.getByTestId('cloudshell-drawer-close-button'); + private readonly loadingBox = this.page.getByTestId('loading-box'); + private readonly timeoutLink = this.page.getByText('Timeout', { exact: true }); + private readonly incrementButton = this.page.locator( + '[data-test="Increment"], [data-test-id="Increment"]', + ); + private readonly timeoutInput = this.page.locator('input[aria-label="Input"]'); + private readonly startButton = this.page.locator('[data-test-id="submit-button"]'); + private readonly resourceTitle = this.page.locator( + '[data-test="resource-title"], [data-test-id="resource-title"]', + ); + private readonly monacoEditor = this.page.locator('div.lines-content.monaco-editor-background'); + private readonly openInNewTabLink = this.page.locator("a[href='/terminal']"); + private readonly closeTerminalButton = this.page.locator( + "button[aria-label='Close terminal'], [aria-label='Close terminal tab']", + ); + private readonly inactivityMessageArea = this.page.locator('div.co-cloudshell-exec__error-msg'); + private readonly perspectiveSwitcherToggle = this.page.locator( + '[data-test-id="perspective-switcher-toggle"]', + ); + + async waitForTerminalIconVisible(maxRetries = 10): Promise { + await this.goTo('/'); + try { + await this.terminalIcon.waitFor({ state: 'visible', timeout: 30_000 }); + return; + } catch { + // Icon not visible on first load — retry with reloads + } + for (let attempt = 0; attempt < maxRetries; attempt++) { + await this.page.reload(); + try { + await this.terminalIcon.waitFor({ state: 'visible', timeout: 15_000 }); + return; + } catch { + // Retry + } + } + throw new Error(`Terminal icon not visible after ${maxRetries} retries`); + } + + async clickTerminalIcon(): Promise { + await this.robustClick(this.terminalIcon); + await this.loadingBox.waitFor({ state: 'detached', timeout: 60_000 }).catch(() => {}); + } + + async waitForTerminalWindow(timeoutMs = 60_000): Promise { + await this.terminalContainer.waitFor({ state: 'visible', timeout: timeoutMs }); + await this.terminalWindow.waitFor({ state: 'visible', timeout: timeoutMs }); + } + + async closeTerminalDrawer(): Promise { + await this.robustClick(this.drawerCloseButton); + await this.terminalContainer.waitFor({ state: 'hidden', timeout: 10_000 }).catch(() => {}); + } + + async closeTerminalSession(): Promise { + await this.robustClick(this.closeTerminalButton.first()); + const confirmButton = this.page.getByRole('button', { name: 'Close' }); + await this.robustClick(confirmButton); + } + + async clickAdvancedTimeout(): Promise { + await this.timeoutLink.waitFor({ state: 'visible', timeout: 30_000 }); + await this.robustClick(this.timeoutLink); + } + + async setTimeoutValue(value: string): Promise { + await this.incrementButton.waitFor({ state: 'visible', timeout: 10_000 }); + await this.robustClick(this.incrementButton); + await this.timeoutInput.fill(value); + await this.timeoutInput.press('Tab'); + } + + async clickStartButton(): Promise { + await this.robustClick(this.startButton); + await this.waitForLoadingComplete(10_000); + } + + async addTerminalTabs(count: number): Promise { + for (let i = 0; i < count; i++) { + await this.robustClick(this.addTabButton); + } + } + + async closeTerminalTab(tabIndex: number): Promise { + await this.robustClick(this.closeTabButtons.nth(tabIndex)); + } + + async getOpenTabCount(): Promise { + const children = this.tabsList.locator('> *'); + return children.count(); + } + + async getResourceTitle(): Promise { + await this.resourceTitle.waitFor({ state: 'visible' }); + return (await this.resourceTitle.textContent()) || ''; + } + + getMonacoEditor(): Locator { + return this.monacoEditor; + } + + getTerminalIcon(): Locator { + return this.terminalIcon; + } + + getTerminalWindow(): Locator { + return this.terminalWindow; + } + + getOpenInNewTabLink(): Locator { + return this.openInNewTabLink; + } + + getInactivityMessageArea(): Locator { + return this.inactivityMessageArea; + } + + async clickProjectDropdown(): Promise { + const dropdown = this.page.locator('[data-test-id="namespace-bar-dropdown"] [type="button"]'); + await this.robustClick(dropdown); + } + + async selectCreateProject(): Promise { + const createBtn = this.page.locator('[data-test-dropdown-menu="#CREATE_RESOURCE_ACTION#"]'); + await this.robustClick(createBtn); + } + + async typeProjectName(name: string): Promise { + await this.page.getByTestId('input-name').fill(name); + } + + async confirmProjectCreation(): Promise { + await this.robustClick(this.page.getByTestId('confirm-action')); + } + + async selectProjectFromDropdown(name: string): Promise { + const filterInput = this.page.getByTestId('dropdown-text-filter'); + await filterInput.fill(name); + const item = this.page.getByTestId('console-select-item').filter({ hasText: name }); + await this.robustClick(item); + } + + async navigateTo(url: string): Promise { + await this.goTo(url); + } + + async waitForPageReady(timeoutMs = 30_000): Promise { + await this.waitForLoadingComplete(timeoutMs); + } + + async navigateToDevWorkspaceSearch(namespace: string): Promise { + await this.goTo(`/search/ns/${namespace}?kind=workspace.devfile.io~v1alpha2~DevWorkspace`); + await this.waitForLoadingComplete(30_000); + } + + async navigateToDevWorkspaceYaml(namespace: string, name: string): Promise { + await this.goTo(`/k8s/ns/${namespace}/workspace.devfile.io~v1alpha2~DevWorkspace/${name}/yaml`); + await this.waitForLoadingComplete(30_000); + } + + async switchPerspective(target: 'Developer' | 'Administrator'): Promise { + const labelMap: Record = { + Administrator: ['Administrator', 'Core platform'], + Developer: ['Developer'], + }; + const labels = labelMap[target] || [target]; + const currentText = (await this.perspectiveSwitcherToggle.textContent()) || ''; + if (labels.some((label) => currentText.includes(label))) { + return; + } + await this.robustClick(this.perspectiveSwitcherToggle); + const menuOption = this.page.locator('[data-test-id="perspective-switcher-menu-option"]'); + for (const label of labels) { + const option = menuOption.filter({ hasText: label }); + if ((await option.count()) > 0) { + await this.robustClick(option.first()); + await this.waitForLoadingComplete(); + return; + } + } + throw new Error(`Perspective "${target}" not found in switcher menu`); + } +} diff --git a/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts b/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts new file mode 100644 index 00000000000..f21e4b7e7dc --- /dev/null +++ b/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts @@ -0,0 +1,78 @@ +import { test, expect } from '../../../fixtures'; +import { WebTerminalPage } from '../../../pages/web-terminal-page'; +import { ensureWebTerminalOperatorInstalled } from '../../../utils/web-terminal-operator'; + +const INACTIVITY_MESSAGE = 'The terminal connection has closed due to inactivity.'; +const TERMINAL_IDLING_TIMEOUT = Number(process.env.TERMINAL_IDLING_TIMEOUT) || 200_000; +const TEST_NAMESPACE = 'aut-terminal-basic'; + +test.describe('Web Terminal basic user', { tag: ['@web-terminal', '@regression'] }, () => { + test.beforeAll(async ({ k8sClient }) => { + await ensureWebTerminalOperatorInstalled(k8sClient); + }); + + test.beforeEach(async ({ k8sClient, cleanup }) => { + await k8sClient.createNamespace(TEST_NAMESPACE); + cleanup.trackNamespace(TEST_NAMESPACE); + }); + + test('WT-01-TC01: open terminal with advanced timeout', async ({ page }) => { + const webTerminal = new WebTerminalPage(page); + + await test.step('Open terminal with 1-minute timeout', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + await webTerminal.clickAdvancedTimeout(); + await webTerminal.setTimeoutValue('1'); + await webTerminal.clickStartButton(); + }); + + await test.step('Verify terminal window is visible', async () => { + await webTerminal.waitForTerminalWindow(); + await expect(webTerminal.getTerminalWindow()).toBeVisible(); + }); + + await test.step('Close terminal session', async () => { + await webTerminal.closeTerminalSession(); + }); + }); + + test('WT-01-TC02: verify Open in new tab button', async ({ page }) => { + const webTerminal = new WebTerminalPage(page); + + await test.step('Wait for terminal icon and open terminal', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + }); + + await test.step('Verify Open in new tab link has target _blank', async () => { + const newTabLink = webTerminal.getOpenInNewTabLink(); + await expect(newTabLink).toBeVisible(); + await expect(newTabLink).toHaveAttribute('target', '_blank'); + }); + }); + + test('WT-01-TC03: inactivity timeout closes terminal', async ({ page }) => { + test.slow(); + const webTerminal = new WebTerminalPage(page); + + await test.step('Open terminal and wait for terminal window', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + await webTerminal.clickStartButton(); + await webTerminal.waitForTerminalWindow(); + await expect(webTerminal.getTerminalWindow()).toBeVisible(); + }); + + await test.step('Wait for inactivity message', async () => { + await expect(webTerminal.getInactivityMessageArea()).toContainText(INACTIVITY_MESSAGE, { + timeout: TERMINAL_IDLING_TIMEOUT, + }); + }); + + await test.step('Verify restart button is shown', async () => { + const restartButton = page.locator('button', { hasText: 'Restart terminal' }); + await expect(restartButton).toBeVisible(); + }); + }); +}); diff --git a/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts b/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts new file mode 100644 index 00000000000..0cb91023c53 --- /dev/null +++ b/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts @@ -0,0 +1,109 @@ +import { test, expect } from '../../../fixtures'; +import { WebTerminalPage } from '../../../pages/web-terminal-page'; +import { ensureWebTerminalOperatorInstalled } from '../../../utils/web-terminal-operator'; + +const DEVWORKSPACE_GROUP = 'workspace.devfile.io'; +const DEVWORKSPACE_VERSION = 'v1alpha2'; +const DEVWORKSPACE_PLURAL = 'devworkspaces'; +const EXISTING_PROJECT = 'aut-terminal-testuser-existed'; +const NEW_PROJECT = 'aut-terminal-testuser'; + +test.describe('Web Terminal for Developer user', { tag: ['@web-terminal', '@regression'] }, () => { + test.beforeAll(async ({ k8sClient }) => { + await ensureWebTerminalOperatorInstalled(k8sClient); + }); + + test.beforeEach(async ({ k8sClient, cleanup }) => { + await k8sClient.createNamespace(EXISTING_PROJECT); + cleanup.trackNamespace(EXISTING_PROJECT); + }); + + test( + 'WT-03-TC01: create new project and use Web Terminal', + { tag: ['@ODC-6745'] }, + async ({ page, k8sClient, cleanup }) => { + const webTerminal = new WebTerminalPage(page); + cleanup.trackNamespace(NEW_PROJECT); + + await test.step('Wait for terminal icon', async () => { + await webTerminal.waitForTerminalIconVisible(); + }); + + await test.step('Create new project from terminal init screen', async () => { + await webTerminal.clickTerminalIcon(); + await webTerminal.clickProjectDropdown(); + await webTerminal.selectCreateProject(); + await webTerminal.typeProjectName(NEW_PROJECT); + await webTerminal.confirmProjectCreation(); + }); + + await test.step('Set timeout and start terminal', async () => { + await webTerminal.clickAdvancedTimeout(); + await webTerminal.setTimeoutValue('1'); + await webTerminal.clickStartButton(); + }); + + await test.step('Verify terminal window is visible', async () => { + await webTerminal.waitForTerminalWindow(); + await expect(webTerminal.getTerminalWindow()).toBeVisible(); + }); + + await test.step('Verify DevWorkspace exists in developer namespace', async () => { + await webTerminal.switchPerspective('Administrator'); + await webTerminal.navigateToDevWorkspaceSearch(NEW_PROJECT); + const terminalLink = page + .locator('[data-test-rows="resource-row"]') + .filter({ hasText: 'terminal' }); + await expect(terminalLink.first()).toBeVisible({ timeout: 60_000 }); + await terminalLink.first().locator('a').first().click(); + await webTerminal.waitForPageReady(); + + const devWorkspaces = await k8sClient.listCustomResources( + DEVWORKSPACE_GROUP, + DEVWORKSPACE_VERSION, + NEW_PROJECT, + DEVWORKSPACE_PLURAL, + ); + expect(devWorkspaces.length).toBeGreaterThan(0); + const phase = (devWorkspaces[0] as any).status?.phase; + expect(phase).toBe('Running'); + }); + }, + ); + + test('WT-03-TC02: open Web Terminal for existing project', async ({ page, k8sClient }) => { + const webTerminal = new WebTerminalPage(page); + + await test.step('Wait for terminal icon and open terminal', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + }); + + await test.step('Select existing project and start terminal', async () => { + await webTerminal.clickProjectDropdown(); + await webTerminal.selectProjectFromDropdown(EXISTING_PROJECT); + await webTerminal.clickStartButton(); + }); + + await test.step('Verify DevWorkspace exists in existing namespace', async () => { + await webTerminal.switchPerspective('Administrator'); + await webTerminal.navigateToDevWorkspaceSearch(EXISTING_PROJECT); + const terminalLink = page + .locator('[data-test-rows="resource-row"]') + .filter({ hasText: 'terminal' }); + await expect(terminalLink.first()).toBeVisible({ timeout: 60_000 }); + await terminalLink.first().locator('a').first().click(); + await webTerminal.waitForPageReady(); + + const devWorkspaces = await k8sClient.listCustomResources( + DEVWORKSPACE_GROUP, + DEVWORKSPACE_VERSION, + EXISTING_PROJECT, + DEVWORKSPACE_PLURAL, + ); + expect(devWorkspaces.length).toBeGreaterThan(0); + const phase = (devWorkspaces[0] as any).status?.phase; + expect(phase).toBe('Running'); + }); + }); +}); diff --git a/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts b/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts new file mode 100644 index 00000000000..ab46359ed4e --- /dev/null +++ b/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts @@ -0,0 +1,154 @@ +import { test, expect } from '../../fixtures'; +import { WebTerminalPage } from '../../pages/web-terminal-page'; +import { ensureWebTerminalOperatorInstalled } from '../../utils/web-terminal-operator'; + +const DEVWORKSPACE_GROUP = 'workspace.devfile.io'; +const DEVWORKSPACE_VERSION = 'v1alpha2'; +const DEVWORKSPACE_PLURAL = 'devworkspaces'; +const TERMINAL_NAMESPACE = 'openshift-terminal'; + +test.describe('Web Terminal for Admin user', { tag: ['@admin', '@web-terminal'] }, () => { + test.beforeAll(async ({ k8sClient }) => { + await ensureWebTerminalOperatorInstalled(k8sClient); + }); + + test.beforeEach(async ({ k8sClient }) => { + const devWorkspaces = await k8sClient.listCustomResources( + DEVWORKSPACE_GROUP, + DEVWORKSPACE_VERSION, + TERMINAL_NAMESPACE, + DEVWORKSPACE_PLURAL, + ); + for (const dw of devWorkspaces) { + const name = (dw as any).metadata?.name; + if (name) { + await k8sClient.deleteCustomResource( + DEVWORKSPACE_GROUP, + DEVWORKSPACE_VERSION, + TERMINAL_NAMESPACE, + DEVWORKSPACE_PLURAL, + name, + ); + } + } + }); + + test( + 'WT-02-TC01: open and close multiple terminal tabs', + { tag: ['@regression'] }, + async ({ page }) => { + const webTerminal = new WebTerminalPage(page); + + await test.step('Wait for terminal icon and start terminal', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + await webTerminal.clickStartButton(); + await webTerminal.waitForTerminalWindow(); + }); + + await test.step('Open 3 additional tabs', async () => { + await webTerminal.addTerminalTabs(3); + }); + + await test.step('Close the 2nd tab', async () => { + await webTerminal.closeTerminalTab(1); + }); + + await test.step('Verify 3 tabs remain', async () => { + const tabCount = await webTerminal.getOpenTabCount(); + expect(tabCount).toEqual(3); + }); + + await test.step('Close terminal drawer', async () => { + await webTerminal.closeTerminalDrawer(); + }); + }, + ); + + test( + 'WT-02-TC02: start terminal with timeout and verify DevWorkspace', + { tag: ['@smoke'] }, + async ({ page, k8sClient }) => { + const webTerminal = new WebTerminalPage(page); + + await test.step('Open terminal with 10-minute timeout', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + await webTerminal.clickAdvancedTimeout(); + await webTerminal.setTimeoutValue('10'); + await webTerminal.clickStartButton(); + }); + + await test.step('Verify DevWorkspace exists in openshift-terminal', async () => { + await webTerminal.switchPerspective('Administrator'); + await webTerminal.navigateToDevWorkspaceSearch(TERMINAL_NAMESPACE); + const terminalRow = page.locator('tr').filter({ hasText: /terminal/i }); + await expect(terminalRow.first()).toBeVisible({ timeout: 60_000 }); + await terminalRow.first().locator('a').first().click(); + await webTerminal.waitForPageReady(); + }); + + await test.step('Verify DevWorkspace UID matches YAML editor', async () => { + const devWsName = await webTerminal.getResourceTitle(); + + const devWorkspaces = await k8sClient.listCustomResources( + DEVWORKSPACE_GROUP, + DEVWORKSPACE_VERSION, + TERMINAL_NAMESPACE, + DEVWORKSPACE_PLURAL, + ); + expect(devWorkspaces.length).toBeGreaterThan(0); + const uid = (devWorkspaces[0] as any).metadata?.uid; + expect(uid).toBeTruthy(); + + await webTerminal.navigateToDevWorkspaceYaml(TERMINAL_NAMESPACE, devWsName); + await expect(webTerminal.getMonacoEditor()).toContainText(uid, { timeout: 30_000 }); + }); + }, + ); + + test( + 'WT-02-TC03: start terminal with defaults and verify DevWorkspace', + { tag: ['@smoke'] }, + async ({ page, k8sClient }) => { + const webTerminal = new WebTerminalPage(page); + + await test.step('Open terminal with default settings', async () => { + await webTerminal.waitForTerminalIconVisible(); + await webTerminal.clickTerminalIcon(); + await webTerminal.clickStartButton(); + }); + + await test.step('Verify terminal window is visible', async () => { + await webTerminal.waitForTerminalWindow(); + await expect(webTerminal.getTerminalWindow()).toBeVisible(); + }); + + await test.step('Verify DevWorkspace exists in openshift-terminal', async () => { + await webTerminal.switchPerspective('Administrator'); + await webTerminal.navigateToDevWorkspaceSearch(TERMINAL_NAMESPACE); + const terminalRow = page.locator('tr').filter({ hasText: /terminal/i }); + await expect(terminalRow.first()).toBeVisible({ timeout: 60_000 }); + await terminalRow.first().locator('a').first().click(); + await webTerminal.waitForPageReady(); + }); + + await test.step('Verify DevWorkspace UID matches YAML editor', async () => { + const devWsName = await webTerminal.getResourceTitle(); + + const devWorkspaces = await k8sClient.listCustomResources( + DEVWORKSPACE_GROUP, + DEVWORKSPACE_VERSION, + TERMINAL_NAMESPACE, + DEVWORKSPACE_PLURAL, + ); + expect(devWorkspaces.length).toBeGreaterThan(0); + const uid = (devWorkspaces[0] as any).metadata?.uid; + expect(uid).toBeTruthy(); + + await webTerminal.navigateToDevWorkspaceYaml(TERMINAL_NAMESPACE, devWsName); + await expect(webTerminal.getMonacoEditor()).toContainText(uid, { timeout: 30_000 }); + }); + }, + ); +}); diff --git a/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts b/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts new file mode 100644 index 00000000000..267ed10a0a9 --- /dev/null +++ b/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts @@ -0,0 +1,161 @@ +import { test, expect } from '../../fixtures'; +import { WebTerminalConfigPage } from '../../pages/web-terminal-config-page'; +import { ensureWebTerminalOperatorInstalled } from '../../utils/web-terminal-operator'; + +const TEST_IMAGE_805 = + 'registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446805'; +const TEST_IMAGE_806 = + 'registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446806'; + +test.describe( + 'Customization of web terminal options', + { tag: ['@admin', '@customize-web-terminal'] }, + () => { + test.beforeAll(async ({ k8sClient }) => { + await ensureWebTerminalOperatorInstalled(k8sClient); + }); + + test( + 'WT-02-TC01: navigate to Web Terminal Configuration page', + { tag: ['@smoke'] }, + async ({ page }) => { + const configPage = new WebTerminalConfigPage(page); + + await test.step('Navigate to Consoles and open Customize', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Verify configuration page is visible', async () => { + await expect(configPage.getConfigSection()).toBeVisible(); + }); + }, + ); + + test( + 'WT-02-TC02: change timeout and image with persist checkboxes', + { tag: ['@smoke'] }, + async ({ page }) => { + const configPage = new WebTerminalConfigPage(page); + + await test.step('Navigate to Web Terminal Configuration', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Set timeout to Minutes and enter image', async () => { + await configPage.incrementTimeout(); + await configPage.selectTimeoutUnit('Minutes'); + await configPage.setImageValue(TEST_IMAGE_805); + }); + + await test.step('Check persist checkboxes and save', async () => { + await configPage.checkPersistCheckboxes(); + await configPage.clickSaveButton(); + }); + + await test.step('Verify success alert', async () => { + await expect(configPage.getSuccessAlert()).toBeVisible(); + }); + }, + ); + + test( + 'WT-02-TC03: change timeout to Hours and verify values persist after tab switch', + { tag: ['@smoke'] }, + async ({ page }) => { + const configPage = new WebTerminalConfigPage(page); + + await test.step('Navigate to Web Terminal Configuration', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Set timeout to Hours, enter image, check persist, and save', async () => { + await configPage.incrementTimeout(); + await configPage.selectTimeoutUnit('Hours'); + await configPage.setImageValue(TEST_IMAGE_806); + await configPage.checkPersistCheckboxes(); + await configPage.clickSaveButton(); + }); + + await test.step('Re-navigate to Web Terminal Configuration to verify persistence', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Verify saved values persist', async () => { + await expect(configPage.getImageInput()).toHaveValue(TEST_IMAGE_806); + await expect(configPage.getSelectToggle()).toContainText('Hours'); + await expect(configPage.getTimeoutCheckbox()).toBeChecked(); + await expect(configPage.getImageCheckbox()).toBeChecked(); + }); + }, + ); + + test( + 'WT-02-TC04: save without persist checkboxes', + { tag: ['@regression'] }, + async ({ page }) => { + const configPage = new WebTerminalConfigPage(page); + + await test.step('Navigate to Web Terminal Configuration', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Set timeout, image, uncheck persist, and save', async () => { + await configPage.incrementTimeout(); + await configPage.selectTimeoutUnit('Hours'); + await configPage.setImageValue(TEST_IMAGE_806); + await configPage.uncheckPersistCheckboxes(); + await configPage.clickSaveButton(); + }); + + await test.step('Verify success alert', async () => { + await expect(configPage.getSuccessAlert()).toBeVisible(); + }); + }, + ); + + test( + 'WT-02-TC05: verify unchecked checkboxes persist after tab switch', + { tag: ['@regression'] }, + async ({ page }) => { + const configPage = new WebTerminalConfigPage(page); + + await test.step('Navigate to Web Terminal Configuration', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Set values, uncheck persist, and save', async () => { + await configPage.incrementTimeout(); + await configPage.selectTimeoutUnit('Hours'); + await configPage.setImageValue(TEST_IMAGE_806); + await configPage.uncheckPersistCheckboxes(); + await configPage.clickSaveButton(); + }); + + await test.step('Re-navigate to Web Terminal Configuration to verify persistence', async () => { + await configPage.navigateToWebTerminalConfig(); + }); + + await test.step('Verify checkboxes are unchecked', async () => { + await expect(configPage.getTimeoutCheckbox()).not.toBeChecked(); + await expect(configPage.getImageCheckbox()).not.toBeChecked(); + }); + }, + ); + + // eslint-disable-next-line playwright/expect-expect + test('WT-02-TC06: verify timeout in DevWorkspaceTemplate YAML (manual)', { + tag: ['@regression'], + annotation: { type: 'skip', description: 'Manual verification required' }, + }, async () => { + test.skip(true, 'Manual verification required'); + }); + + // eslint-disable-next-line playwright/expect-expect + test('WT-02-TC07: verify image in DevWorkspaceTemplate YAML (manual)', { + tag: ['@regression'], + annotation: { type: 'skip', description: 'Manual verification required' }, + }, async () => { + test.skip(true, 'Manual verification required'); + }); + }, +); diff --git a/frontend/e2e/utils/web-terminal-operator.ts b/frontend/e2e/utils/web-terminal-operator.ts new file mode 100644 index 00000000000..e8526b18ecb --- /dev/null +++ b/frontend/e2e/utils/web-terminal-operator.ts @@ -0,0 +1,67 @@ +import KubernetesClient from '../clients/kubernetes-client'; + +const SUBSCRIPTION_GROUP = 'operators.coreos.com'; +const SUBSCRIPTION_VERSION = 'v1alpha1'; +const SUBSCRIPTION_PLURAL = 'subscriptions'; +const OPERATOR_NAMESPACE = 'openshift-operators'; + +const webTerminalSubscription = { + apiVersion: 'operators.coreos.com/v1alpha1', + kind: 'Subscription', + metadata: { + name: 'web-terminal', + namespace: OPERATOR_NAMESPACE, + }, + spec: { + channel: 'fast', + installPlanApproval: 'Automatic', + name: 'web-terminal', + source: 'redhat-operators', + sourceNamespace: 'openshift-marketplace', + }, +}; + +export async function ensureWebTerminalOperatorInstalled( + k8sClient: KubernetesClient, +): Promise { + try { + await k8sClient.getCustomResource( + SUBSCRIPTION_GROUP, + SUBSCRIPTION_VERSION, + OPERATOR_NAMESPACE, + SUBSCRIPTION_PLURAL, + 'web-terminal', + ); + return; + } catch { + // Subscription doesn't exist — create it + } + + await k8sClient.createCustomResource( + SUBSCRIPTION_GROUP, + SUBSCRIPTION_VERSION, + OPERATOR_NAMESPACE, + SUBSCRIPTION_PLURAL, + webTerminalSubscription, + ); + + const maxWaitMs = 300_000; + const pollIntervalMs = 10_000; + const deadline = Date.now() + maxWaitMs; + + while (Date.now() < deadline) { + const pods = await k8sClient.getPods(OPERATOR_NAMESPACE); + const controllerPod = pods.find( + (pod) => + pod.metadata?.name?.includes('web-terminal-controller') && + pod.status?.phase === 'Running' && + pod.status?.conditions?.some((c) => c.type === 'Ready' && c.status === 'True'), + ); + if (controllerPod) { + return; + } + await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); + } + + throw new Error('Web Terminal operator controller pod not ready within 5 minutes'); +} diff --git a/frontend/packages/dev-console/integration-tests/support/constants/webTerminal.ts b/frontend/packages/dev-console/integration-tests/support/constants/webTerminal.ts deleted file mode 100644 index 98c53673d91..00000000000 --- a/frontend/packages/dev-console/integration-tests/support/constants/webTerminal.ts +++ /dev/null @@ -1,5 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ - -export enum messages { - inactivityMessage = 'The terminal connection has closed due to inactivity.', -} diff --git a/frontend/packages/dev-console/integration-tests/support/pageObjects/webterminal-po.ts b/frontend/packages/dev-console/integration-tests/support/pageObjects/webterminal-po.ts deleted file mode 100644 index 437ec4ff0cd..00000000000 --- a/frontend/packages/dev-console/integration-tests/support/pageObjects/webterminal-po.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const webTerminalPO = { - webTerminalIcon: '[data-tour-id="tour-cloud-shell-button"]', - addTerminalIcon: '[data-test="multi-tab-terminal"] [aria-label="Add new tab"]', - closeTerminalIcon: '[aria-label="Close terminal tab"]', - tabsList: '[data-test="multi-tab-terminal"] ul', - openCommandLine: 'button[data-tour-id="tour-cloud-shell-button"]', - terminalWindow: 'div.xterm-screen>div.xterm-rows', - terminalOpenInNewTabBtn: "a[href='/terminal']", - terminalCloseWindowBtn: "button[aria-label='Close terminal'], [aria-label='Close terminal tab']", - terminalInnactivityMessageArea: 'div.co-cloudshell-exec__error-msg', - createProjectMenu: { - createProjectDropdownMenu: '[data-test-id="namespace-bar-dropdown"] [type="button"]', - createProjectButton: '[data-test-dropdown-menu="#CREATE_RESOURCE_ACTION#"]', - selectProjectField: 'input#form-input-newNamespace-field', - inputField: 'dropdown-text-filter', - }, - - projectNameMenu: { - projectNameField: '[data-test="input-name"]', - }, - closeTerminalDialog: {}, -}; diff --git a/frontend/packages/dev-console/integration-tests/support/pages/functions/addTerminalTabs.ts b/frontend/packages/dev-console/integration-tests/support/pages/functions/addTerminalTabs.ts deleted file mode 100644 index d462aa6e530..00000000000 --- a/frontend/packages/dev-console/integration-tests/support/pages/functions/addTerminalTabs.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { webTerminalPO } from '../../pageObjects/webterminal-po'; - -export const addTerminals = (n: number) => { - for (let i = 0; i < n; i++) { - cy.get(webTerminalPO.addTerminalIcon).click(); - } -}; - -export const closeTerminal = (x: string) => { - const n = x.substring(0, 1); - cy.get(webTerminalPO.closeTerminalIcon) - .eq(Number(n) - 1) - .click(); -}; diff --git a/frontend/packages/dev-console/integration-tests/support/pages/functions/checkTerminalIcon.ts b/frontend/packages/dev-console/integration-tests/support/pages/functions/checkTerminalIcon.ts deleted file mode 100644 index 04558dc7282..00000000000 --- a/frontend/packages/dev-console/integration-tests/support/pages/functions/checkTerminalIcon.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { webTerminalPO } from '../../pageObjects/webterminal-po'; - -export const checkTerminalIcon = (tries: number = 10) => { - if (tries < 1) { - return; - } - cy.get('body').then(($body) => { - if ($body.find(webTerminalPO.webTerminalIcon).length === 0) { - cy.reload(); - cy.wait(10000); // wait is for body to render after reload - checkTerminalIcon(tries - 1); - } else { - cy.log('Found'); - } - }); -}; diff --git a/frontend/packages/webterminal-plugin/integration-tests/.eslintrc b/frontend/packages/webterminal-plugin/integration-tests/.eslintrc deleted file mode 100644 index 5768e567162..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/.eslintrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "env": { - "cypress/globals": true, - "node": true - }, - "extends": ["../../.eslintrc", "plugin:cypress/recommended", "plugin:prettier/recommended"], - "plugins": ["cypress"], - "rules": { - "no-console": "off", - "no-namespace": "off", - "no-redeclare": "off", - "promise/catch-or-return": "off", - "promise/no-nesting": "off", - "cypress/no-unnecessary-waiting": "off", - "cypress/unsafe-to-chain-command": "off" - } -} diff --git a/frontend/packages/webterminal-plugin/integration-tests/cypress.config.js b/frontend/packages/webterminal-plugin/integration-tests/cypress.config.js deleted file mode 100644 index b9cad8b4192..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/cypress.config.js +++ /dev/null @@ -1,14 +0,0 @@ -const { defineConfig } = require('@console/cypress-integration-tests/cypress-common-config'); - -module.exports = defineConfig({ - fixturesFolder: 'testData', - env: { - TAGS: - '(@web-terminal or @customize-web-terminal) and (@smoke or @regression or @pre-condition) and not (@manual or @to-do or @un-verified or @broken-test)', - NAMESPACE: 'aut-webterminal', - }, - e2e: { - specPattern: 'features/**/*.{feature,features}', - supportFile: 'support/commands/index.ts', - }, -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/features/customization/customization-of-web-terminal.feature b/frontend/packages/webterminal-plugin/integration-tests/features/customization/customization-of-web-terminal.feature deleted file mode 100644 index 0e147ae7872..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/features/customization/customization-of-web-terminal.feature +++ /dev/null @@ -1,85 +0,0 @@ -@customize-web-terminal @ODC-7283 -Feature: Customization of web terminal options - As admin you can change the default timeout and image of Web Terminal. - - Background: - Given user has installed Web Terminal operator - And user is at developer perspective - And user has created or selected namespace "aut-web-terminal" - - @smoke - Scenario: When navigates to cluster configuration page: WT-02-TC01 - Given user is at Consoles page - When user navigates to Cluster configuration page - And user clicks on Web Terminal tab - Then user should see Web Terminal Configuration page - - - @smoke - Scenario: When user changes web terminal settings: WT-02-TC02 - Given user is at Web Terminal Configuration page - When user increase the timeout value and set unit as "Minutes" - And user enters image value as "registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446805" - And user checks checkboxes to save data even after operator restarts or update - And user clicks on Save button to save web terminal settings - Then user should see a success alert - - - @smoke - Scenario: When user changes web terminal default image and timeout: WT-02-TC03 - Given user is at Web Terminal Configuration page - When user increase the timeout value and set unit as "Hours" - And user enters image value as "registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446806" - And user checks checkboxes to save data even after operator restarts or update - And user clicks on Save button to save web terminal settings - And user switches to Developer tab - And user clicks on Web Terminal tab - Then user should see new image value as "registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446806" - And user should see new timeout unit as "Hours" - And user should see timeout checkbox to save data even after operator restarts or update is checked - And user should see image checkbox to save data even after operator restarts or update is checked - - @regression - Scenario: When user selects not to save data after operator restarts or update: WT-02-TC04 - Given user is at Web Terminal Configuration page - When user increase the timeout value and set unit as "Hours" - And user enters image value as "registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446806" - And user unchecks checkboxes to save data even after operator restarts or update - And user clicks on Save button to save web terminal settings - Then user should see a success alert - - @regression - Scenario: When user selects not to save data after operator restarts or update: WT-02-TC05 - Given user is at Web Terminal Configuration page - When user increase the timeout value and set unit as "Hours" - And user enters image value as "registry.redhat.io/web-terminal/web-terminal-tooling-rhel8@sha256:9ff1f660fccd3a2f0515ba997d48ad87d2ba47c40b67062c74580bbea9446806" - And user unchecks checkboxes to save data even after operator restarts or update - And user clicks on Save button to save web terminal settings - And user switches to Developer tab - And user clicks on Web Terminal tab - Then user should see timeout checkbox to save data even after operator restarts or update is unchecked - And user should see image checkbox to save data even after operator restarts or update is unchecked - - - @regression @manual - Scenario: When web terminal timeout value is changed: WT-02-TC06 - Given user has updated timeout value in Web Terminal Congiguration page - And user decided to save timeout value even after operator restarts or update - And user is at namespace "openshift-operators" - When user searches "DevWorkspaceTemplates" in Search page - And user selects "web-terminal-exec" resource - And user switches to the YAML tab - Then user should see new timeout value in "WEB_TERMINAL_IDLE_TIMEOUT" evnironment variable - And user should see "web-terminal.redhat.com/unmanaged-state: 'true'" got added in "metadata.annotations" - - - @regression @manual - Scenario: When web terminal image value is changed: WT-02-TC07 - Given user has updated image value in Web Terminal Congiguration page - And user decided to save image value even after operator restarts or update - And user is at namespace "openshift-operators" - When user searches "DevWorkspaceTemplates" in Search page - And user selects "web-terminal-tooling" resource - And user switches to the YAML tab - Then user should see new image value in 'spec.components' for resource name "web-terminal-tooling" in "container.image" value - And user should see "web-terminal.redhat.com/unmanaged-state: 'true'" got added in "metadata.annotations" diff --git a/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-teminal-basic.feature b/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-teminal-basic.feature deleted file mode 100644 index 81cccf419db..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-teminal-basic.feature +++ /dev/null @@ -1,32 +0,0 @@ -@web-terminal -Feature: Web Terminal - As a basic user, I should be able to use web terminal - - Background: - Given user has logged in as basic user - # And user has installed webTerminal in namespace "aut-terminal-basic" - And user has created or selected namespace "aut-terminal-basic" - - @regression - Scenario: Open existing Web Terminal instance: WT-01-TC01 - When user clicks on the Web Terminal icon on the Masthead - And user clicks advanced option for Timeout - And user sets timeout to "1" Minute - And user clicks on Start button - Then user will see the terminal window - And user close current Web Terminal session - - @regression - Scenario: Web Terminal in new tab: WT-01-TC02 - Given user can see terminal icon on masthead - When user clicks on the Web Terminal icon on the Masthead - And user clicks on Open Terminal in new tab button on the terminal window - Then user will see the terminal window opened in new tab - - @regression - Scenario: Web Terminal is stopped by inactivity: WT-01-TC03 - Given user can see terminal icon on masthead - When user clicks on the Web Terminal icon on the Masthead - Then user will see the terminal window - And user does nothing with displayed terminal window 1 minutes - Then user will be informed that terminal is closed by inactivity and is proposed to restart it diff --git a/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-terminal-adminuser.feature b/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-terminal-adminuser.feature deleted file mode 100644 index 9dc6dd05327..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-terminal-adminuser.feature +++ /dev/null @@ -1,43 +0,0 @@ -@web-terminal -Feature: Web Terminal for Admin user - As a user with admin rights, I should be able to use web terminal - - - Background: - Given user has logged in - And user has closed existing terminal workspace - - - @regression @ODC-6463 - Scenario Outline: User is able to open and close multiple terminals in the cloudshell: WT-02-TC01 - Given user can see terminal icon on masthead - When user clicks on the Web Terminal icon on the Masthead - And user opens additional web terminal tabs - And user closed "" web terminal tab - Then user is able see web terminal tabs - And user closed web terminal window - - Examples: - | number_of_terminals | closed_terminal | open_terminals | - | 3 | 2nd | 3 | - - - @smoke @ODC-6745 - Scenario: Create new project with timeout and use Web Terminal: WT-02-TC02 - Given user can see terminal icon on masthead - When user clicks on the Web Terminal icon on the Masthead - And user clicks advanced option for Timeout - And user sets timeout to "10" Minute - And user clicks on Start button - Then user will see the terminal instance for namespace "openshift-terminal" - And user ID obtained by API should match with user id in yaml editor for "openshift-terminal" namespace - - - @smoke @ODC-6745 - Scenario: Create new project and use Web Terminal: WT-02-TC03 - Given user can see terminal icon on masthead - When user clicks on the Web Terminal icon on the Masthead - And user clicks on Start button - Then user will see the terminal window - And user will see the terminal instance for namespace "openshift-terminal" - And user ID obtained by API should match with user id in yaml editor for "openshift-terminal" namespace diff --git a/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-terminal-devuser.feature b/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-terminal-devuser.feature deleted file mode 100644 index 07fd0443875..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/features/web-terminal/web-terminal-devuser.feature +++ /dev/null @@ -1,34 +0,0 @@ -@web-terminal -Feature: Web Terminal for Developer user - As a developer user, I should be able to use web terminal - - Background: - - Given user with basic rights has installed Web Terminal operator - And user has logged in as basic user - # for correct checking of the user story we can use just an one project with active terminal - # we use 2 different namespace (projects) for avoiding conflicts - # 1. `aut-terminal-testuser` for creation, starting and removing DevWorkspace - # 2. `aut-terminal-testuser-existed` for creation DevWorkspace in existed project - # in existed project - And user has created or selected namespace "aut-terminal-testuser-existed" - - @regression @ODC-6745 - Scenario: Create new project and use Web Terminal: WT-03-TC01 - Given user can see terminal icon on masthead - When user selects Create Project from Project drop down menu - And user enters project name "aut-terminal-testuser" - And user clicks on the Web Terminal icon on the Masthead - And user clicks advanced option for Timeout - And user sets timeout to 1 Minute - And user clicks on Start button - Then user will see the terminal window - Then user will see the terminal instance for developer namespace "aut-terminal-testuser" - - @regression - Scenario: Open Web Terminal for existing project WT-03-TC02 - Given user can see terminal icon on masthead - When user clicks on the Web Terminal icon on the Masthead - And user clicks on Start button - And user selects "aut-terminal-testuser-existed" from Project drop down menu - Then user will see the terminal instance for developer namespace "aut-terminal-testuser-existed" diff --git a/frontend/packages/webterminal-plugin/integration-tests/package.json b/frontend/packages/webterminal-plugin/integration-tests/package.json deleted file mode 100644 index d0ca410c410..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "@webterminal-plugin/integration-tests", - "version": "0.0.1", - "description": "WebTerminal Cypress tests", - "private": true, - "cypress-cucumber-preprocessor": { - "step_definitions": "support/step-definitions/*/" - }, - "scripts": { - "test-cypress": "../../../node_modules/.bin/cypress open --env openshift=true", - "test-cypress-headless": "node --max-old-space-size=4096 ../../../node_modules/.bin/cypress run ${CYPRESS_RECORD_KEY:+--record} --env openshift=true --browser ${BRIDGE_E2E_BROWSER_NAME:-electron} --headless --spec \"features/web-terminal/web-terminal-adminuser.feature\"", - "test-cypress-headless-all": "node --max-old-space-size=4096 ../../../node_modules/.bin/cypress run --env openshift=true --browser ${BRIDGE_E2E_BROWSER_NAME:-electron} --headless --spec \"features/*/*.feature\";" - } -} diff --git a/frontend/packages/webterminal-plugin/integration-tests/reporter-config.json b/frontend/packages/webterminal-plugin/integration-tests/reporter-config.json deleted file mode 100644 index ad8daad62e4..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/reporter-config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "reporterEnabled": "mocha-junit-reporter, mochawesome", - "mochaJunitReporterReporterOptions": { - "mochaFile": "../../../gui_test_screenshots/junit_cypress-[hash].xml", - "toConsole": false - }, - "mochawesomeReporterOptions": { - "reportDir": "../../../gui_test_screenshots/", - "reportFilename": "cypress_report_webterminal", - "overwrite": false, - "html": false, - "json": true - } -} diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/commands/hooks.ts b/frontend/packages/webterminal-plugin/integration-tests/support/commands/hooks.ts deleted file mode 100644 index 9ecbf34005c..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/commands/hooks.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { checkErrors } from '@console/cypress-integration-tests/support'; -import { installWebterminalOperatorUsingCLI } from '@console/dev-console/integration-tests/support/pages'; - -before(() => { - cy.login(); - cy.document().its('readyState').should('eq', 'complete'); - installWebterminalOperatorUsingCLI(); -}); - -after(() => { - const namespaces: string[] = Cypress.expose('NAMESPACES') || []; - cy.log(`Deleting "${namespaces.join(' ')}" namespace`); - cy.exec(`oc delete namespace ${namespaces.join(' ')}`, { - failOnNonZeroExit: false, - timeout: 180000, - }); -}); - -beforeEach(() => { - cy.initAdmin(); - cy.byLegacyTestID('topology-header').should('exist').click({ force: true }); -}); - -afterEach(() => { - checkErrors(); -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/commands/index.ts b/frontend/packages/webterminal-plugin/integration-tests/support/commands/index.ts deleted file mode 100644 index 58f43820ae0..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/commands/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Include the cypress customized commands related files -import '@console/cypress-integration-tests/support/selectors'; -import '@console/cypress-integration-tests/support/a11y'; -import '@console/cypress-integration-tests/support/login'; -import '@console/cypress-integration-tests/support/project'; -import '@console/cypress-integration-tests/support'; -import '@console/dev-console/integration-tests/support/commands/app'; -import './hooks'; diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/pages/functions/webTerminalConfiguration.ts b/frontend/packages/webterminal-plugin/integration-tests/support/pages/functions/webTerminalConfiguration.ts deleted file mode 100644 index ef2bc6e9ffc..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/pages/functions/webTerminalConfiguration.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { devNavigationMenu } from '@console/dev-console/integration-tests/support/constants'; -import { navigateTo } from '@console/dev-console/integration-tests/support/pages/app'; - -export const webTerminalConfiguration = () => { - navigateTo(devNavigationMenu.Consoles); - cy.byLegacyTestID('actions-menu-button').should('be.visible').click(); - cy.byTestActionID('Customize').should('be.visible').click(); - cy.wait(5000); - cy.get('[role="presentation"]').contains('Web Terminal').should('be.visible').click(); -}; diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/common/webTerminal.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/common/webTerminal.ts deleted file mode 100644 index 18087aba69a..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/common/webTerminal.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Given, When, Then, And } from 'cypress-cucumber-preprocessor/steps'; -import { switchPerspective } from '@console/dev-console/integration-tests/support/constants'; -import { perspective } from '@console/dev-console/integration-tests/support/pages'; -import { checkDeveloperPerspective } from '@console/dev-console/integration-tests/support/pages/functions/checkDeveloperPerspective'; -import { checkTerminalIcon } from '@console/dev-console/integration-tests/support/pages/functions/checkTerminalIcon'; -import { webTerminalPage } from '@console/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/webTerminal-page'; - -const idp = Cypress.expose('BRIDGE_HTPASSWD_IDP') || 'test'; -const username = Cypress.expose('BRIDGE_HTPASSWD_USERNAME') || 'test'; -const kubeAdmUserName = Cypress.expose('KUBEADMIN_NAME') || 'kubeadmin'; - -// create web terminal instance in dedicated namespace under basic user and relogin as admin with oc client -function installDevWsAndReconfigureIdlingTimeout(dedicatedNamespace: string) { - // we need to create an active terminal session in background before test, also - // we rewrite default idling timeout for the terminal (because 15 min - too long change it to 1 min) - cy.env(['BRIDGE_HTPASSWD_PASSWORD', 'BRIDGE_KUBEADMIN_PASSWORD']).then( - ({ BRIDGE_HTPASSWD_PASSWORD, BRIDGE_KUBEADMIN_PASSWORD }) => { - const password = BRIDGE_HTPASSWD_PASSWORD || 'test'; - try { - cy.exec(`oc login -u ${username} -p ${password} --insecure-skip-tls-verify`); - cy.exec(`oc new-project ${dedicatedNamespace}`); - cy.exec( - `oc apply -f testData/yamls/web-terminal/web-terminal.yaml -n ${dedicatedNamespace}`, - ); - cy.exec( - `oc login -u ${kubeAdmUserName} -p ${BRIDGE_KUBEADMIN_PASSWORD} --insecure-skip-tls-verify`, - ); - } catch (err) { - // relogin as admin if something went wrong - cy.exec( - `oc login -u ${kubeAdmUserName} -p ${BRIDGE_KUBEADMIN_PASSWORD} --insecure-skip-tls-verify`, - ); - throw err; - } - // override the default idling timeout from 15 minutes to 1 minute - cy.exec( - 'oc apply -f testData/yamls/web-terminal/dev-ws-custom-idling-config.yaml -n openshift-operators', - ); - }, - ); -} - -Given('user can see terminal icon on masthead', () => { - checkTerminalIcon(); - - webTerminalPage.verifyCloudShellBtn(); -}); - -When('user clicks on the Web Terminal icon on the Masthead', () => { - webTerminalPage.clickOpenCloudShellBtn(); - cy.get('[data-test="loading-box"]').should('not.exist'); -}); - -Then('user will see the terminal window', () => { - cy.get('.co-cloudshell-terminal__container').should('be.visible'); - // cy.wait(15000); - webTerminalPage.verifyWebTerminalWindow(); -}); - -// check existing of web terminal in the dedicated project. Create it for the correct checking if a webterminal instance is not existed. -// It needs the web-terminal-basic.feature -Given('user has installed webTerminal in namespace {string}', (namespace: string) => { - let devWsExistingOutput: string = ''; - cy.exec(`oc get DevWorkspace -n ${namespace}`, { failOnNonZeroExit: false }) - .then((result) => { - devWsExistingOutput = result.stderr; - }) - .then(() => { - if ( - devWsExistingOutput.startsWith('No resources found') || - devWsExistingOutput.includes('Forbidden') - ) { - installDevWsAndReconfigureIdlingTimeout(namespace); - } - }); -}); - -And('user has logged in as basic user', () => { - Cypress.session.clearAllSavedSessions(); - cy.env(['BRIDGE_HTPASSWD_PASSWORD']).then(({ BRIDGE_HTPASSWD_PASSWORD }) => { - cy.login(idp, username, BRIDGE_HTPASSWD_PASSWORD || 'test'); - // sometimes guide tour is not closed properly without delay - cy.wait(1000); - }); -}); - -Given('user is at developer perspective', () => { - checkDeveloperPerspective(); -}); - -Given('user is at administrator perspective', () => { - perspective.switchTo(switchPerspective.Administrator); -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/customization/customization-of-web-terminal.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/customization/customization-of-web-terminal.ts deleted file mode 100644 index 7caf09e324d..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/customization/customization-of-web-terminal.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps'; -import { nav } from '@console/cypress-integration-tests/views/nav'; -import { - devNavigationMenu, - switchPerspective, -} from '@console/dev-console/integration-tests/support/constants'; -import { - app, - installWebterminalOperatorUsingCLI, - navigateTo, - perspective, -} from '@console/dev-console/integration-tests/support/pages'; -import { webTerminalConfiguration } from '../../pages/functions/webTerminalConfiguration'; - -Given('user has installed Web Terminal operator', () => { - installWebterminalOperatorUsingCLI(); - cy.reload(); - app.waitForDocumentLoad(); -}); - -Given('user has logged in as admin user', () => { - perspective.switchTo(switchPerspective.Administrator); - nav.sidenav.switcher.shouldHaveText(switchPerspective.Administrator); -}); - -Given('user is at Consoles page', () => { - navigateTo(devNavigationMenu.Consoles); -}); - -When('user clicks on Web Terminal tab', () => { - cy.wait(5000); - cy.get('[role="presentation"]').contains('Web Terminal').should('be.visible').click(); -}); - -Then('user should see Web Terminal Configuration page', () => { - cy.byTestID('web-terminal form-section').should('be.visible'); -}); - -Given('user is at Web Terminal Configuration page', () => { - webTerminalConfiguration(); -}); - -When('user switches to Developer tab', () => { - cy.get('[role="presentation"]').contains('Developer').should('be.visible').click(); -}); - -When('user increase the timeout value and set unit as {string}', (unit: string) => { - cy.get('[data-test-id="Increment"]').should('be.visible').click(); - cy.byTestID('console-select-menu-toggle').click(); - cy.byTestID('console-select-item').contains(unit).click(); -}); - -When('user enters image value as {string}', (image: string) => { - cy.get('[data-test="web-terminal-image"]').should('be.visible').clear().type(image); -}); - -When('user clicks on Save button to save web terminal settings', () => { - cy.get('[data-test="save-button"]').should('be.enabled').click(); -}); - -Then('user should see a success alert', () => { - cy.get('[aria-label="Success Alert"]').should('be.visible'); -}); - -When('user checks checkboxes to save data even after operator restarts or update', () => { - cy.get('[data-test="timeout-value-checkbox"]').should('be.enabled').check(); - cy.get('[data-test="image-value-checkbox"]').should('be.enabled').check(); -}); - -When('user unchecks checkboxes to save data even after operator restarts or update', () => { - cy.get('[data-test="timeout-value-checkbox"]').should('be.enabled').uncheck(); - cy.get('[data-test="image-value-checkbox"]').should('be.enabled').uncheck(); -}); - -When('user navigates to Cluster configuration page', () => { - cy.byLegacyTestID('actions-menu-button').should('be.visible').click(); - cy.byTestActionID('Customize').should('be.visible').click(); -}); - -Then( - 'user should see timeout checkbox to save data even after operator restarts or update is unchecked', - () => { - cy.get('[data-test="timeout-value-checkbox"]').should('not.be.checked'); - }, -); - -Then( - 'user should see image checkbox to save data even after operator restarts or update is unchecked', - () => { - cy.get('[data-test="image-value-checkbox"]').should('not.be.checked'); - }, -); - -Then( - 'user should see timeout checkbox to save data even after operator restarts or update is checked', - () => { - cy.get('[data-test="timeout-value-checkbox"]').should('be.checked'); - }, -); - -Then( - 'user should see image checkbox to save data even after operator restarts or update is checked', - () => { - cy.get('[data-test="image-value-checkbox"]').should('be.checked'); - }, -); - -When( - 'user decides not to save image value by unchecking the checkbox to save data even after operator restarts or update in Web Terminal Configuration page', - () => { - cy.get('[data-test="image-value-checkbox"]').should('be.enabled').uncheck(); - }, -); - -When( - ' user decides not to save timeout value by unchecking the checkbox to save data even after operator restarts or update in Web Terminal Configuration page', - () => { - cy.get('[data-test="timeout-value-checkbox"]').should('be.enabled').uncheck(); - }, -); - -Then('user should see new image value as {string}', (imageValue: string) => { - cy.get('[data-test="web-terminal-image"]').should('have.value', imageValue); -}); - -Then('user should see new timeout unit as {string}', (unitValue: string) => { - cy.byTestID('console-select-menu-toggle').should('include.text', unitValue); -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/initTerminal-page.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/initTerminal-page.ts deleted file mode 100644 index 9f1c81382f2..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/initTerminal-page.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { formPO } from '@console/dev-console/integration-tests/support/pageObjects'; -import { webTerminalPO } from '@console/dev-console/integration-tests/support/pageObjects/webterminal-po'; -import { app } from '@console/dev-console/integration-tests/support/pages/app'; - -export const initTerminalPage = { - clickOnProjectDropDown: () => { - app.waitForDocumentLoad(); - cy.get(webTerminalPO.createProjectMenu.createProjectDropdownMenu).click('center'); - }, - - selectCreateProjectButton: () => { - cy.get(webTerminalPO.createProjectMenu.createProjectButton).click(); - }, - - typeProjectName: (projectName: string) => { - cy.get(webTerminalPO.projectNameMenu.projectNameField).type(projectName); - }, - - clickStartButton: () => { - cy.get(formPO.create).should('be.enabled').click({ force: true }); - cy.get('[data-test="loading-box-body"]').should('exist'); - }, - - selectProject: (projectName: string) => { - cy.byTestID(webTerminalPO.createProjectMenu.inputField) - .type(projectName) - .should('have.value', projectName); - cy.byTestID('console-select-item').contains(projectName).click(); - }, - - createAndStartTerminalInNewProject: (projectName: string) => { - initTerminalPage.clickOnProjectDropDown(); - initTerminalPage.selectCreateProjectButton(); - initTerminalPage.typeProjectName(projectName); - initTerminalPage.clickStartButton(); - }, - - startTerminalInExistedProject: (projectName: string) => { - initTerminalPage.clickOnProjectDropDown(); - initTerminalPage.selectProject(projectName); - initTerminalPage.clickStartButton(); - }, -}; diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/webTerminal-page.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/webTerminal-page.ts deleted file mode 100644 index 2941051b2f3..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/webTerminal-page.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { warningModal } from '@console/cypress-integration-tests/views/warning-modal'; -import { messages } from '@console/dev-console/integration-tests/support/constants/webTerminal'; -import { webTerminalPO } from '@console/dev-console/integration-tests/support/pageObjects/webterminal-po'; - -export const webTerminalPage = { - clickOpenCloudShellBtn: () => cy.get(webTerminalPO.openCommandLine).click(), - - verifyCloudShellBtn: () => cy.get(webTerminalPO.openCommandLine).should('be.visible'), - - verifyWebTerminalWindow: () => cy.get(webTerminalPO.terminalWindow).should('be.visible'), - - verifyOpenInNewTabButton: () => { - cy.get(webTerminalPO.terminalOpenInNewTabBtn).should('be.visible'); - }, - - verifyOpenningInNewTabAttrButton: () => { - cy.get(webTerminalPO.terminalOpenInNewTabBtn) - .invoke('attr', 'target') - .should('equal', '_blank'); - }, - verifyInnactivityMessage: (timeout: number) => { - cy.get(webTerminalPO.terminalInnactivityMessageArea, { timeout }).should( - 'contain.text', - messages.inactivityMessage, - ); - }, - - verifyRestartTerminalButton: () => { - cy.get('button').contains('Restart terminal'); - }, - - closeCurrentTerminalSession: () => { - cy.get(webTerminalPO.terminalCloseWindowBtn).click(); - warningModal.shouldBeOpened('WebTerminalCloseConfirmation'); - warningModal.confirm('WebTerminalCloseConfirmation'); - }, - - deleteTerminalInstanceActionMenu: () => { - cy.byLegacyTestID('actions-menu-button').should('be.visible').click(); - cy.get('[role="menu"]').should('be.visible'); - cy.byTestActionID('Delete DevWorkspace').should('be.visible').click(); - cy.get('[role="dialog"]').should('be.visible'); - cy.byTestID('confirm-action').click(); - cy.byTestID('empty-box').should('be.visible'); - }, -}; diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-Terminal-devuser.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-Terminal-devuser.ts deleted file mode 100644 index 6df89d77995..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-Terminal-devuser.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { When, Then } from 'cypress-cucumber-preprocessor/steps'; -import { - devWorkspaceStatuses, - switchPerspective, -} from '@console/dev-console/integration-tests/support/constants'; -import { webTerminalPO } from '@console/dev-console/integration-tests/support/pageObjects/webterminal-po'; -import { perspective } from '@console/dev-console/integration-tests/support/pages'; -import { devWorkspacePage } from '@console/dev-console/integration-tests/support/pages/devworspace/devworkspacePage'; -import { searchResource } from '@console/dev-console/integration-tests/support/pages/search-resources/search-page'; -import { initTerminalPage } from '@console/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/initTerminal-page'; - -When('user selects Create Project from Project drop down menu', () => { - initTerminalPage.clickOnProjectDropDown(); - initTerminalPage.selectCreateProjectButton(); -}); - -When('user enters project name {string}', (projectName: string) => { - initTerminalPage.typeProjectName(projectName); - cy.byTestID('confirm-action').click(); -}); - -When('user clicks on Start button', () => { - initTerminalPage.clickStartButton(); -}); - -Then( - 'user will see the terminal instance for developer namespace {string}', - (nameSpace: string) => { - initTerminalPage.clickOnProjectDropDown(); - cy.byTestID(webTerminalPO.createProjectMenu.inputField) - .type(nameSpace) - .should('have.value', nameSpace); - cy.byTestID('console-select-item').contains(nameSpace).click(); - perspective.switchTo(switchPerspective.Administrator); - searchResource.searchResourceByNameAsAdmin('DevWorkspace'); - cy.get('div').contains('Resources').click(); - searchResource.selectSearchedItem('terminal'); - devWorkspacePage.verifyDevWsResourceStatus(devWorkspaceStatuses.running); - cy.exec(`oc delete namespace ${nameSpace}`, { failOnNonZeroExit: true }); - }, -); - -When('user selects {string} from Project drop down menu', (projectName: string) => { - initTerminalPage.clickOnProjectDropDown(); - initTerminalPage.selectProject(projectName); -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-teminal-basic.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-teminal-basic.ts deleted file mode 100644 index ac82ceb6a7a..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-teminal-basic.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { When, Then, And, Given } from 'cypress-cucumber-preprocessor/steps'; -import { - adminNavigationMenuPO, - devNavigationMenuPO, -} from '@console/dev-console/integration-tests/support/pageObjects'; -import { - installWebterminalOperatorUsingCLI, - projectNameSpace, -} from '@console/dev-console/integration-tests/support/pages'; -import { webTerminalPage } from '@console/webterminal-plugin/integration-tests/support/step-definitions/pages/web-terminal/webTerminal-page'; - -Given('user with basic rights has installed Web Terminal operator', () => { - installWebterminalOperatorUsingCLI(); -}); - -When('user clicks on Open Terminal in new tab button on the terminal window', () => { - webTerminalPage.verifyOpenInNewTabButton(); -}); -Then('user close current Web Terminal session', () => { - webTerminalPage.closeCurrentTerminalSession(); -}); -Then('user will see the terminal window opened in new tab', () => { - webTerminalPage.verifyOpenningInNewTabAttrButton(); -}); - -And('user does nothing with displayed terminal window 1 minutes', () => { - const terminalIdlingTimeout: number = Number(Cypress.expose('TERMINAL_IDLING_TIMEOUT')) || 180000; // [workaround] changed to 180 seconds due to https://issues.redhat.com/browse/WTO-334 - cy.wait(terminalIdlingTimeout); - webTerminalPage.verifyInnactivityMessage(terminalIdlingTimeout); -}); - -Then( - 'user will be informed that terminal is closed by inactivity and is proposed to restart it', - () => { - webTerminalPage.verifyRestartTerminalButton(); - }, -); - -Given('user has created or selected namespace {string}', (projectName: string) => { - Cypress.expose('NAMESPACE', projectName); - cy.get(adminNavigationMenuPO.workloads.main).click(); - cy.get(devNavigationMenuPO.topology).click(); - projectNameSpace.selectOrCreateProject(`${projectName}`); - // cy.get(devNavigationMenuPO.project).click(); -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-terminal-adminuser.ts b/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-terminal-adminuser.ts deleted file mode 100644 index fa175700e7b..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/support/step-definitions/web-terminal/web-terminal-adminuser.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { Given, When, Then, And } from 'cypress-cucumber-preprocessor/steps'; -import { - switchPerspective, - devWorkspaceStatuses, -} from '@console/dev-console/integration-tests/support/constants'; -import { webTerminalPO } from '@console/dev-console/integration-tests/support/pageObjects/webterminal-po'; -import { - perspective, - projectNameSpace, -} from '@console/dev-console/integration-tests/support/pages'; -import { devWorkspacePage } from '@console/dev-console/integration-tests/support/pages/devworspace/devworkspacePage'; -import { - addTerminals, - closeTerminal, -} from '@console/dev-console/integration-tests/support/pages/functions/addTerminalTabs'; -import { checkTerminalIcon } from '@console/dev-console/integration-tests/support/pages/functions/checkTerminalIcon'; -import { operatorsPage } from '@console/dev-console/integration-tests/support/pages/operators-page'; -import { searchResource } from '@console/dev-console/integration-tests/support/pages/search-resources/search-page'; - -Given('user has logged in', () => { - cy.login(); -}); - -Given('user has closed existing terminal workspace', () => { - cy.exec('oc delete devworkspaces --all -n openshift-terminal', { - failOnNonZeroExit: false, - timeout: 30000, - }); -}); - -Given('user can see terminal icon on masthead', () => { - checkTerminalIcon(); - cy.get(webTerminalPO.webTerminalIcon).should('be.visible'); -}); - -When('user clicks on the Web Terminal icon on the Masthead', () => { - cy.get(webTerminalPO.webTerminalIcon).click(); - cy.get('[data-test="loading-box"]').should('not.exist'); -}); - -When('user clicks advanced option for Timeout', () => { - cy.get('[role="tabpanel"] button').contains('Timeout').should('be.visible').click(); -}); - -When('user sets timeout to {string} Minute', (time: string) => { - cy.byLegacyTestID('Increment').click(); - cy.get('input[aria-label="Input"]').should('not.have.value', '0'); - cy.get('input[aria-label="Input"]').clear().invoke('val', time).trigger('change'); - cy.get('input[aria-label="Input"]').should('have.value', time); -}); - -When('user opens {int} additional web terminal tabs', (n: number) => { - addTerminals(n); -}); - -When('user closed {string} web terminal tab', (n: string) => { - closeTerminal(n); -}); - -When('user closed web terminal window', () => { - cy.byTestID('cloudshell-drawer-close-button').should('be.visible').click(); - cy.wait(2000); -}); - -Then('user is able see {int} web terminal tabs', (n: number) => { - cy.get(webTerminalPO.tabsList).then(($el) => { - expect($el.prop('children').length).toEqual(n); - }); -}); - -Then('user will get created DevWorkspace instance in {string} namespace', (namespace: string) => { - searchResource.searchResourceByNameAsAdmin('DevWorkspace'); - searchResource.verifyItemInSearchResultsByPreffixName(namespace); - searchResource.selectSearchedItem('terminal'); - devWorkspacePage.verifyDevWsResourceStatus(devWorkspaceStatuses.running); -}); - -And( - 'user ID obtained by API should match with user id in yaml editor for {string} namespace', - (terminalNamespace: string) => { - let k8sUserId: string = ''; - const devWsNamePrefURI = `/workspace.devfile.io/v1alpha1/namespaces/${terminalNamespace}/devworkspaces`; - let devWsName: string = ''; - const baseUrl = Cypress.config('baseUrl'); - const apiPrefURI = `${baseUrl}/api/kubernetes/apis`; - const linkToYamlEditorPrefURI = `${baseUrl}/k8s/ns/${terminalNamespace}/workspace.devfile.io~v1alpha1~DevWorkspace/`; - - // get the devworkspace name from resource title - cy.get('[data-test="page-heading"] h1 [data-test-id="resource-title"]') - .should('be.visible') - .then(($item) => { - devWsName = $item.text(); - }); - // get user ID with the Cypress request to k8s API - cy.request(apiPrefURI + devWsNamePrefURI) - .then((responce) => { - k8sUserId = responce.body.items[0].metadata.uid; - }) - // go to the yaml editor by direct URL and assert user ids in the editor and obteined with API request - .then(() => { - cy.visit(`${linkToYamlEditorPrefURI}${devWsName}/yaml`); - }) - .then(() => { - cy.get('div.lines-content.monaco-editor-background').should('include.text', k8sUserId); - }); - }, -); - -Then('user will see the terminal instance for namespace {string}', (nameSpace: string) => { - perspective.switchTo(switchPerspective.Administrator); - operatorsPage.navigateToInstallOperatorsPage(); - // verifyWebTerminalAvailability(); - projectNameSpace.selectProject(nameSpace); - searchResource.searchResourceByNameAsAdmin('DevWorkspace'); - searchResource.selectSearchedItem('terminal'); - // Disabling following line due to terminal loading issue from backend at the first load - // devWorkspacePage.verifyDevWsResourceStatus(devWorkspaceStatuses.running); -}); - -Given('user has created or selected namespace {string}', (projectName: string) => { - Cypress.expose('NAMESPACE', projectName); - projectNameSpace.selectOrCreateProject(`${projectName}`); - // cy.get(devNavigationMenuPO.project).click(); -}); diff --git a/frontend/packages/webterminal-plugin/integration-tests/testData/devworkspaceOperatorSubscription.yaml b/frontend/packages/webterminal-plugin/integration-tests/testData/devworkspaceOperatorSubscription.yaml deleted file mode 100644 index e46c4b9b068..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/testData/devworkspaceOperatorSubscription.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: CatalogSource -metadata: - name: devworkspace-operator-catalog - namespace: openshift-marketplace -spec: - displayName: DevWorkspace Operator Catalog - image: 'quay.io/devfile/devworkspace-operator-index:next' - publisher: Red Hat - sourceType: grpc - updateStrategy: - registryPoll: - interval: 10m ---- -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: devworkspace-operator - namespace: openshift-operators -spec: - channel: next - installPlanApproval: Automatic - name: devworkspace-operator - source: devworkspace-operator-catalog - sourceNamespace: openshift-marketplace - startingCSV: devworkspace-operator.v0.32.0-dev.5 diff --git a/frontend/packages/webterminal-plugin/integration-tests/testData/webterminalOperatorSubscription.yaml b/frontend/packages/webterminal-plugin/integration-tests/testData/webterminalOperatorSubscription.yaml deleted file mode 100644 index a3db0b621e8..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/testData/webterminalOperatorSubscription.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: web-terminal - namespace: openshift-operators -spec: - channel: fast - installPlanApproval: Automatic - name: web-terminal - source: redhat-operators - sourceNamespace: openshift-marketplace - startingCSV: web-terminal.v1.10.0 \ No newline at end of file diff --git a/frontend/packages/webterminal-plugin/integration-tests/tsconfig.json b/frontend/packages/webterminal-plugin/integration-tests/tsconfig.json deleted file mode 100644 index e3f5737b750..00000000000 --- a/frontend/packages/webterminal-plugin/integration-tests/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../dev-console/integration-tests/tsconfig.json", - "include": ["**/*.ts", "./support/commands/index.ts"], - "paths": { - "pages/*":["support/pages/*"], - "page-objects/*": ["support/pageObjects/*"], - "constants/*": ["support/constants/*"] - } -} diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 57ce72baede..c08914a504c 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -27,7 +27,7 @@ const packages = [ ]; // Packages that also have developer-persona tests -const devPackages = ['smoke', 'dev-console', 'shipwright', 'topology']; +const devPackages = ['smoke', 'dev-console', 'shipwright', 'topology', 'webterminal']; const chromeArgs = [ '--ignore-certificate-errors', diff --git a/frontend/public/components/namespace-bar.tsx b/frontend/public/components/namespace-bar.tsx index 7bafe0d60ef..9ab7783c676 100644 --- a/frontend/public/components/namespace-bar.tsx +++ b/frontend/public/components/namespace-bar.tsx @@ -91,7 +91,11 @@ export const NamespaceBarDropdowns: FC = ({ } return ( -
+
{ onNamespaceChange?.(newNamespace); @@ -139,7 +143,11 @@ export const NamespaceBar: FC = return (
{hideProjects ? ( -
+
{children}
) : ( diff --git a/frontend/public/components/utils/number-spinner.tsx b/frontend/public/components/utils/number-spinner.tsx index f1b07c38c06..0e9fd3b105f 100644 --- a/frontend/public/components/utils/number-spinner.tsx +++ b/frontend/public/components/utils/number-spinner.tsx @@ -26,9 +26,9 @@ export const NumberSpinner: FC = ({ inputProps={{ ...inputProps }} className={className} minusBtnAriaLabel={t('public~Decrement')} - minusBtnProps={{ 'data-test-id': 'Decrement' } as ButtonProps} + minusBtnProps={{ 'data-test-id': 'Decrement', 'data-test': 'Decrement' } as ButtonProps} plusBtnAriaLabel={t('public~Increment')} - plusBtnProps={{ 'data-test-id': 'Increment' } as ButtonProps} + plusBtnProps={{ 'data-test-id': 'Increment', 'data-test': 'Increment' } as ButtonProps} isDisabled={inputProps.disabled} />
diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 1a95458a51b..23f1e3e9725 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -5671,12 +5671,6 @@ __metadata: languageName: node linkType: hard -"@webterminal-plugin/integration-tests@workspace:packages/webterminal-plugin/integration-tests": - version: 0.0.0-use.local - resolution: "@webterminal-plugin/integration-tests@workspace:packages/webterminal-plugin/integration-tests" - languageName: unknown - linkType: soft - "@wry/context@npm:^0.4.0": version: 0.4.4 resolution: "@wry/context@npm:0.4.4"