diff options
author | Shah El-Rahman <selrahman@gitlab.com> | 2018-04-06 12:36:22 +0300 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2018-04-06 12:36:22 +0300 |
commit | 43ef375e084884ed4260ac9c9de8f601d5594c90 (patch) | |
tree | b5214f9deb9f389e5428f5c011b9c7cbfc55d506 /spec | |
parent | ca330f7ea30b368b928f5468a1f53264d74aa8aa (diff) |
Add confirmation modal to "Change username"
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/profiles_controller_spec.rb | 22 | ||||
-rw-r--r-- | spec/features/profile_spec.rb | 8 | ||||
-rw-r--r-- | spec/features/profiles/account_spec.rb | 12 | ||||
-rw-r--r-- | spec/javascripts/profile/account/components/update_username_spec.js | 172 |
4 files changed, 209 insertions, 5 deletions
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb index 891485406c6..de6ef919221 100644 --- a/spec/controllers/profiles_controller_spec.rb +++ b/spec/controllers/profiles_controller_spec.rb @@ -84,6 +84,28 @@ describe ProfilesController, :request_store do expect(user.username).to eq(new_username) end + it 'updates a username using JSON request' do + sign_in(user) + + put :update_username, + user: { username: new_username }, + format: :json + + expect(response.status).to eq(200) + expect(json_response['message']).to eq('Username successfully changed') + end + + it 'renders an error message when the username was not updated' do + sign_in(user) + + put :update_username, + user: { username: 'invalid username.git' }, + format: :json + + expect(response.status).to eq(422) + expect(json_response['message']).to match(/Username change failed/) + end + it 'raises a correct error when the username is missing' do sign_in(user) diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb index 0848857ed1e..15dcb30cbdd 100644 --- a/spec/features/profile_spec.rb +++ b/spec/features/profile_spec.rb @@ -97,9 +97,13 @@ describe 'Profile account page', :js do end it 'changes my username' do - fill_in 'user_username', with: 'new-username' + fill_in 'username-change-input', with: 'new-username' - click_button('Update username') + page.find('[data-target="#username-change-confirmation-modal"]').click + + page.within('.modal') do + find('.js-modal-primary-action').click + end expect(page).to have_content('new-username') end diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index e8eb0d17ca4..215b658eb7b 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Profile > Account' do +feature 'Profile > Account', :js do given(:user) { create(:user, username: 'foo') } before do @@ -59,6 +59,12 @@ end def update_username(new_username) allow(user.namespace).to receive(:move_dir) visit profile_account_path - fill_in 'user_username', with: new_username - click_button 'Update username' + + fill_in 'username-change-input', with: new_username + + page.find('[data-target="#username-change-confirmation-modal"]').click + + page.within('.modal') do + find('.js-modal-primary-action').click + end end diff --git a/spec/javascripts/profile/account/components/update_username_spec.js b/spec/javascripts/profile/account/components/update_username_spec.js new file mode 100644 index 00000000000..bac306edf5a --- /dev/null +++ b/spec/javascripts/profile/account/components/update_username_spec.js @@ -0,0 +1,172 @@ +import Vue from 'vue'; +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; + +import updateUsername from '~/profile/account/components/update_username.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('UpdateUsername component', () => { + const rootUrl = gl.TEST_HOST; + const actionUrl = `${gl.TEST_HOST}/update/username`; + const username = 'hasnoname'; + const newUsername = 'new_username'; + let Component; + let vm; + let axiosMock; + + beforeEach(() => { + axiosMock = new MockAdapter(axios); + Component = Vue.extend(updateUsername); + vm = mountComponent(Component, { + actionUrl, + rootUrl, + initialUsername: username, + }); + }); + + afterEach(() => { + vm.$destroy(); + axiosMock.restore(); + }); + + const findElements = () => { + const modalSelector = `#${vm.$options.modalId}`; + + return { + input: vm.$el.querySelector(`#${vm.$options.inputId}`), + openModalBtn: vm.$el.querySelector(`[data-target="${modalSelector}"]`), + modal: vm.$el.querySelector(modalSelector), + modalBody: vm.$el.querySelector(`${modalSelector} .modal-body`), + modalHeader: vm.$el.querySelector(`${modalSelector} .modal-title`), + confirmModalBtn: vm.$el.querySelector(`${modalSelector} .btn-warning`), + }; + }; + + it('has a disabled button if the username was not changed', done => { + const { input, openModalBtn } = findElements(); + input.dispatchEvent(new Event('input')); + + Vue.nextTick() + .then(() => { + expect(vm.username).toBe(username); + expect(vm.newUsername).toBe(username); + expect(openModalBtn).toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); + + it('has an enabled button which if the username was changed', done => { + const { input, openModalBtn } = findElements(); + input.value = newUsername; + input.dispatchEvent(new Event('input')); + + Vue.nextTick() + .then(() => { + expect(vm.username).toBe(username); + expect(vm.newUsername).toBe(newUsername); + expect(openModalBtn).not.toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); + + it('confirmation modal contains proper header and body', done => { + const { modalBody, modalHeader } = findElements(); + + vm.newUsername = newUsername; + + Vue.nextTick() + .then(() => { + expect(modalHeader.textContent).toContain('Change username?'); + expect(modalBody.textContent).toContain( + `You are going to change the username ${username} to ${newUsername}`, + ); + }) + .then(done) + .catch(done.fail); + }); + + it('confirmation modal should escape usernames properly', done => { + const { modalBody } = findElements(); + + vm.username = vm.newUsername = '<i>Italic</i>'; + + Vue.nextTick() + .then(() => { + expect(modalBody.innerHTML).toContain('<i>Italic</i>'); + expect(modalBody.innerHTML).not.toContain(vm.username); + }) + .then(done) + .catch(done.fail); + }); + + it('executes API call on confirmation button click', done => { + const { confirmModalBtn } = findElements(); + + axiosMock.onPut(actionUrl).replyOnce(() => [200, { message: 'Username changed' }]); + spyOn(axios, 'put').and.callThrough(); + + vm.newUsername = newUsername; + + Vue.nextTick() + .then(() => { + confirmModalBtn.click(); + expect(axios.put).toHaveBeenCalledWith(actionUrl, { user: { username: newUsername } }); + }) + .then(done) + .catch(done.fail); + }); + + it('sets the username after a successful update', done => { + const { input, openModalBtn } = findElements(); + + axiosMock.onPut(actionUrl).replyOnce(() => { + expect(input).toBeDisabled(); + expect(openModalBtn).toBeDisabled(); + + return [200, { message: 'Username changed' }]; + }); + + vm.newUsername = newUsername; + + vm + .onConfirm() + .then(() => { + expect(vm.username).toBe(newUsername); + expect(vm.newUsername).toBe(newUsername); + expect(input).not.toBeDisabled(); + expect(input.value).toBe(newUsername); + expect(openModalBtn).toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); + + it('does not set the username after a erroneous update', done => { + const { input, openModalBtn } = findElements(); + + axiosMock.onPut(actionUrl).replyOnce(() => { + expect(input).toBeDisabled(); + expect(openModalBtn).toBeDisabled(); + + return [400, { message: 'Invalid username' }]; + }); + + const invalidUsername = 'anything.git'; + vm.newUsername = invalidUsername; + + vm + .onConfirm() + .then(() => done.fail('Expected onConfirm to throw!')) + .catch(() => { + expect(vm.username).toBe(username); + expect(vm.newUsername).toBe(invalidUsername); + expect(input).not.toBeDisabled(); + expect(input.value).toBe(invalidUsername); + expect(openModalBtn).not.toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); +}); |