From cfae32706fa54056b91ef459a94614ac62ce4227 Mon Sep 17 00:00:00 2001 From: pnaik1 Date: Fri, 19 Apr 2024 15:04:55 +0530 Subject: [PATCH] added user management --- frontend/src/__mocks__/mockGroupConfig.ts | 28 ++++++++ .../cypress/e2e/projects/projectDetails.cy.ts | 6 +- .../e2e/userManagement/userManagement.cy.ts | 51 ++++++++++++++ .../cypress/cypress/pages/userManagement.ts | 68 +++++++++++++++++++ .../cypress/cypress/support/commands/odh.ts | 11 +++ frontend/src/components/MultiSelection.tsx | 3 +- frontend/src/components/SettingSection.tsx | 4 +- .../src/pages/groupSettings/GroupSettings.tsx | 9 ++- 8 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 frontend/src/__mocks__/mockGroupConfig.ts create mode 100644 frontend/src/__tests__/cypress/cypress/e2e/userManagement/userManagement.cy.ts create mode 100644 frontend/src/__tests__/cypress/cypress/pages/userManagement.ts diff --git a/frontend/src/__mocks__/mockGroupConfig.ts b/frontend/src/__mocks__/mockGroupConfig.ts new file mode 100644 index 0000000000..2ac16da0dc --- /dev/null +++ b/frontend/src/__mocks__/mockGroupConfig.ts @@ -0,0 +1,28 @@ +import { GroupsConfig } from '~/pages/groupSettings/groupTypes'; + +export const mockGroupSettings = (): GroupsConfig => ({ + adminGroups: [ + { + id: 0, + name: 'odh-admins', + enabled: true, + }, + { + id: 1, + name: 'odh-admins-1', + enabled: false, + }, + ], + allowedGroups: [ + { + id: 0, + name: 'odh-admins', + enabled: false, + }, + { + id: 1, + name: 'system:authenticated', + enabled: false, + }, + ], +}); diff --git a/frontend/src/__tests__/cypress/cypress/e2e/projects/projectDetails.cy.ts b/frontend/src/__tests__/cypress/cypress/e2e/projects/projectDetails.cy.ts index ec9ab2e2d8..c2c55a9d7d 100644 --- a/frontend/src/__tests__/cypress/cypress/e2e/projects/projectDetails.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/e2e/projects/projectDetails.cy.ts @@ -315,9 +315,11 @@ describe('Project Details', () => { }); projectDetails.visitSection('test-project', 'workbenches'); const notebookRow = projectDetails.getNotebookRow('test-notebook'); - notebookRow.findOutdatedElyraInfo().should('not.exist'); - projectDetails.findElyraInvalidVersionAlert().should('not.exist'); + notebookRow.findOutdatedElyraInfo().should('be.visible'); + projectDetails.findElyraInvalidVersionAlert().should('be.visible'); + projectDetails.findUnsupportedPipelineVersionAlert().should('not.exist'); }); + it('Notebook with updated Elyra image and no pipeline server', () => { initIntercepts({ imageStreamPythonDependencies: '[{"name":"odh-elyra","version":"3.16"}]', diff --git a/frontend/src/__tests__/cypress/cypress/e2e/userManagement/userManagement.cy.ts b/frontend/src/__tests__/cypress/cypress/e2e/userManagement/userManagement.cy.ts new file mode 100644 index 0000000000..c155667b16 --- /dev/null +++ b/frontend/src/__tests__/cypress/cypress/e2e/userManagement/userManagement.cy.ts @@ -0,0 +1,51 @@ +import { mockGroupSettings } from '~/__mocks__/mockGroupConfig'; +import { userManagement } from '~/__tests__/cypress/cypress/pages/userManagement'; + +describe('User Management', () => { + beforeEach(() => { + cy.interceptOdh('GET /api/groups-config', mockGroupSettings()); + cy.interceptOdh('PUT /api/groups-config', mockGroupSettings()).as('saveGroupSetting'); + userManagement.visit(); + }); + + it('Administrator group setting', () => { + const administratorGroupSection = userManagement.getAdministratorGroupSection(); + administratorGroupSection.shouldHaveAdministratorGroupInfo(); + administratorGroupSection.clearMultiChipItem(); + administratorGroupSection.selectMultiGroup('odh-admins'); + administratorGroupSection.findMultiSelectGroupInput().type('odh-admin'); + administratorGroupSection.findMultiGroupOptions('odh-admins-1').click(); + administratorGroupSection.findChipItem().should('contain', 'odh-admins'); + administratorGroupSection.removeChipItem('odh-admins'); + administratorGroupSection.findChipItem().should('not.contain', /^odh-admins$/); + administratorGroupSection.removeChipItem('odh-admins-1'); + administratorGroupSection.findErrorText().should('exist'); + administratorGroupSection.findMultiGroupOptions('odh-admins').click(); + administratorGroupSection.findErrorText().should('not.exist'); + userManagement.findSubmitButton().should('be.disabled'); + }); + + it('User group setting', () => { + const userGroupSection = userManagement.getUserGroupSection(); + userManagement.findSubmitButton().should('be.disabled'); + userGroupSection.findErrorText().should('exist'); + userGroupSection.selectMultiGroup('odh-admins'); + userGroupSection.findMultiGroupOptions('system:authenticated').click(); + userGroupSection.findChipItem().should('contain', 'odh-admins'); + userGroupSection.removeChipItem('odh-admins'); + userManagement.findSubmitButton().should('be.enabled'); + userManagement.findSubmitButton().click(); + cy.wait('@saveGroupSetting').then((interception) => { + expect(interception.request.body).to.eql({ + adminGroups: [ + { id: 0, name: 'odh-admins', enabled: true }, + { id: 1, name: 'odh-admins-1', enabled: false }, + ], + allowedGroups: [ + { id: 0, name: 'odh-admins', enabled: false }, + { id: 1, name: 'system:authenticated', enabled: true }, + ], + }); + }); + }); +}); diff --git a/frontend/src/__tests__/cypress/cypress/pages/userManagement.ts b/frontend/src/__tests__/cypress/cypress/pages/userManagement.ts new file mode 100644 index 0000000000..904f066b75 --- /dev/null +++ b/frontend/src/__tests__/cypress/cypress/pages/userManagement.ts @@ -0,0 +1,68 @@ +import { Contextual } from './components/Contextual'; + +class GroupSettingSection extends Contextual { + shouldHaveAdministratorGroupInfo() { + this.find().findByTestId('data-science-administrator-info'); + return this; + } + + clearMultiChipItem() { + this.find().findByRole('button', { name: 'Clear all' }).click(); + } + + findMultiSelectGroupInput() { + return this.find().find('input'); + } + + findMultiGroupOptions(name: string) { + return this.find().findByTestId('multi-group-selection').findByRole('option', { name }); + } + + private findChipGroup() { + return this.find().findByRole('list', { name: 'Chip group category' }); + } + + findChipItem() { + return this.findChipGroup().find('li'); + } + + removeChipItem(name: string) { + this.findChipGroup() + .findByRole('button', { name: `Remove ${name}` }) + .click(); + } + + findErrorText() { + return this.find().findByTestId('group-selection-error-text'); + } + + selectMultiGroup(name: string) { + this.find().findByRole('button', { name: 'Options menu' }).click(); + this.findMultiGroupOptions(name).click(); + } +} +class UserManagement { + visit() { + cy.visit('/groupSettings'); + this.wait(); + } + + private wait() { + cy.findByTestId('app-page-title').should('have.text', 'User management'); + cy.testA11y(); + } + + findSubmitButton() { + return cy.findByTestId('save-button'); + } + + getAdministratorGroupSection() { + return new GroupSettingSection(() => cy.findByTestId('data-science-administrator-groups')); + } + + getUserGroupSection() { + return new GroupSettingSection(() => cy.findByTestId('data-science-user-groups')); + } +} + +export const userManagement = new UserManagement(); diff --git a/frontend/src/__tests__/cypress/cypress/support/commands/odh.ts b/frontend/src/__tests__/cypress/cypress/support/commands/odh.ts index f7fe221ca5..09c9c23879 100644 --- a/frontend/src/__tests__/cypress/cypress/support/commands/odh.ts +++ b/frontend/src/__tests__/cypress/cypress/support/commands/odh.ts @@ -10,6 +10,7 @@ import type { ServingRuntimeKind, TemplateKind, } from '~/k8sTypes'; +import { GroupsConfig } from '~/pages/groupSettings/groupTypes'; import type { StatusResponse } from '~/redux/types'; import type { BYONImage, @@ -57,6 +58,16 @@ declare global { response?: OdhResponse, ): Cypress.Chainable; + interceptOdh( + type: 'GET /api/groups-config', + response?: OdhResponse, + ): Cypress.Chainable; + + interceptOdh( + type: 'PUT /api/groups-config', + response?: OdhResponse, + ): Cypress.Chainable; + interceptOdh( type: 'GET /api/components', options: { diff --git a/frontend/src/components/MultiSelection.tsx b/frontend/src/components/MultiSelection.tsx index c3bcbe120c..123c38652e 100644 --- a/frontend/src/components/MultiSelection.tsx +++ b/frontend/src/components/MultiSelection.tsx @@ -26,6 +26,7 @@ export const MultiSelection: React.FC = ({ value, setValue, return ( <> {noSelectedItems && ( - + One or more group must be selected diff --git a/frontend/src/components/SettingSection.tsx b/frontend/src/components/SettingSection.tsx index c608576dcb..14de874e9c 100644 --- a/frontend/src/components/SettingSection.tsx +++ b/frontend/src/components/SettingSection.tsx @@ -4,6 +4,7 @@ import { Card, CardBody, CardFooter, CardTitle, Stack, StackItem } from '@patter type SettingSectionProps = { children: React.ReactNode; title: string; + testId?: string; description?: React.ReactNode; footer?: React.ReactNode; }; @@ -12,9 +13,10 @@ const SettingSection: React.FC = ({ title, children, footer, + testId, description, }) => ( - + {title} diff --git a/frontend/src/pages/groupSettings/GroupSettings.tsx b/frontend/src/pages/groupSettings/GroupSettings.tsx index 9e6b2f97ee..362d4fa61b 100644 --- a/frontend/src/pages/groupSettings/GroupSettings.tsx +++ b/frontend/src/pages/groupSettings/GroupSettings.tsx @@ -64,9 +64,11 @@ const GroupSettings: React.FC = () => { { - + {