From 66ba85487955bb0cfb755c3924f0dcdfb465fd72 Mon Sep 17 00:00:00 2001 From: therealrinku Date: Tue, 16 Dec 2025 11:54:03 +0545 Subject: [PATCH 1/2] Make error and success message user friendly during username update Changelog: fixed --- .../account/components/update_username.vue | 18 ++++++--- .../components/update_username_spec.js | 38 ++++++++----------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/app/assets/javascripts/profile/account/components/update_username.vue b/app/assets/javascripts/profile/account/components/update_username.vue index bc5de488830618..4d6a5e95d0afc6 100644 --- a/app/assets/javascripts/profile/account/components/update_username.vue +++ b/app/assets/javascripts/profile/account/components/update_username.vue @@ -2,7 +2,6 @@ import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui'; import { escape } from 'lodash'; import SafeHtml from '~/vue_shared/directives/safe_html'; -import { createAlert, VARIANT_INFO } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { __, s__, sprintf } from '~/locale'; @@ -34,6 +33,7 @@ export default { isRequestPending: false, username: this.initialUsername, newUsername: this.initialUsername, + errorMessage: null, }; }, computed: { @@ -82,19 +82,18 @@ Please update your Git repository remotes as soon as possible.`), return axios .put(this.actionUrl, putData) .then((result) => { - createAlert({ message: result.data.message, variant: VARIANT_INFO }); + this.$toast.show(result.data.message); + this.username = username; this.isRequestPending = false; + this.errorMessage = null; }) .catch((error) => { const errorMessage = error?.response?.data?.message || s__('Profiles|An error occurred while updating your username, please try again.'); - createAlert({ - message: errorMessage, - renderMessageHTML: true, - }); + this.errorMessage = errorMessage; this.isRequestPending = false; throw error; }); @@ -120,9 +119,16 @@ Please update your Git repository remotes as soon as possible.`), :disabled="isRequestPending" class="form-control gl-md-form-input-lg" required="required" + @input="errorMessage = null" />

{{ path }}

+

{ let axiosMock; const findNewUsernameInput = () => wrapper.findByTestId('new-username-input'); + const findUsernameUpdateError = () => wrapper.findByTestId('username-update-error'); const createComponent = (props = {}) => { wrapper = shallowMountExtended(UpdateUsername, { @@ -34,6 +34,11 @@ describe('UpdateUsername component', () => { stubs: { GlModal, }, + mocks: { + $toast: { + show: jest.fn(), + }, + }, }); }; @@ -114,7 +119,7 @@ describe('UpdateUsername component', () => { expect(axios.put).toHaveBeenCalledWith(actionUrl, { user: { username: newUsername } }); }); - it('sets the username after a successful update', async () => { + it('sets the username after a successful update and shows toast message', async () => { const { input, openModalBtn, modal } = findElements(); axiosMock.onPut(actionUrl).replyOnce(() => { @@ -131,6 +136,8 @@ describe('UpdateUsername component', () => { expect(input.attributes('disabled')).toBe(undefined); expect(openModalBtn.props('disabled')).toBe(true); expect(openModalBtn.props('loading')).toBe(false); + + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('Username changed'); }); it('does not set the username after a erroneous update', async () => { @@ -158,13 +165,10 @@ describe('UpdateUsername component', () => { await clickModalWithErrorResponse(); - expect(createAlert).toHaveBeenCalledWith({ - message: 'Invalid username', - renderMessageHTML: true, - }); + expect(findUsernameUpdateError().element.textContent).toBe('Invalid username'); }); - it('decodes HTML entities in error messages', async () => { + it('decodes HTML entities in error message', async () => { const encodedMessage = 'Username change failed - '-' is a reserved name & cannot contain <special> characters or "quotes"'; axiosMock.onPut(actionUrl).replyOnce(() => { @@ -173,18 +177,7 @@ describe('UpdateUsername component', () => { await clickModalWithErrorResponse(); - expect(createAlert).toHaveBeenCalledWith({ - message: encodedMessage, - renderMessageHTML: true, - }); - - // Test what the user actually sees when HTML is rendered - const alertCall = createAlert.mock.calls[0][0]; - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = alertCall.message; - - // This simulates what happens when renderMessageHTML: true - expect(tempDiv.textContent).toBe( + expect(findUsernameUpdateError().element.textContent).toBe( 'Username change failed - \'-\' is a reserved name & cannot contain characters or "quotes"', ); }); @@ -196,10 +189,9 @@ describe('UpdateUsername component', () => { await clickModalWithErrorResponse(); - expect(createAlert).toHaveBeenCalledWith({ - message: 'An error occurred while updating your username, please try again.', - renderMessageHTML: true, - }); + expect(findUsernameUpdateError().element.textContent).toBe( + 'An error occurred while updating your username, please try again.', + ); }); }); }); -- GitLab From 29a9003a76b6865a95dec3bcddb115e9b3691f1b Mon Sep 17 00:00:00 2001 From: therealrinku Date: Tue, 16 Dec 2025 11:56:34 +0545 Subject: [PATCH 2/2] Make eslint happy --- .../javascripts/profile/account/components/update_username.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/profile/account/components/update_username.vue b/app/assets/javascripts/profile/account/components/update_username.vue index 4d6a5e95d0afc6..3fd33b0c4049ed 100644 --- a/app/assets/javascripts/profile/account/components/update_username.vue +++ b/app/assets/javascripts/profile/account/components/update_username.vue @@ -125,9 +125,9 @@ Please update your Git repository remotes as soon as possible.`),

{{ path }}