Skip to content

Commit

Permalink
Merge branch 'cypress-RHOAIENG-17501' of https://github.com/antowaddl…
Browse files Browse the repository at this point in the history
…e/odh-dashboard into cypress-RHOAIENG-17501
  • Loading branch information
antowaddle committed Jan 29, 2025
2 parents a270460 + ba65003 commit 0c419f3
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# testClusterStorageCreation.cy.ts Test Data #
projectPVStorageResourceName: "cy-pv-storage-test"
pvStorageName: "cy-pv-storage"
pvStorageDescription: "Test Description of PV Storage"
pvStorageNameEdited: "cy-pv-storage-edited"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# testDataConnectionCreation.cy.ts Test Data #
projectDCResourceName: "cypress-dc-test-project"
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ class ClusterStorageModal extends Modal {
return this.find().findByTestId('modal-submit-button');
}

findPVStorageSizeValue() {
return this.find().find('[aria-label="Input"]');
}

private findPVSizeSelectButton() {
return this.find().findByTestId('value-unit-select');
}
Expand Down Expand Up @@ -234,6 +238,10 @@ class ClusterStorage {
findCreateButtonFromActions() {
return cy.findByTestId('actions-cluster-storage-button');
}

findKebabToggle() {
return cy.get('button[aria-label="Kebab toggle"]');
}
}

export const clusterStorage = new ClusterStorage();
Expand Down
72 changes: 72 additions & 0 deletions frontend/src/__tests__/cypress/cypress/pages/connections.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TableRow } from './components/table';
import { Modal } from './components/Modal';

class ConnectionsPage {
findTable() {
Expand All @@ -11,9 +12,80 @@ class ConnectionsPage {
);
}

findDataConnectionName() {
return cy.findByTestId('table-row-title');
}

findAddConnectionButton() {
return cy.findByTestId('add-connection-button');
}

findCreateConnectionButton() {
return cy.findByTestId('create-connection-button');
}

findKebabToggle() {
return cy.get('button[aria-label="Kebab toggle"]');
}

findDeleteButton() {
return cy.contains('.pf-v6-c-menu__item-text', 'Delete');
}
}
class ConnectionModal extends Modal {
constructor(edit = false) {
super(`${edit ? 'Edit' : 'Add'} connection`);
}

findConnectionTypeDropdown() {
return this.find().findByTestId('connection-type-dropdown');
}

findS3CompatibleStorageOption() {
return cy.findByText('S3 compatible object storage - v1');
}

findSubmitButton() {
return this.findFooter().findByTestId('data-connection-submit-button');
}

findCreateButton() {
return this.find().findByTestId('modal-submit-button');
}

findConnectionNameInput() {
return this.find().findByTestId('connection-name-desc-name');
}

findConnectionDescriptionInput() {
return this.find().findByTestId('connection-name-desc-description');
}

findNameInput() {
return this.find().findByTestId('field Name');
}

findAwsKeyInput() {
return this.find().findByTestId('field AWS_ACCESS_KEY_ID');
}

findAwsSecretKeyInput() {
return this.find().findByTestId('field AWS_SECRET_ACCESS_KEY');
}

findEndpointInput() {
return this.find().findByTestId('field AWS_S3_ENDPOINT');
}

findRegionInput() {
return this.find().findByTestId('field AWS_DEFAULT_REGION');
}

findBucketInput() {
return this.find().findByTestId('field AWS_S3_BUCKET');
}
}

export const connectionsPage = new ConnectionsPage();
export const addConnectionModal = new ConnectionModal(false);
export const editConnectionModal = new ConnectionModal(true);
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import type { DataScienceProjectData, DashboardConfig } from '~/__tests__/cypress/cypress/types';
import { projectDetails, projectListPage } from '~/__tests__/cypress/cypress/pages/projects';
import { HTPASSWD_CLUSTER_ADMIN_USER } from '~/__tests__/cypress/cypress/utils/e2eUsers';
import { loadDSPFixture } from '~/__tests__/cypress/cypress/utils/dataLoader';
import { createCleanProject } from '~/__tests__/cypress/cypress/utils/projectChecker';
import { deleteOpenShiftProject } from '~/__tests__/cypress/cypress/utils/oc_commands/project';
import {
clusterStorage,
addClusterStorageModal,
updateClusterStorageModal,
} from '~/__tests__/cypress/cypress/pages/clusterStorage';
import { deleteModal } from '~/__tests__/cypress/cypress/pages/components/DeleteModal';

