From 406345e257b38b15d0e755c4c79e8bbec25904b1 Mon Sep 17 00:00:00 2001 From: Harsh Vador <58542468+harsh-vador@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:23:10 +0530 Subject: [PATCH] Add & Organise Cypress User spec (#14624) * add user spec * organize user spec * change test description * cover different user roles * change max password length * code refactor * fix failing update admin details test --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> --- .../ui/cypress/common/Entities/UserClass.ts | 151 +++++++ .../ui/cypress/common/Utils/Users.ts | 382 ++++++++++++++++++ .../resources/ui/cypress/common/common.js | 134 ------ .../ui/cypress/constants/constants.js | 70 ++++ .../ui/cypress/constants/service.constants.js | 4 + .../ui/cypress/e2e/Pages/Users.spec.js | 227 ----------- .../ui/cypress/e2e/Pages/Users.spec.ts | 292 +++++++++++++ .../resources/ui/cypress/support/commands.js | 12 +- .../resources/ui/cypress/support/index.ts | 6 +- .../ui/src/constants/regex.constants.ts | 2 +- .../src/pages/UserListPage/UserListPageV1.tsx | 4 +- 11 files changed, 914 insertions(+), 370 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Entities/UserClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Users.ts delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.ts diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/UserClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/UserClass.ts new file mode 100644 index 00000000000..0ee0c622a6e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/UserClass.ts @@ -0,0 +1,151 @@ +/* + * Copyright 2022 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + descriptionBox, + interceptURL, + verifyResponseStatusCode, +} from '../../common/common'; +import { VISIT_SERVICE_PAGE_DETAILS } from '../../constants/service.constants'; +import { + permanentDeleteUser, + restoreUser, + softDeleteUser, +} from '../Utils/Users'; + +class UsersTestClass { + protected name: string; + + public getName() { + return this.name; + } + + visitUserListPage() { + cy.get('[data-testid="app-bar-item-settings"]') + .should('exist') + .should('be.visible') + .click(); + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + cy.get('[data-testid="settings-left-panel"]').contains('Users').click(); + } + + softDeleteUser(name) { + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + verifyResponseStatusCode('@getUsers', 200); + softDeleteUser(name); + } + + restoreSoftDeletedUser(name, editedName) { + restoreUser(name, editedName); + } + + permanentDeleteUser(name) { + permanentDeleteUser(name); + cy.logout(); + } + + checkConsumerPermissions() { + // check Add domain permission + cy.get('[data-testid="add-domain"]').should('not.be.exist'); + cy.get('[data-testid="edit-displayName-button"]').should('not.be.exist'); + // check edit owner permission + cy.get('[data-testid="edit-owner"]').should('not.be.exist'); + // check edit description permission + cy.get('[data-testid="edit-description"]').should('be.exist'); + // check edit tier permission + cy.get('[data-testid="edit-tier"]').should('be.exist'); + // check add tags button + cy.get( + ':nth-child(2) > [data-testid="tags-container"] > [data-testid="entity-tags"] > .m-t-xss > .ant-tag' + ).should('be.exist'); + // check add glossary term button + cy.get( + ':nth-child(3) > [data-testid="glossary-container"] > [data-testid="entity-tags"] > .m-t-xss > .ant-tag' + ).should('be.exist'); + // check edit tier permission + cy.get('[data-testid="manage-button"]').should('not.be.exist'); + cy.get('[data-testid="lineage"] > .ant-space-item').click(); + cy.get('[data-testid="edit-lineage"]').should('be.disabled'); + } + + checkStewardServicesPermissions() { + cy.get('[data-testid="app-bar-item-explore"]').click(); + Object.values(VISIT_SERVICE_PAGE_DETAILS).forEach((service) => { + cy.get('[data-testid="app-bar-item-settings"]').click(); + cy.get(`[data-menu-id*="${service.settingsMenuId}"]`).click(); + cy.get('[data-testid="add-service-button"] > span').should('not.exist'); + }); + cy.get('[data-testid="app-bar-item-explore"]').click(); + cy.get('[data-testid="tables-tab"] > .ant-space').click(); + cy.get( + '.ant-drawer-title > [data-testid="entity-link"] > .ant-typography' + ).click(); + cy.get('[data-testid="edit-tier"]').should('be.visible'); + } + + checkStewardPermissions() { + // check Add domain permission + cy.get('[data-testid="add-domain"]').should('not.be.exist'); + cy.get('[data-testid="edit-displayName-button"]').should('be.exist'); + // check edit owner permission + cy.get('[data-testid="edit-owner"]').should('be.exist'); + // check edit description permission + cy.get('[data-testid="edit-description"]').should('be.exist'); + // check edit tier permission + cy.get('[data-testid="edit-tier"]').should('be.exist'); + // check add tags button + cy.get( + ':nth-child(2) > [data-testid="tags-container"] > [data-testid="entity-tags"] > .m-t-xss > .ant-tag' + ).should('be.exist'); + // check add glossary term button + cy.get( + ':nth-child(3) > [data-testid="glossary-container"] > [data-testid="entity-tags"] > .m-t-xss > .ant-tag' + ).should('be.exist'); + // check edit tier permission + cy.get('[data-testid="manage-button"]').should('be.exist'); + cy.get('[data-testid="lineage"] > .ant-space-item').click(); + cy.get('[data-testid="edit-lineage"]').should('be.enabled'); + } + + restoreAdminDetails() { + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + cy.get('[data-testid="edit-displayName"]').should('be.visible'); + cy.get('[data-testid="edit-displayName"]').click(); + cy.get('[data-testid="displayName"]').clear(); + interceptURL('PATCH', '/api/v1/users/*', 'updateName'); + cy.get('[data-testid="inline-save-btn"]').click(); + cy.get('[data-testid="edit-displayName"]').scrollIntoView(); + verifyResponseStatusCode('@updateName', 200); + + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + cy.get('[data-testid="edit-teams-button"]').click(); + interceptURL('PATCH', '/api/v1/users/*', 'updateTeam'); + cy.get('.ant-select-selection-item-remove > .anticon').click(); + cy.get('[data-testid="inline-save-btn"]').click(); + verifyResponseStatusCode('@updateTeam', 200); + + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + cy.get('[data-testid="edit-description"]').click(); + cy.get(descriptionBox).clear(); + interceptURL('PATCH', '/api/v1/users/*', 'patchDescription'); + cy.get('[data-testid="save"]').should('be.visible').click(); + verifyResponseStatusCode('@patchDescription', 200); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + } +} + +export default UsersTestClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Users.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Users.ts new file mode 100644 index 00000000000..85adf015c8d --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Users.ts @@ -0,0 +1,382 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + customFormatDateTime, + getEpochMillisForFutureDays, +} from '../../../src/utils/date-time/DateTimeUtils'; +import { + descriptionBox, + interceptURL, + toastNotification, + verifyResponseStatusCode, +} from '../common'; + +export const addUser = ({ + name, + email, + password, + role, +}: { + name: string; + email: string; + password: string; + role: string; +}) => { + cy.get('[data-testid="add-user"]').click(); + + cy.get('[data-testid="email"]') + .scrollIntoView() + .should('exist') + .should('be.visible') + .type(email); + cy.get('[data-testid="displayName"]') + .should('exist') + .should('be.visible') + .type(name); + cy.get(descriptionBox) + .should('exist') + .should('be.visible') + .type('Adding user'); + cy.get(':nth-child(2) > .ant-radio > .ant-radio-input').click(); + cy.get('#password').type(password); + cy.get('#confirmPassword').type(password); + cy.get('[data-testid="roles-dropdown"] > .ant-select-selector') + .click() + .type(role); + cy.get('.ant-select-item-option-content').click(); + cy.get('[data-testid="roles-dropdown"] > .ant-select-selector').click(); + interceptURL('POST', ' /api/v1/users', 'add-user'); + cy.get('[data-testid="save-user"]').scrollIntoView().click(); + verifyResponseStatusCode('@add-user', 201); + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + + verifyResponseStatusCode('@getUsers', 200); +}; + +export const visitProfileSection = () => { + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + verifyResponseStatusCode('@getUsers', 200); + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + cy.get('[data-testid="access-token"] > .ant-space-item').click(); +}; +export const softDeleteUser = (username: string) => { + // Search the created user + interceptURL( + 'GET', + '/api/v1/search/query?q=**&from=0&size=*&index=*', + 'searchUser' + ); + cy.get('[data-testid="searchbar"]').type(username); + + verifyResponseStatusCode('@searchUser', 200); + + // Click on delete button + cy.get(`[data-testid="delete-user-btn-${username}"]`); + cy.get(':nth-child(4) > .ant-space > .ant-space-item > .ant-btn').click(); + // Soft deleting the user + cy.get('[data-testid="soft-delete"]').click(); + cy.get('[data-testid="confirmation-text-input"]').type('DELETE'); + + interceptURL( + 'DELETE', + '/api/v1/users/*?hardDelete=false&recursive=false', + 'softdeleteUser' + ); + interceptURL('GET', '/api/v1/users*', 'userDeleted'); + cy.get('[data-testid="confirm-button"]').click(); + verifyResponseStatusCode('@softdeleteUser', 200); + verifyResponseStatusCode('@userDeleted', 200); + + toastNotification('User deleted successfully!'); + + interceptURL('GET', '/api/v1/search/query*', 'searchUser'); + + // Verifying the deleted user + cy.get('[data-testid="searchbar"]').scrollIntoView().clear().type(username); + + verifyResponseStatusCode('@searchUser', 200); +}; + +export const restoreUser = (username: string, editedUserName: string) => { + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + + verifyResponseStatusCode('@getUsers', 200); + // Click on deleted user toggle + cy.get('[data-testid="show-deleted"]').click(); + interceptURL('GET', '/api/v1/search/query*', 'searchUser'); + verifyResponseStatusCode('@getUsers', 200); + + cy.get('[data-testid="searchbar"]').type(username); + + verifyResponseStatusCode('@searchUser', 200); + + cy.get(`[data-testid="restore-user-btn-${username}"]`).click(); + cy.get('.ant-modal-body > p').should( + 'contain', + `Are you sure you want to restore ${editedUserName}?` + ); + interceptURL('PUT', '/api/v1/users', 'restoreUser'); + cy.get('.ant-modal-footer > .ant-btn-primary').click(); + verifyResponseStatusCode('@restoreUser', 200); + toastNotification('User restored successfully'); +}; + +export const permanentDeleteUser = (username: string) => { + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + interceptURL('GET', '/api/v1/users/name/*', 'getUser'); + verifyResponseStatusCode('@getUsers', 200); + verifyResponseStatusCode('@getUser', 200); + interceptURL('GET', '/api/v1/search/query*', 'searchUser'); + cy.get('[data-testid="searchbar"]').type(username); + verifyResponseStatusCode('@searchUser', 200); + cy.get(`[data-testid="delete-user-btn-${username}"]`).click(); + cy.get('[data-testid="hard-delete"]').click(); + cy.get('[data-testid="confirmation-text-input"]').type('DELETE'); + interceptURL( + 'DELETE', + 'api/v1/users/*?hardDelete=true&recursive=false', + 'hardDeleteUser' + ); + cy.get('[data-testid="confirm-button"]') + .should('exist') + .should('be.visible') + .click(); + verifyResponseStatusCode('@hardDeleteUser', 200); + + toastNotification('User deleted successfully!'); + + interceptURL( + 'GET', + 'api/v1/search/query?q=**&from=0&size=15&index=user_search_index', + 'searchUser' + ); + + cy.get('[data-testid="searchbar"]').type(username); + verifyResponseStatusCode('@searchUser', 200); + + cy.get('[data-testid="search-error-placeholder"]').should('be.exist'); +}; +export const visitUserListPage = () => { + cy.get('[data-testid="app-bar-item-settings"]') + .should('exist') + .should('be.visible') + .click(); + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + cy.get('[data-testid="settings-left-panel"]').contains('Users').click(); +}; + +export const generateToken = () => { + cy.get('[data-testid="no-token"]').should('be.visible'); + cy.get('[data-testid="auth-mechanism"] > span').click(); + cy.get('[data-testid="token-expiry"]').should('be.visible').click(); + cy.contains('1 hr').should('exist').should('be.visible').click(); + cy.get('[data-testid="token-expiry"]').should('be.visible'); + cy.get('[data-testid="save-edit"]').should('be.visible').click(); +}; + +export const revokeToken = () => { + cy.get('[data-testid="revoke-button"]').should('be.visible').click(); + cy.get('[data-testid="body-text"]').should( + 'contain', + 'Are you sure you want to revoke access for Personal Access Token?' + ); + cy.get('[data-testid="save-button"]').click(); + cy.get('[data-testid="revoke-button"]').should('not.exist'); +}; + +export const updateExpiration = (expiry: number) => { + cy.get('[data-testid="dropdown-profile"]').click(); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + cy.get('[data-testid="access-token"] > .ant-space-item').click(); + cy.get('[data-testid="no-token"]').should('be.visible'); + cy.get('[data-testid="auth-mechanism"] > span').click(); + + cy.get('[data-testid="token-expiry"]').click(); + cy.contains(`${expiry} days`).click(); + const expiryDate = customFormatDateTime( + getEpochMillisForFutureDays(expiry), + `ccc d'th' MMMM, yyyy` + ); + cy.get('[data-testid="save-edit"]').click(); + cy.get('[data-testid="center-panel"]') + .find('[data-testid="revoke-button"]') + .should('be.visible'); + cy.get('[data-testid="token-expiry"]') + .invoke('text') + .should('contain', `Expires on ${expiryDate}`); + cy.get('[data-testid="token-expiry"]').click(); + revokeToken(); +}; + +export const editDisplayName = (editedUserName: string) => { + cy.get('[data-testid="edit-displayName"]').should('be.visible'); + cy.get('[data-testid="edit-displayName"]').click(); + cy.get('[data-testid="displayName"]').clear(); + cy.get('[data-testid="displayName"]').type(editedUserName); + interceptURL('PATCH', '/api/v1/users/*', 'updateName'); + cy.get('[data-testid="inline-save-btn"]').click(); + cy.get('[data-testid="edit-displayName"]').scrollIntoView(); + cy.get('[data-testid="user-name"]').should('contain', editedUserName); +}; + +export const editDescription = (updatedDescription: string) => { + cy.get('[data-testid="edit-description"]').click(); + cy.get(descriptionBox).clear().type(updatedDescription); + interceptURL('PATCH', '/api/v1/users/*', 'patchDescription'); + cy.get('[data-testid="save"]').should('be.visible').click(); + verifyResponseStatusCode('@patchDescription', 200); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + cy.get( + ':nth-child(2) > :nth-child(1) > [data-testid="viewer-container"] > [data-testid="markdown-parser"] > :nth-child(1) > .toastui-editor-contents > p' + ).should('contain', updatedDescription); +}; + +export const editTeams = (teamName: string) => { + cy.get('[data-testid="edit-teams-button"]').click(); + cy.get('.ant-select-selection-item-remove > .anticon').click(); + cy.get('[data-testid="team-select"]').click(); + cy.get('[data-testid="team-select"]').type(teamName); + interceptURL('PATCH', '/api/v1/users/*', 'updateTeams'); + cy.get('.filter-node > .ant-select-tree-node-content-wrapper').click(); + cy.get('[data-testid="inline-save-btn"]').click({ timeout: 10000 }); + verifyResponseStatusCode('@updateTeams', 200); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + cy.get(`[data-testid="${teamName}"]`).should('exist').and('be.visible'); +}; + +export const handleUserUpdateDetails = ( + editedUserName: string, + updatedDescription: string +) => { + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + // edit displayName + editDisplayName(editedUserName); + // edit description + cy.wait(500); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + editDescription(updatedDescription); + + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); +}; + +export const handleAdminUpdateDetails = ( + editedUserName: string, + updatedDescription: string, + teamName: string, + role?: string +) => { + // edit displayName + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + editDisplayName(editedUserName); + + // edit teams + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + editTeams(teamName); + + // edit description + cy.wait(500); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + editDescription(updatedDescription); + + // edit roles + cy.get(`[data-testid="chip-container"]`).should('contain', role); +}; + +export const updateDetails = ({ + updatedDisplayName, + updatedDescription, + isAdmin, + teamName, + role, +}: { + email: string; + password: string; + updatedDisplayName: string; + updatedDescription: string; + teamName: string; + isAdmin?: boolean; + role?: string; +}) => { + isAdmin + ? handleAdminUpdateDetails( + updatedDisplayName, + updatedDescription, + teamName, + role + ) + : handleUserUpdateDetails(updatedDisplayName, updatedDescription); +}; + +export const resetPassword = (password: string, newPassword: string) => { + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + cy.clickOutside(); + cy.get('[data-testid="change-password-button"]').click(); + cy.get('.ant-modal-wrap').should('be.visible'); + cy.get('[data-testid="input-oldPassword"]').clear().type(password); + cy.get('[data-testid="input-newPassword"]').clear().type(newPassword); + cy.get('[data-testid="input-confirm-newPassword"]').clear().type(newPassword); + interceptURL('PUT', '/api/v1/users/changePassword', 'changePassword'); + cy.get('.ant-modal-footer > .ant-btn-primary') + .contains('Update Password') + .click(); + verifyResponseStatusCode('@changePassword', 200); + toastNotification('Password updated successfully.'); +}; + +export const editRole = (username: string, role: string) => { + interceptURL('GET', '/api/v1/users?*', 'getUsers'); + verifyResponseStatusCode('@getUsers', 200); + + // Search the created user + interceptURL( + 'GET', + '/api/v1/search/query?q=**&from=0&size=*&index=*', + 'searchUser' + ); + cy.get('[data-testid="searchbar"]').type(username); + verifyResponseStatusCode('@searchUser', 200); + cy.get(`[data-testid=${username}]`).click(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get('.ant-collapse-expand-icon > .anticon > svg').click(); + cy.get('[data-testid="edit-roles-button"]').click(); + cy.get('.ant-select-selection-item-remove > .anticon').click(); + cy.get('[data-testid="inline-edit-container"] #select-role') + .click() + .type(role); + cy.get('.ant-select-item-option-content').contains(role).click(); + interceptURL('PATCH', `/api/v1/users/*`, 'updateRole'); + cy.get('[data-testid="inline-save-btn"]').click(); + verifyResponseStatusCode('@updateRole', 200); + cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView(); + cy.get(`[data-testid=chip-container]`).should('contain', role); +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js index 235dfe0a666..08d46bc7ea6 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js @@ -657,140 +657,6 @@ export const addNewTagToEntity = (entityObj, term) => { } }; -export const addUser = (username, email) => { - cy.get('[data-testid="email"]') - .scrollIntoView() - .should('exist') - .should('be.visible') - .type(email); - cy.get('[data-testid="displayName"]') - .should('exist') - .should('be.visible') - .type(username); - cy.get(descriptionBox) - .should('exist') - .should('be.visible') - .type('Adding user'); - interceptURL('GET', ' /api/v1/users/generateRandomPwd', 'generatePassword'); - cy.get('[data-testid="password-generator"]').should('be.visible').click(); - interceptURL('POST', ' /api/v1/users', 'add-user'); - verifyResponseStatusCode('@generatePassword', 200); - cy.get('[data-testid="save-user"]').scrollIntoView().click(); - verifyResponseStatusCode('@add-user', 201); -}; - -export const softDeleteUser = (username, isAdmin) => { - // Search the created user - interceptURL( - 'GET', - '/api/v1/search/query?q=**&from=0&size=*&index=*', - 'searchUser' - ); - cy.get('[data-testid="searchbar"]').type(username); - - verifyResponseStatusCode('@searchUser', 200); - - // Click on delete button - cy.get(`[data-testid="delete-user-btn-${username}"]`).click(); - - // Soft deleting the user - cy.get('[data-testid="soft-delete"]').click(); - cy.get('[data-testid="confirmation-text-input"]').type('DELETE'); - - interceptURL( - 'DELETE', - '/api/v1/users/*?hardDelete=false&recursive=false', - 'softdeleteUser' - ); - interceptURL('GET', '/api/v1/users*', 'userDeleted'); - cy.get('[data-testid="confirm-button"]').click(); - verifyResponseStatusCode('@softdeleteUser', 200); - verifyResponseStatusCode('@userDeleted', 200); - - toastNotification('User deleted successfully!'); - - interceptURL('GET', '/api/v1/search/query*', 'searchUser'); - - // Verifying the deleted user - cy.get('[data-testid="searchbar"]').scrollIntoView().clear().type(username); - - verifyResponseStatusCode('@searchUser', 200); - cy.get('[data-testid="search-error-placeholder"]').should('be.visible'); -}; - -export const restoreUser = (username) => { - // Click on deleted user toggle - interceptURL('GET', '/api/v1/users*', 'deletedUser'); - cy.get('[data-testid="show-deleted"]').click(); - verifyResponseStatusCode('@deletedUser', 200); - interceptURL( - 'GET', - '/api/v1/search/query?q=**&from=0&size=*&index=*', - 'searchUser' - ); - cy.get('[data-testid="searchbar"]').type(username); - - verifyResponseStatusCode('@searchUser', 200); - - cy.get(`[data-testid="restore-user-btn-${username}"]`).click(); - cy.get('.ant-modal-body > p').should( - 'contain', - `Are you sure you want to restore ${username}?` - ); - interceptURL('PUT', '/api/v1/users', 'restoreUser'); - cy.get('.ant-modal-footer > .ant-btn-primary').click(); - verifyResponseStatusCode('@restoreUser', 200); - toastNotification('User restored successfully'); - - // Verifying the restored user - cy.get('[data-testid="show-deleted"]').click(); - - interceptURL('GET', '/api/v1/search/query*', 'searchUser'); - cy.get('[data-testid="searchbar"]').type(username); - verifyResponseStatusCode('@searchUser', 200); - cy.get(`[data-testid=${username}]`).should('exist'); -}; - -export const deleteSoftDeletedUser = (username) => { - interceptURL('GET', '/api/v1/users?*', 'getUsers'); - - cy.get('.ant-switch-handle').should('exist').should('be.visible').click(); - - verifyResponseStatusCode('@getUsers', 200); - - cy.get(`[data-testid="delete-user-btn-${username}"]`) - .should('exist') - .should('be.visible') - .click(); - cy.get('[data-testid="confirmation-text-input"]').type('DELETE'); - interceptURL( - 'DELETE', - 'api/v1/users/*?hardDelete=true&recursive=false', - 'hardDeleteUser' - ); - cy.get('[data-testid="confirm-button"]') - .should('exist') - .should('be.visible') - .click(); - verifyResponseStatusCode('@hardDeleteUser', 200); - - toastNotification('User deleted successfully!'); - - interceptURL( - 'GET', - 'api/v1/search/query?q=**&from=0&size=15&index=user_search_index', - 'searchUser' - ); - - cy.get('[data-testid="searchbar"]') - .should('exist') - .should('be.visible') - .type(username); - verifyResponseStatusCode('@searchUser', 200); - - cy.get('[data-testid="search-error-placeholder"]').should('be.visible'); -}; - export const toastNotification = (msg, closeToast = true) => { cy.get('.Toastify__toast-body').should('contain.text', msg); cy.wait(200); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js index 3b638f72f62..36faef86787 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js @@ -740,3 +740,73 @@ export const DOMAIN_3 = { }, ], }; +export const GLOBAL_SETTING_PERMISSIONS = { + metadata: { + testid: '[data-menu-id*="metadata"]', + }, + customAttributesTable: { + testid: '[data-menu-id*="tables"]', + }, + customAttributesTopics: { + testid: '[data-menu-id*="topics"]', + }, + customAttributesDashboards: { + testid: '[data-menu-id*="customAttributes.dashboards"]', + }, + customAttributesPipelines: { + testid: '[data-menu-id*="customAttributes.pipelines"]', + }, + customAttributesMlModels: { + testid: '[data-menu-id*="customAttributes.mlModels"]', + }, + bots: { + testid: '[data-menu-id*="bots"]', + }, +}; +export const ID = { + teams: { + testid: '[data-menu-id*="teams"]', + button: 'add-team', + api: '/api/v1/teams/name/Organization?*', + }, + users: { + testid: '[data-menu-id*="users"]', + button: 'add-user', + api: '/api/v1/users?*', + }, + admins: { + testid: '[data-menu-id*="admins"]', + button: 'add-user', + api: '/api/v1/users?*', + }, + databases: { + testid: '[data-menu-id*="databases"]', + button: 'add-service-button', + api: '/api/v1/services/databaseServices?*', + }, + messaging: { + testid: '[data-menu-id*="messaging"]', + button: 'add-service-button', + api: '/api/v1/services/messagingServices?*', + }, + dashboard: { + testid: '[data-menu-id*="services.dashboards"]', + button: 'add-service-button', + api: '/api/v1/services/dashboardServices?*', + }, + pipelines: { + testid: '[data-menu-id*="services.pipelines"]', + button: 'add-service-button', + api: '/api/v1/services/pipelineServices?*', + }, + mlmodels: { + testid: '[data-menu-id*="services.mlmodels"]', + button: 'add-service-button', + api: '/api/v1/services/mlmodelServices?*', + }, + storage: { + testid: '[data-menu-id*="services.storages"]', + button: 'add-service-button', + api: '/api/v1/services/storageServices?*', + }, +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/service.constants.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/service.constants.js index a5ec97989c2..9aec7a6c4a9 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/service.constants.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/service.constants.js @@ -69,4 +69,8 @@ export const VISIT_SERVICE_PAGE_DETAILS = { settingsMenuId: 'services.search', serviceCategory: SERVICE_CATEGORIES.SEARCH_SERVICES, }, + [SERVICE_TYPE.Metadata]: { + settingsMenuId: 'services.metadata', + serviceCategory: SERVICE_CATEGORIES.METADATA_SERVICES, + }, }; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js deleted file mode 100644 index d5cbb08c2dd..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2022 Collate. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// eslint-disable-next-line spaced-comment -/// -import { - customFormatDateTime, - getEpochMillisForFutureDays, -} from '../../../src/utils/date-time/DateTimeUtils'; -import { - addUser, - deleteSoftDeletedUser, - interceptURL, - restoreUser, - softDeleteUser, - uuid, - verifyResponseStatusCode, -} from '../../common/common'; - -const userName = `Usercttest${uuid()}`; -const userEmail = `${userName}@gmail.com`; - -const adminName = `Admincttest${uuid()}`; -const adminEmail = `${adminName}@gmail.com`; - -const searchBotText = 'bot'; - -const expirationTime = { - oneday: '1', - sevendays: '7', - onemonth: '30', - twomonths: '60', - threemonths: '90', -}; - -const revokeToken = () => { - // Click on revoke button - cy.get('[data-testid="revoke-button"]').should('be.visible').click(); - // Verify the revoke text - cy.get('[data-testid="body-text"]').should( - 'contain', - 'Are you sure you want to revoke access for Personal Access Token?' - ); - // Click on confirm button - cy.get('[data-testid="save-button"]').click(); - // Verify the revoke is successful - cy.get('[data-testid="revoke-button"]').should('not.exist'); -}; - -describe('Users flow should work properly', () => { - beforeEach(() => { - cy.login(); - - cy.get('[data-testid="app-bar-item-settings"]') - .should('exist') - .should('be.visible') - .click(); - interceptURL('GET', '/api/v1/users?*', 'getUsers'); - cy.get('[data-testid="settings-left-panel"]').contains('Users').click(); - }); - - it('Add new User', () => { - // Clicking on Add user button - cy.get('[data-testid="add-user"]').click(); - - addUser(userName, userEmail); - verifyResponseStatusCode('@getUsers', 200); - }); - - it('Soft delete user', () => { - softDeleteUser(userName); - }); - - it('Restore soft deleted user', () => { - restoreUser(userName); - }); - - it('Permanently Delete Soft Deleted User', () => { - softDeleteUser(userName); - deleteSoftDeletedUser(userName); - }); - - it('Search for bot user', () => { - interceptURL( - 'GET', - `/api/v1/search/query?q=*${searchBotText}***isBot:false&from=0&size=25&index=user_search_index`, - 'searchUser' - ); - cy.get('[data-testid="searchbar"]') - .should('exist') - .should('be.visible') - .type(searchBotText); - - verifyResponseStatusCode('@searchUser', 200); - }); -}); - -describe('Admin flow should work properly', () => { - beforeEach(() => { - cy.login(); - - cy.get('[data-testid="app-bar-item-settings"]') - .should('exist') - .should('be.visible') - .click(); - interceptURL('GET', '/api/v1/users?*isAdmin=true*', 'getAdmins'); - cy.get('.ant-menu-title-content') - .contains('Admins') - .should('exist') - .should('be.visible') - .click(); - }); - - it('Add admin user', () => { - // Clicking on add user button - cy.get('[data-testid="add-user"]').click(); - - // Setting the user to admin before adding user - cy.get('[data-testid="admin"]') - .scrollIntoView() - .should('exist') - .should('be.visible') - .click(); - - addUser(adminName, adminEmail); - verifyResponseStatusCode('@getAdmins', 200); - - // Validate if user is added in the User tab - interceptURL( - 'GET', - '/api/v1/search/query?q=**&from=0&size=*&index=*', - 'searchUser' - ); - cy.get('[data-testid="searchbar"]') - .should('exist') - .should('be.visible') - .type(adminName); - verifyResponseStatusCode('@searchUser', 200); - cy.get('.ant-table-tbody ').should('contain', adminName); - }); - - it('Soft delete admin', () => { - softDeleteUser(adminName, true); - }); - - it('Restore soft deleted admin', () => { - restoreUser(adminName); - }); - - it('Permanently Delete Soft Deleted admin', () => { - softDeleteUser(adminName, true); - deleteSoftDeletedUser(adminName); - }); - - describe('Personal Access Token flow should work properly', () => { - beforeEach(() => { - cy.login(); - }); - - it('Token should be generated and revoked', function () { - // Enter profile section - cy.get('.username').click(); - cy.get('[data-testid="user-name"] > .ant-typography').click(); - cy.get('[data-testid="access-token"] > .ant-space-item').click(); - cy.get('[data-testid="access-token"] > .ant-space-item').should( - 'be.visible' - ); - - // generate token - cy.get('[data-testid="no-token"]').should('be.visible'); - cy.get('[data-testid="auth-mechanism"] > span').click(); - cy.get('[data-testid="token-expiry"]').should('be.visible').click(); - cy.contains('1 hr').should('exist').should('be.visible').click(); - cy.get('[data-testid="token-expiry"]').should('be.visible'); - cy.get('[data-testid="save-edit"]').should('be.visible').click(); - - // revoke token - cy.get('[data-testid="revoke-button"] > span').should('be.visible'); - cy.get('[data-testid="revoke-button"] > span').click(); - cy.get('[data-testid="save-button"] > span').click(); - cy.get(':nth-child(1) > .ant-row > .ant-form-item-label > label').should( - 'be.visible' - ); - }); - - Object.values(expirationTime).forEach((expiry) => { - it(`Update token expiration for ${expiry} days`, () => { - cy.get('.username').click(); - cy.get('[data-testid="user-name"] > .ant-typography').click(); - cy.get('[data-testid="access-token"] > .ant-space-item').click(); - cy.get('[data-testid="access-token"] > .ant-space-item').should( - 'be.visible' - ); - cy.get('[data-testid="no-token"]').should('be.visible'); - cy.get('[data-testid="auth-mechanism"] > span').click(); - - cy.get('[data-testid="token-expiry"]').click(); - // Select the expiration period - cy.contains(`${expiry} days`).click(); - // Save the updated date - const expiryDate = customFormatDateTime( - getEpochMillisForFutureDays(expiry), - `ccc d'th' MMMM, yyyy` - ); - cy.get('[data-testid="save-edit"]').click(); - cy.get('[data-testid="center-panel"]') - .find('[data-testid="revoke-button"]') - .should('be.visible'); - // Verify the expiry time - cy.get('[data-testid="token-expiry"]') - .invoke('text') - .should('contain', `Expires on ${expiryDate}`); - cy.get('[data-testid="token-expiry"]').click(); - revokeToken(); - }); - }); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.ts new file mode 100644 index 00000000000..e6313e514e3 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.ts @@ -0,0 +1,292 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// eslint-disable-next-line spaced-comment +import UsersTestClass from '../../common/Entities/UserClass'; +import { visitEntityDetailsPage } from '../../common/Utils/Entity'; +import { addOwner, removeOwner } from '../../common/Utils/Owner'; +import { + addUser, + editRole, + generateToken, + resetPassword, + revokeToken, + updateDetails, + updateExpiration, + visitUserListPage, +} from '../../common/Utils/Users'; +import { interceptURL, verifyResponseStatusCode } from '../../common/common'; +import { EntityType } from '../../constants/Entity.interface'; + +import { + BASE_URL, + DELETE_ENTITY, + GLOBAL_SETTING_PERMISSIONS, + ID, + uuid, +} from '../../constants/constants'; +import { NAVBAR_DETAILS } from '../../constants/redirections.constants'; +const entity = new UsersTestClass(); +const expirationTime = { + oneday: '1', + sevendays: '7', + onemonth: '30', + twomonths: '60', + threemonths: '90', +}; +const name = `Usercttest${uuid()}`; +const glossary = NAVBAR_DETAILS.glossary; +const tag = NAVBAR_DETAILS.tags; +const ownerName = 'Aaron Warren'; +const user = { + name: name, + email: `${name}@gmail.com`, + password: `User@${uuid()}`, + updatedDisplayName: `Edited${uuid()}`, + newPassword: `NewUser@${uuid()}`, + teamName: 'Applications', + updatedDescription: 'This is updated description', + newStewardPassword: `StewUser@${uuid()}`, +}; + +describe('User with different Roles', () => { + it('Update own admin details', () => { + cy.login(); + updateDetails({ + ...user, + isAdmin: true, + role: 'Admin', + }); + }); + + it('Create Data Consumer User', () => { + cy.login(); + visitUserListPage(); + addUser({ ...user, role: 'Data Consumer' }); + cy.logout(); + }); + + it('Reset Data Consumer Password', () => { + cy.login(user.email, user.password); + + resetPassword(user.password, user.newPassword); + cy.logout(); + + cy.login(user.email, user.newPassword); + }); + + it('Token generation & revocation', () => { + cy.login(user.email, user.newPassword); + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography', { + timeout: 10000, + }).click(); + cy.get('[data-testid="access-token"]').click(); + generateToken(); + revokeToken(); + }); + + it(`Update token expiration`, () => { + cy.login(user.email, user.newPassword); + visitUserListPage(); + Object.values(expirationTime).forEach((expiry) => { + updateExpiration(expiry); + }); + }); + + it('Data Consumer user should have only view permission for glossary and tags', () => { + Cypress.session.clearAllSavedSessions(); + cy.storeSession(user.email, user.newPassword); + cy.goToHomePage(); + cy.url().should('eq', `${BASE_URL}/my-data`); + + // Check CRUD for Glossary + cy.get(glossary.testid) + .should('be.visible') + .click({ animationDistanceThreshold: 10 }); + if (glossary.subMenu) { + cy.get(glossary.subMenu).should('be.visible').click({ force: true }); + } + cy.clickOutside(); + + cy.clickOnLogo(); + + // Check CRUD for Tags + cy.get(tag.testid) + .should('be.visible') + .click({ animationDistanceThreshold: 10 }); + if (tag.subMenu) { + cy.get(tag.subMenu).should('be.visible').click({ force: true }); + } + cy.get('body').click(); + cy.wait(200); + cy.get('[data-testid="add-new-tag-button"]').should('not.exist'); + + cy.get('[data-testid="manage-button"]').should('not.exist'); + }); + + it('Data Consumer operations for settings page', () => { + cy.storeSession(user.email, user.newPassword); + cy.goToHomePage(); + cy.url().should('eq', `${BASE_URL}/my-data`); + // Navigate to settings + cy.get(NAVBAR_DETAILS.settings.testid).should('be.visible').click(); + Object.values(ID).forEach((id) => { + if (id?.api) { + interceptURL('GET', id.api, 'getTabDetails'); + } + cy.get(id.testid).should('be.visible').click(); + if (id?.api) { + verifyResponseStatusCode('@getTabDetails', 200); + } + cy.get(`[data-testid="${id.button}"]`).should('not.be.exist'); + }); + + Object.values(GLOBAL_SETTING_PERMISSIONS).forEach((id) => { + if (id.testid === '[data-menu-id*="metadata"]') { + cy.get(id.testid).should('be.visible').click(); + } else { + cy.get(id.testid).should('not.be.exist'); + } + }); + }); + + it('Data Consumer permissions for table details page', () => { + cy.login(); + visitEntityDetailsPage({ + term: DELETE_ENTITY.table.term, + serviceName: DELETE_ENTITY.table.serviceName, + entity: EntityType.Table, + }); + addOwner(ownerName); + cy.logout(); + cy.login(user.email, user.newPassword); + visitEntityDetailsPage({ + term: DELETE_ENTITY.table.term, + serviceName: DELETE_ENTITY.table.serviceName, + entity: EntityType.Table, + }); + entity.checkConsumerPermissions(); + }); + + it('Update Data Consumer details', () => { + cy.login(user.email, user.newPassword); + updateDetails({ ...user, isAdmin: false }); + }); + + it('Update Data Steward details', () => { + // change role from consumer to steward + cy.login(); + visitUserListPage(); + editRole(user.name, 'Data Steward'); + cy.logout(); + // login to steward user + cy.login(user.email, user.newPassword); + updateDetails({ ...user, isAdmin: false }); + cy.logout(); + }); + + it('Reset Data Steward Password', () => { + cy.login(user.email, user.newPassword); + resetPassword(user.newPassword, user.newStewardPassword); + cy.logout(); + cy.login(user.email, user.newStewardPassword); + }); + + it('Token generation & revocation for Data Steward', () => { + cy.login(user.email, user.newStewardPassword); + visitUserListPage(); + cy.get('[data-testid="dropdown-profile"]').click({ force: true }); + cy.get('[data-testid="user-name"] > .ant-typography').click({ + force: true, + }); + cy.get('[data-testid="access-token"] > .ant-space-item').click(); + generateToken(); + revokeToken(); + }); + + it(`Update token expiration for Data Steward`, () => { + cy.login(user.email, user.newStewardPassword); + visitUserListPage(); + Object.values(expirationTime).forEach((expiry) => { + updateExpiration(expiry); + }); + }); + + it('Data Steward operations for settings page', () => { + cy.login(user.email, user.newStewardPassword); + cy.url().should('eq', `${BASE_URL}/my-data`); + // Navigate to settings + cy.get(NAVBAR_DETAILS.settings.testid).should('be.visible').click(); + Object.values(ID).forEach((id) => { + if (id?.api) { + interceptURL('GET', id.api, 'getTabDetails'); + } + cy.get(id.testid).should('be.visible').click(); + if (id?.api) { + verifyResponseStatusCode('@getTabDetails', 200); + } + cy.get(`[data-testid="${id.button}"]`).should('not.be.exist'); + }); + + Object.values(GLOBAL_SETTING_PERMISSIONS).forEach((id) => { + if (id.testid === '[data-menu-id*="metadata"]') { + cy.get(id.testid).should('be.visible').click(); + } else { + cy.get(id.testid).should('not.be.exist'); + } + }); + }); + + it('Check Data Steward permissions', () => { + cy.login(user.email, user.newStewardPassword); + entity.checkStewardServicesPermissions(); + cy.goToHomePage(); + visitEntityDetailsPage({ + term: DELETE_ENTITY.table.term, + serviceName: DELETE_ENTITY.table.serviceName, + entity: EntityType.Table, + }); + entity.checkStewardPermissions(); + cy.logout(); + }); + + it('Admin Soft delete user', () => { + cy.login(); + visitUserListPage(); + entity.softDeleteUser(user.name); + }); + + it('Admin Restore soft deleted user', () => { + cy.login(); + visitUserListPage(); + entity.restoreSoftDeletedUser(user.name, user.updatedDisplayName); + }); + + it('Admin Permanent Delete User', () => { + cy.login(); + visitUserListPage(); + entity.permanentDeleteUser(user.name); + }); + + it('Restore Admin Details', () => { + cy.login(); + entity.restoreAdminDetails(); + cy.goToHomePage(); + visitEntityDetailsPage({ + term: DELETE_ENTITY.table.term, + serviceName: DELETE_ENTITY.table.serviceName, + entity: EntityType.Table, + }); + removeOwner(ownerName); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js b/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js index 1c86b80c631..40311feb3a1 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js @@ -130,10 +130,13 @@ Cypress.Commands.add('storeSession', (username, password) => { }); }); -Cypress.Commands.add('login', () => { - cy.storeSession(LOGIN.username, LOGIN.password); - cy.goToHomePage(); -}); +Cypress.Commands.add( + 'login', + (username = LOGIN.username, password = LOGIN.password) => { + cy.storeSession(username, password); + cy.goToHomePage(); + } +); Cypress.Commands.add('clickOutside', function () { return cy.get('body').click(0, 0); // 0,0 here are the x and y coordinates @@ -149,4 +152,5 @@ Cypress.Commands.add('logout', () => { verifyResponseStatusCode('@logoutUser', 200); cy.url().should('eq', `${BASE_URL}/signin`); + Cypress.session.clearAllSavedSessions(); }); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/support/index.ts b/openmetadata-ui/src/main/resources/ui/cypress/support/index.ts index 1fcb5f8a9af..0b7157eb2f4 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/support/index.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/support/index.ts @@ -20,7 +20,11 @@ declare global { * Custom command to select DOM element by data-cy attribute. * @example cy.login() */ - login(): void; + login(email?: string, password?: string): void; + logout(): void; + goToHomePage(doNotNavigate: boolean): void; + clickOnLogo(): void; + clickOutside(): void; } } } diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/regex.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/regex.constants.ts index f1e8f36be76..8ad1d63fe45 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/regex.constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/regex.constants.ts @@ -32,7 +32,7 @@ export const delimiterRegex = /[\\[\]\\()\\;\\,\\|\\{}\\``\\/\\<>\\^]/g; export const nameWithSpace = /\s/g; export const passwordRegex = - /^(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[^\w\d\s:])([^\s]){8,16}$/g; + /^(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[^\w\d\s:])([^\s]){8,56}$/g; export const allowedNameRegEx = /[`!@#$%^&*()+=[\]{};:"\\|,.<>/?~]/; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx index 0168a6e11d5..11a925b94d4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx @@ -324,9 +324,7 @@ const UserListPageV1 = () => { disabled={!isAdminUser} icon={