Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Adding login/logout test #3977

Merged
merged 2 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions test/ui/Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,20 @@ node('rhel8') {
}
}
}
stage('cluster-dependent UI tests') {
wrap([$class: 'Xvnc']) {
sh "npm run cluster-ui-test"
junit 'report.xml'
withEnv(['PATH+EXTRA=' + pwd()]){
stage('cluster-dependent UI tests') {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
wrap([$class: 'Xvnc']) {
sh 'curl -L -o $(pwd)/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"'
sh 'chmod +x kubectl'
sh "npm run cluster-ui-test"
junit 'report.xml'
}
}
}
}
stage('Archive Artifacts'){
archiveArtifacts artifacts: '/tmp/test-resources/screenshots/*', allowEmptyArchive: true
}
}
}
2 changes: 2 additions & 0 deletions test/ui/cluster-ui-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as path from 'path';
import { createComponentTest } from './suite/component';
import { checkExtension } from './suite/extension';
import { checkOpenshiftView } from './suite/openshift';
import { loginTest } from './suite/login';

describe('Extension cluster-dependant UI tests', function () {
const kubeConfig = path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.kube', 'config');
Expand All @@ -31,5 +32,6 @@ describe('Extension cluster-dependant UI tests', function () {

checkExtension();
checkOpenshiftView();
loginTest();
createComponentTest(contextFolder);
});
4 changes: 4 additions & 0 deletions test/ui/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ export const INPUTS = {
newFolderQuickPick: 'Select workspace for component',
yes: 'Yes',
no: 'No',
logout: 'Logout',
};

export const MENUS = {
newProject: 'New Project',
delete: 'Delete',
deleteProject: 'Delete Project',
bindService: 'Bind Service',
startDev: 'Start Dev',
};
Expand All @@ -51,4 +53,6 @@ export const NOTIFICATIONS = {
projectDeleteSuccess: (projectName: string) => `Project '${projectName}' successfully deleted`,
savePasswordPrompt: 'Do you want to save username and password?',
loginSuccess: (cluster: string) => `Successfully logged in to '${cluster}'`,
doYouWantLogOut: 'Do you want to logout of cluster?',
logoutSuccess: 'Successfully logged out. Do you want to login to a new cluster'
};
92 changes: 18 additions & 74 deletions test/ui/suite/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
*-----------------------------------------------------------------------------------------------*/

import { expect } from 'chai';
import { ActivityBar, EditorView, InputBox, NotificationType, SideBarView, TerminalView, TreeItem, ViewSection, VSBrowser, WelcomeContentButton, Workbench } from 'vscode-extension-tester';
import { itemExists, notificationExists, terminalHasText, waitForInputUpdate } from '../common/conditions';
import { BUTTONS, COMPONENTS, INPUTS, MENUS, NOTIFICATIONS, VIEWS } from '../common/constants';
import { ActivityBar, EditorView, InputBox, NotificationType, SideBarView, TerminalView, TreeItem, VSBrowser, ViewSection, Workbench } from 'vscode-extension-tester';
import { notificationExists, itemExists, terminalHasText } from '../common/conditions';
import { VIEWS, MENUS, NOTIFICATIONS, INPUTS, COMPONENTS } from '../common/constants';



export function createComponentTest(contextFolder: string) {
describe('Component creation', function() {
describe('Component creation', function () {
const cluster = process.env.CLUSTER_URL || 'https://api.crc.testing:6443';
const clusterName = cluster;
const user = process.env.CLUSTER_USER || 'developer';
const password = process.env.CLUSTER_PASSWORD || 'developer';

let view: SideBarView;
let explorer: ViewSection;
let components: ViewSection;
Expand All @@ -29,106 +30,49 @@ export function createComponentTest(contextFolder: string) {
editorView = new EditorView();
});

beforeEach(async function() {
beforeEach(async function () {
const notificationCenter = await new Workbench().openNotificationsCenter();
const notifications = await notificationCenter.getNotifications(NotificationType.Any);
if(notifications.length > 0) {
if (notifications.length > 0) {
await notificationCenter.close();
}
await new EditorView().closeAllEditors();
});

afterEach(async function() {
afterEach(async function () {
editorView = new EditorView();
await editorView.closeAllEditors();
});

after(async function() {
after(async function () {
this.timeout(60000);
const projectItem = await explorer.findItem(projectName);
if (projectItem) {
const menu = await projectItem.openContextMenu();
await menu.select(MENUS.delete);
await menu.select(MENUS.deleteProject);
const notif = await notificationExists(NOTIFICATIONS.deleteProjectWarning(projectName), VSBrowser.instance.driver);
await notif.takeAction(INPUTS.yes);
await notificationExists(NOTIFICATIONS.projectDeleteSuccess(projectName), VSBrowser.instance.driver, 40000);
}
});

it('Login with credentials', async function() {
this.timeout(30_000);
await explorer.expand();
const content = await explorer.findWelcomeContent();
// eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
console.log(`content: ${await Promise.all((await content.getButtons()).map(async item => await item.getTitle()))}`);
const btns = await content.getButtons();
let loginBtn: WelcomeContentButton;

for(const btn of btns) {
if (await btn.getTitle() === BUTTONS.login) {
loginBtn = btn;
break;
}
}
if (!loginBtn) {
expect.fail('No login button available');
}
await loginBtn.click();
// select new URL
const inputBox = await InputBox.create();
await inputBox.selectQuickPick(INPUTS.newUrlQuickPick);

// provide the cluster URL
const clusterMessage = await waitForInputUpdate(inputBox, '');
await inputBox.setText(cluster);
await inputBox.confirm();

// select credentials login
const typeMessage = await waitForInputUpdate(inputBox, clusterMessage);
await inputBox.selectQuickPick(INPUTS.credentialsQuickPick);

// create new credentials
const userMessage = await waitForInputUpdate(inputBox, typeMessage);
await inputBox.selectQuickPick(INPUTS.newUserQuickPick);

// provide user name
const nameMessage = await waitForInputUpdate(inputBox, userMessage);
await inputBox.setText(user);
await inputBox.confirm();

// provide password
await waitForInputUpdate(inputBox, nameMessage);
await inputBox.setText(password);
await inputBox.confirm();

// don't save the credentials when asked
const notification = await notificationExists(NOTIFICATIONS.savePasswordPrompt, VSBrowser.instance.driver);
await notification.takeAction(INPUTS.no);

// wait for confirmation that the login was successful
await notificationExists(NOTIFICATIONS.loginSuccess(cluster), VSBrowser.instance.driver, 15000);

// make sure the cluster shows up in the tree view
const clusterItem = await itemExists(clusterName, explorer);
expect(clusterItem).not.undefined;
});

it('Create a new project', async function() {
it('Create a new project', async function () {
this.timeout(30000);
await explorer.expand();
const clusterItem = await explorer.findItem(clusterName) as TreeItem;
await clusterItem.expand();
await new Promise((res) => { setTimeout(res, 2_500); });
const menu = await clusterItem.openContextMenu();
await menu.select(MENUS.newProject);

const input = await InputBox.create();
await input.setText(projectName);
await input.confirm();

await clusterItem.expand();
await itemExists(projectName, explorer);
});

it.skip('Create a new component from scratch', async function() {
it.skip('Create a new component from scratch', async function () {
this.timeout(120_000);
const newComponent = (await (await components.findWelcomeContent()).getButtons())[1];
await newComponent.click();
Expand Down Expand Up @@ -165,7 +109,7 @@ export function createComponentTest(contextFolder: string) {
});

// Pending on https://github.com/redhat-developer/vscode-extension-tester/pull/855
it.skip('Start the component in dev mode', async function() {
it.skip('Start the component in dev mode', async function () {
this.timeout(180000);
const component = await itemExists(compName, components, 30_000);

Expand All @@ -186,7 +130,7 @@ export function createComponentTest(contextFolder: string) {
await itemExists(compName, components, 60_000);
});

it.skip('Check for \'Bind Service\' button (don\'t click it)', async function() {
it.skip('Check for \'Bind Service\' button (don\'t click it)', async function () {
this.timeout(60000);
const component = await itemExists(compName, components);
const menu = await component.openContextMenu();
Expand Down
135 changes: 135 additions & 0 deletions test/ui/suite/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { ActivityBar, InputBox, SideBarView, VSBrowser, ViewSection } from 'vscode-extension-tester';
import { INPUTS, NOTIFICATIONS, VIEWS } from '../common/constants';
import { expect } from 'chai';
import { notificationExists, itemExists } from '../common/conditions';
import { activateCommand } from '../common/command-activator';
import { collapse } from '../common/overdrives';

export function loginTest() {
describe('Login', function () {
const user = process.env.CLUSTER_USER || 'developer';
const password = process.env.CLUSTER_PASSWORD || 'developer';
const cluster = process.env.CLUSTER_URL || 'https://api.crc.testing:6443';
const clusterName = cluster;

let explorer: ViewSection;
let view: SideBarView;

before(async function context() {
view = await (await new ActivityBar().getViewControl(VIEWS.openshift)).openView();
explorer = await view.getContent().getSection(VIEWS.appExplorer);
await explorer.expand();
});

it('Login works when kube config is missing', async function test() {
this.timeout(30_000);

const content = await explorer.findWelcomeContent();
const welcomeContentButtons = await content.getButtons();
const loginButton = welcomeContentButtons[0];

await loginButton.click();

await login(true, false);

// don't save the credentials when asked
await saveCredentials(INPUTS.no);

// wait for confirmation that the login was successful
await notificationExists(NOTIFICATIONS.loginSuccess(cluster), VSBrowser.instance.driver, 15_000);

// make sure the cluster shows up in the tree view
const clusterItem = await itemExists(clusterName, explorer);
expect(clusterItem).to.be.not.undefined;
});

it('Logout works', async function test() {
await logout(INPUTS.no);
await new Promise((res) => { setTimeout(res, 1_500); });
const content = await explorer.findWelcomeContent();
expect(content).to.be.not.undefined;
});

it('Credentials can be saved', async function test() {
this.timeout(30_000);

explorer = await view.getContent().getSection(VIEWS.appExplorer);
await collapse(explorer);
//await explorer.collapse();
await explorer.expand();

const action = await explorer.getAction('Login into Cluster');
await action.click();

await login(false, false);
await saveCredentials(INPUTS.yes);

await notificationExists(NOTIFICATIONS.loginSuccess(cluster), VSBrowser.instance.driver, 15_000);
let clusterItem = await itemExists(clusterName, explorer);
expect(clusterItem).to.be.not.undefined;

await logout(INPUTS.yes);
await login(false, true);

await notificationExists(NOTIFICATIONS.loginSuccess(cluster), VSBrowser.instance.driver, 15_000);
clusterItem = await itemExists(clusterName, explorer);
expect(clusterItem).to.be.not.undefined;
});

async function login(firstLogin: boolean, savedPassword: boolean) {

// select new URL
let inputBox = await InputBox.create();
if (firstLogin) {
await inputBox.selectQuickPick(INPUTS.newUrlQuickPick);

// provide the cluster URL
await inputBox.setText(cluster);
await inputBox.confirm();
} else {
await inputBox.selectQuickPick(clusterName);
}

//select credentials login
inputBox = await InputBox.create();
await inputBox.selectQuickPick(INPUTS.credentialsQuickPick);

// set credentials
if (firstLogin) {
await inputBox.selectQuickPick(INPUTS.newUserQuickPick);
// provide user name
await inputBox.setText(user);
await inputBox.confirm();
} else {
await inputBox.selectQuickPick(user);
}

// provide password
if (!savedPassword) {
await inputBox.setText(password);
}

await inputBox.confirm();
}

async function saveCredentials(option: string) {
const notification = await notificationExists(NOTIFICATIONS.savePasswordPrompt, VSBrowser.instance.driver,);
await notification.takeAction(option);
}

async function logout(option: string) {
await activateCommand('>OpenShift: Log out');

let notification = await notificationExists(NOTIFICATIONS.doYouWantLogOut, VSBrowser.instance.driver);
await notification.takeAction(INPUTS.logout);

notification = await notificationExists(NOTIFICATIONS.logoutSuccess, VSBrowser.instance.driver);
await notification.takeAction(option);
}
});
}
Loading