describe('Verify Cluster Storage - Creating, Editing and Deleting', () => {
let testData: DataScienceProjectData;
let dashboardConfig: DashboardConfig;
let projectName: string;
let pvStorageName: string;
let pvStorageDescription: string;
let pvStorageNameEdited: string;

// Setup: Load test data and ensure clean state
before(() => {
// Retrieve the dashboard configuration
cy.getDashboardConfig().then((config) => {
dashboardConfig = config as DashboardConfig;
cy.log('Dashboard Config:', JSON.stringify(dashboardConfig, null, 2));
const { pvcSize } = dashboardConfig.notebookController;
cy.log(`Value of PVC Size: ${String(pvcSize)}`);
});
return loadDSPFixture('e2e/dataScienceProjects/testClusterStorageCreation.yaml')
.then((fixtureData: DataScienceProjectData) => {
testData = fixtureData;
projectName = testData.projectPVStorageResourceName;
pvStorageName = testData.pvStorageName;
pvStorageDescription = testData.pvStorageDescription;
pvStorageNameEdited = testData.pvStorageNameEdited;
if (!projectName) {
throw new Error('Project name is undefined or empty in the loaded fixture');
}
cy.log(`Loaded project name: ${projectName}`);
return createCleanProject(projectName);
})
.then(() => {
cy.log(`Project ${projectName} confirmed to be created and verified successfully`);
});
});
after(() => {
// Delete provisioned Project
if (projectName) {
cy.log(`Deleting Project ${projectName} after the test has finished.`);
deleteOpenShiftProject(projectName);
}
});

it(
'Create, Edit and Delete a Persistent Volume Storage',
{ tags: ['@Sanity', '@SanitySet1', '@ODS-1824', '@Dashboard'] },
() => {
// Authentication and navigation
cy.step('Log into the application');
cy.visitWithLogin('/', HTPASSWD_CLUSTER_ADMIN_USER);

// Project navigation and navigate to the Cluster Storage tab
cy.step(
`Navigate to the Project list tab and search for ${testData.projectPVStorageResourceName}`,
);
projectListPage.navigate();
projectListPage.filterProjectByName(testData.projectPVStorageResourceName);
projectListPage.findProjectLink(testData.projectPVStorageResourceName).click();

//Navigate to Cluster Storage and click to Add Storage
cy.step('Navigate to Cluster Storage and click to create Cluster Storage');
projectDetails.findSectionTab('cluster-storages').click();
clusterStorage.findCreateButton().click();

// Enter validate Cluster Storage details into the Cluster Storage Modal
cy.step('Enter valid Cluster Storage details and verify creation');
addClusterStorageModal.findNameInput().type(pvStorageName);
addClusterStorageModal.findDescriptionInput().type(pvStorageDescription);
const numericPvcSize = dashboardConfig.notebookController.pvcSize.replace(/\D/g, '');
addClusterStorageModal.findPVStorageSizeValue().should('have.value', numericPvcSize);
addClusterStorageModal.findSubmitButton().click();
clusterStorage.getClusterStorageRow(pvStorageName);

// Edit the Cluster Storage, amend the name and update
cy.step('Edit the Cluster Storage and verify edits are successful');
clusterStorage.findKebabToggle().click();
clusterStorage.getClusterStorageRow(pvStorageName).findKebabAction('Edit storage').click();
updateClusterStorageModal.findNameInput().clear();
updateClusterStorageModal.findNameInput().type(pvStorageNameEdited);
updateClusterStorageModal.findSubmitButton().click();
clusterStorage.getClusterStorageRow(pvStorageNameEdited);

// Delete the Cluster Storage and confirm that the deletion was successful
cy.step('Delete the Cluster Storage and verify deletion');
clusterStorage.findKebabToggle().click();
clusterStorage.getClusterStorageRow(pvStorageName).findKebabAction('Delete storage').click();
deleteModal.shouldBeOpen();
deleteModal.findInput().type(pvStorageName);
deleteModal.findSubmitButton().should('be.enabled').click();
clusterStorage.findEmptyState().should('exist');
},
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { HTPASSWD_CLUSTER_ADMIN_USER } from '~/__tests__/cypress/cypress/utils/e2eUsers';
import { projectListPage, projectDetails } from '~/__tests__/cypress/cypress/pages/projects';
import { deleteOpenShiftProject } from '~/__tests__/cypress/cypress/utils/oc_commands/project';
import type { DataScienceProjectData, AWSS3BucketDetails } from '~/__tests__/cypress/cypress/types';
import { connectionsPage, addConnectionModal } from '~/__tests__/cypress/cypress/pages/connections';
import { loadDSPFixture } from '~/__tests__/cypress/cypress/utils/dataLoader';
import { createCleanProject } from '~/__tests__/cypress/cypress/utils/projectChecker';
import { deleteModal } from '~/__tests__/cypress/cypress/pages/components/DeleteModal';
import { AWS_BUCKETS } from '~/__tests__/cypress/cypress/utils/s3Buckets';

describe('Verify Data Connections - Creation and Deletion', () => {
let testData: DataScienceProjectData;
let projectName: string;
let s3Config: AWSS3BucketDetails;
let s3AccessKey: string;
let s3SecretKey: string;

// Setup: Load test data and ensure clean state
before(() => {
const bucketKey = 'BUCKET_1' as const;
const bucketConfig = AWS_BUCKETS[bucketKey];

s3Config = bucketConfig;
s3AccessKey = AWS_BUCKETS.AWS_ACCESS_KEY_ID;
s3SecretKey = AWS_BUCKETS.AWS_SECRET_ACCESS_KEY;

cy.log('S3 Configuration:');
cy.log(`Bucket Name: ${s3Config.NAME}`);
cy.log(`Bucket Region: ${s3Config.REGION}`);
cy.log(`Bucket Endpoint: ${s3Config.ENDPOINT}`);
cy.log(`Access Key ID: ${s3AccessKey.substring(0, 5)}...`);
cy.log(`Secret Access Key: ${s3SecretKey.substring(0, 5)}...`);

return loadDSPFixture('e2e/dataScienceProjects/testDataConnectionCreation.yaml')
.then((fixtureData: DataScienceProjectData) => {
testData = fixtureData;
projectName = testData.projectDCResourceName;
if (!projectName) {
throw new Error('Project name is undefined or empty in the loaded fixture');
}
cy.log(`Loaded project name: ${projectName}`);
return createCleanProject(projectName);
})
.then(() => {
cy.log(`Project ${projectName} confirmed to be created and verified successfully`);
});
});
after(() => {
// Delete provisioned Project
if (projectName) {
cy.log(`Deleting Project ${projectName} after the test has finished.`);
deleteOpenShiftProject(projectName);
}
});

it(
'Create and Delete a Data Connection',
{ tags: ['@Sanity', '@SanitySet1', '@ODS-1826', '@Dashboard', '@Tier1'] },
() => {
// Authentication and navigation
cy.step('Log into the application');
cy.visitWithLogin('/', HTPASSWD_CLUSTER_ADMIN_USER);

// Project navigation
cy.step(`Navigate to the Project list tab and search for ${testData.projectDCResourceName}`);
projectListPage.navigate();
projectListPage.filterProjectByName(testData.projectDCResourceName);
projectListPage.findProjectLink(testData.projectDCResourceName).click();

//Navigate to Data Connections and create Connection
cy.step('Navigate to Connections and click to create Connection');
projectDetails.findSectionTab('connections').click();
connectionsPage.findCreateConnectionButton().click();

// Enter validate Data Connection details into the Data Connection Modal
cy.step('Enter valid Data Connection details and verify creation');
addConnectionModal.findConnectionTypeDropdown().click();
addConnectionModal.findS3CompatibleStorageOption().click();
addConnectionModal.findConnectionNameInput().type(s3Config.NAME);
addConnectionModal.findConnectionDescriptionInput().type('S3 Bucket Connection');
addConnectionModal.findAwsKeyInput().type(s3AccessKey);
addConnectionModal.findAwsSecretKeyInput().type(s3SecretKey);
addConnectionModal.findEndpointInput().type(s3Config.ENDPOINT);
addConnectionModal.findRegionInput().type(s3Config.REGION);
addConnectionModal.findBucketInput().type(s3Config.NAME);
addConnectionModal.findCreateButton().click();
connectionsPage.getConnectionRow(s3Config.NAME).find().should('exist');

// Delete the Data Connection and confirm that the deletion was successful
cy.step('Delete the Data Connection and verify deletion');
connectionsPage.findKebabToggle().click();
connectionsPage.getConnectionRow(s3Config.NAME).findKebabAction('Delete').click();
deleteModal.shouldBeOpen();
deleteModal.findInput().type(s3Config.NAME);
deleteModal.findSubmitButton().should('be.enabled').click();
connectionsPage.findDataConnectionName().should('not.exist');
},
);
});
5 changes: 5 additions & 0 deletions frontend/src/__tests__/cypress/cypress/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ export type DataScienceProjectData = {
projectMultiModelAdminResourceName: string;
multiModelAdminName: string;
modelOpenVinoExamplePath: string;
projectDCResourceName: string;
projectPVStorageResourceName: string;
pvStorageName: string;
pvStorageDescription: string;
pvStorageNameEdited: string;
invalidResourceNames: string[];
};

Expand Down
7 changes: 6 additions & 1 deletion frontend/src/concepts/connectionTypes/ConnectionTypeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@ const ConnectionTypeForm: React.FC<Props> = ({

return (
<>
<FormGroup label="Connection type" fieldId="connection-type" isRequired>
<FormGroup
label="Connection type"
fieldId="connection-type"
data-testid="connection-type-dropdown"
isRequired
>
<TypeaheadSelect
id="connection-type"
selectOptions={selectOptions}
Expand Down

0 comments on commit 0c419f3

Please sign in to comment.