diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java b/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java
index 2b4711d8b75a..1329be62b5b9 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/security/auth/BasicAuthenticator.java
@@ -16,7 +16,6 @@
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static javax.ws.rs.core.Response.Status.NOT_IMPLEMENTED;
-import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;
import static org.openmetadata.schema.api.teams.CreateUser.CreatePasswordType.ADMIN_CREATE;
import static org.openmetadata.schema.auth.ChangePasswordRequest.RequestType.SELF;
import static org.openmetadata.schema.auth.ChangePasswordRequest.RequestType.USER;
@@ -271,7 +270,7 @@ public void changeUserPwdWithOldPwd(UriInfo uriInfo, String userName, ChangePass
if (request.getRequestType() == SELF
&& !BCrypt.verifyer().verify(request.getOldPassword().toCharArray(), storedHashPassword).verified) {
- throw new CustomExceptionMessage(UNAUTHORIZED, "Old Password is not correct");
+ throw new CustomExceptionMessage(BAD_REQUEST, "Old Password is not correct");
}
storedBasicAuthMechanism.setPassword(newHashedPassword);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.test.tsx
new file mode 100644
index 000000000000..99dc6a9ce96d
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.test.tsx
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2023 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 { act, fireEvent, render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import React from 'react';
+import ChangePasswordForm from './ChangePasswordForm';
+
+const mockSave = jest.fn();
+
+const mockCancel = jest.fn();
+
+const MOCK_PROPS = {
+ visible: true,
+ onCancel: mockCancel,
+ isLoggedInUser: true,
+ isLoading: false,
+ onSave: mockSave,
+};
+
+describe('ChangePasswordForm', () => {
+ it('should render correctly', async () => {
+ render();
+ const modal = await screen.findByTestId('modal-container');
+
+ expect(modal).toBeInTheDocument();
+ });
+
+ it('should handle form submission correctly for logged in user', async () => {
+ render();
+ const cancelButton = await screen.findByText('Cancel');
+ const submitButton = await screen.findByText('label.update-entity');
+
+ expect(cancelButton).toBeInTheDocument();
+ expect(submitButton).toBeInTheDocument();
+
+ userEvent.type(
+ await screen.findByTestId('input-oldPassword'),
+ 'oldPassword'
+ );
+
+ userEvent.type(await screen.findByTestId('input-newPassword'), 'Test@123');
+ userEvent.type(
+ await screen.findByTestId('input-confirm-newPassword'),
+ 'Test@123'
+ );
+
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+
+ expect(mockSave).toHaveBeenCalledTimes(1);
+ });
+
+ it('handles form submission correctly for admin', async () => {
+ render(
+
+ );
+
+ const cancelButton = await screen.findByText('Cancel');
+ const submitButton = await screen.findByText('label.update-entity');
+
+ expect(cancelButton).toBeInTheDocument();
+ expect(submitButton).toBeInTheDocument();
+
+ userEvent.type(await screen.findByTestId('input-newPassword'), 'Test@123');
+ userEvent.type(
+ await screen.findByTestId('input-confirm-newPassword'),
+ 'Test@123'
+ );
+
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+
+ expect(mockSave).toHaveBeenCalledWith({
+ newPassword: 'Test@123',
+ confirmPassword: 'Test@123',
+ });
+ });
+
+ it('should invoke onCancel when Cancel button is clicked', async () => {
+ render(
+
+ );
+
+ const cancelButton = await screen.findByText('Cancel');
+ const submitButton = await screen.findByText('label.update-entity');
+
+ expect(cancelButton).toBeInTheDocument();
+ expect(submitButton).toBeInTheDocument();
+
+ await act(async () => {
+ fireEvent.click(cancelButton);
+ });
+
+ expect(mockCancel).toHaveBeenCalledTimes(1);
+ });
+
+ it('displays loading state during submission', async () => {
+ render();
+ const submitButton = await screen.findByText('label.update-entity');
+
+ userEvent.type(
+ await screen.findByTestId('input-oldPassword'),
+ 'oldPassword'
+ );
+
+ userEvent.type(await screen.findByTestId('input-newPassword'), 'Test@123');
+ userEvent.type(
+ await screen.findByTestId('input-confirm-newPassword'),
+ 'Test@123'
+ );
+
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+
+ expect(
+ await screen.findByRole('img', { name: 'loading' })
+ ).toBeInTheDocument();
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx
index e16a2ee688c7..0f66127755bf 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Users/ChangePasswordForm.tsx
@@ -42,6 +42,7 @@ const ChangePasswordForm: React.FC = ({
centered
closable={false}
confirmLoading={isLoading}
+ data-testid="modal-container"
maskClosable={false}
okButtonProps={{
form: 'change-password-form',
@@ -67,6 +68,7 @@ const ChangePasswordForm: React.FC = ({
onFinish={onSave}>
{isLoggedInUser && (
= ({
]}>
= ({
]}>
= ({
]}>
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx
index 744a1c81a4ca..5d8cb88c7283 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Users/UsersProfile/UserProfileDetails/UserProfileDetails.component.tsx
@@ -171,27 +171,31 @@ const UserProfileDetails = ({
),
[showChangePasswordComponent]
);
-
const handleChangePassword = async (data: ChangePasswordRequest) => {
try {
setIsLoading(true);
+
+ const newData = {
+ username: userData.name,
+ requestType: isLoggedInUser ? RequestType.Self : RequestType.User,
+ };
+
const sendData = {
...data,
- ...(isAdminUser &&
- !isLoggedInUser && {
- username: userData.name,
- requestType: RequestType.User,
- }),
+ ...newData,
};
+
await changePassword(sendData);
- setIsChangePassword(false);
+
showSuccessToast(
t('server.update-entity-success', { entity: t('label.password') })
);
- } catch (err) {
- showErrorToast(err as AxiosError);
+
+ setIsChangePassword(false);
+ } catch (error) {
+ showErrorToast(error as AxiosError);
} finally {
- setIsLoading(true);
+ setIsLoading(false);
}
};