diff options
Diffstat (limited to 'spec/frontend/profile')
3 files changed, 168 insertions, 24 deletions
diff --git a/spec/frontend/profile/account/components/update_username_spec.js b/spec/frontend/profile/account/components/update_username_spec.js index 8295d1d43cf..a3d7b63373c 100644 --- a/spec/frontend/profile/account/components/update_username_spec.js +++ b/spec/frontend/profile/account/components/update_username_spec.js @@ -2,10 +2,13 @@ import { GlModal } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import { TEST_HOST } from 'helpers/test_constants'; +import { deprecatedCreateFlash as createFlash } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import UpdateUsername from '~/profile/account/components/update_username.vue'; +jest.mock('~/flash'); + describe('UpdateUsername component', () => { const rootUrl = TEST_HOST; const actionUrl = `${TEST_HOST}/update/username`; @@ -105,7 +108,8 @@ describe('UpdateUsername component', () => { axiosMock.onPut(actionUrl).replyOnce(() => { expect(input.attributes('disabled')).toBe('disabled'); - expect(openModalBtn.props('disabled')).toBe(true); + expect(openModalBtn.props('disabled')).toBe(false); + expect(openModalBtn.props('loading')).toBe(true); return [200, { message: 'Username changed' }]; }); @@ -115,6 +119,7 @@ describe('UpdateUsername component', () => { expect(input.attributes('disabled')).toBe(undefined); expect(openModalBtn.props('disabled')).toBe(true); + expect(openModalBtn.props('loading')).toBe(false); }); it('does not set the username after a erroneous update', async () => { @@ -122,7 +127,8 @@ describe('UpdateUsername component', () => { axiosMock.onPut(actionUrl).replyOnce(() => { expect(input.attributes('disabled')).toBe('disabled'); - expect(openModalBtn.props('disabled')).toBe(true); + expect(openModalBtn.props('disabled')).toBe(false); + expect(openModalBtn.props('loading')).toBe(true); return [400, { message: 'Invalid username' }]; }); @@ -130,6 +136,29 @@ describe('UpdateUsername component', () => { await expect(wrapper.vm.onConfirm()).rejects.toThrow(); expect(input.attributes('disabled')).toBe(undefined); expect(openModalBtn.props('disabled')).toBe(false); + expect(openModalBtn.props('loading')).toBe(false); + }); + + it('shows an error message if the error response has a `message` property', async () => { + axiosMock.onPut(actionUrl).replyOnce(() => { + return [400, { message: 'Invalid username' }]; + }); + + await expect(wrapper.vm.onConfirm()).rejects.toThrow(); + + expect(createFlash).toBeCalledWith('Invalid username'); + }); + + it("shows a fallback error message if the error response doesn't have a `message` property", async () => { + axiosMock.onPut(actionUrl).replyOnce(() => { + return [400]; + }); + + await expect(wrapper.vm.onConfirm()).rejects.toThrow(); + + expect(createFlash).toBeCalledWith( + 'An error occurred while updating your username, please try again.', + ); }); }); }); diff --git a/spec/frontend/profile/preferences/components/profile_preferences_spec.js b/spec/frontend/profile/preferences/components/profile_preferences_spec.js index 82c41178410..9e6f5594d26 100644 --- a/spec/frontend/profile/preferences/components/profile_preferences_spec.js +++ b/spec/frontend/profile/preferences/components/profile_preferences_spec.js @@ -1,10 +1,19 @@ import { GlButton } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import IntegrationView from '~/profile/preferences/components/integration_view.vue'; import ProfilePreferences from '~/profile/preferences/components/profile_preferences.vue'; import { i18n } from '~/profile/preferences/constants'; -import { integrationViews, userFields, bodyClasses } from '../mock_data'; +import { + integrationViews, + userFields, + bodyClasses, + themes, + lightModeThemeId1, + darkModeThemeId, + lightModeThemeId2, +} from '../mock_data'; const expectedUrl = '/foo'; @@ -14,7 +23,7 @@ describe('ProfilePreferences component', () => { integrationViews: [], userFields, bodyClasses, - themes: [{ id: 1, css_class: 'foo' }], + themes, profilePreferencesPath: '/update-profile', formEl: document.createElement('form'), }; @@ -49,6 +58,30 @@ describe('ProfilePreferences component', () => { return document.querySelector('.flash-container .flash-text'); } + function createThemeInput(themeId = lightModeThemeId1) { + const input = document.createElement('input'); + input.setAttribute('name', 'user[theme_id]'); + input.setAttribute('type', 'radio'); + input.setAttribute('value', themeId.toString()); + input.setAttribute('checked', 'checked'); + return input; + } + + function createForm(themeInput = createThemeInput()) { + const form = document.createElement('form'); + form.setAttribute('url', expectedUrl); + form.setAttribute('method', 'put'); + form.appendChild(themeInput); + return form; + } + + function setupBody() { + const div = document.createElement('div'); + div.classList.add('container-fluid'); + document.body.appendChild(div); + document.body.classList.add('content-wrapper'); + } + beforeEach(() => { setFixtures('<div class="flash-container"></div>'); }); @@ -84,30 +117,15 @@ describe('ProfilePreferences component', () => { let form; beforeEach(() => { - const div = document.createElement('div'); - div.classList.add('container-fluid'); - document.body.appendChild(div); - document.body.classList.add('content-wrapper'); - - form = document.createElement('form'); - form.setAttribute('url', expectedUrl); - form.setAttribute('method', 'put'); - - const input = document.createElement('input'); - input.setAttribute('name', 'user[theme_id]'); - input.setAttribute('type', 'radio'); - input.setAttribute('value', '1'); - input.setAttribute('checked', 'checked'); - form.appendChild(input); - + setupBody(); + form = createForm(); wrapper = createComponent({ provide: { formEl: form }, attachTo: document.body }); - const beforeSendEvent = new CustomEvent('ajax:beforeSend'); form.dispatchEvent(beforeSendEvent); }); it('disables the submit button', async () => { - await wrapper.vm.$nextTick(); + await nextTick(); const button = findSubmitButton(); expect(button.props('disabled')).toBe(true); }); @@ -116,7 +134,7 @@ describe('ProfilePreferences component', () => { const successEvent = new CustomEvent('ajax:success'); form.dispatchEvent(successEvent); - await wrapper.vm.$nextTick(); + await nextTick(); const button = findSubmitButton(); expect(button.props('disabled')).toBe(false); }); @@ -125,7 +143,7 @@ describe('ProfilePreferences component', () => { const errorEvent = new CustomEvent('ajax:error'); form.dispatchEvent(errorEvent); - await wrapper.vm.$nextTick(); + await nextTick(); const button = findSubmitButton(); expect(button.props('disabled')).toBe(false); }); @@ -160,4 +178,89 @@ describe('ProfilePreferences component', () => { expect(findFlashError().innerText.trim()).toEqual(message); }); }); + + describe('theme changes', () => { + const { location } = window; + + let themeInput; + let form; + + function setupWrapper() { + wrapper = createComponent({ provide: { formEl: form }, attachTo: document.body }); + } + + function selectThemeId(themeId) { + themeInput.setAttribute('value', themeId.toString()); + } + + function dispatchBeforeSendEvent() { + const beforeSendEvent = new CustomEvent('ajax:beforeSend'); + form.dispatchEvent(beforeSendEvent); + } + + function dispatchSuccessEvent() { + const successEvent = new CustomEvent('ajax:success'); + form.dispatchEvent(successEvent); + } + + beforeAll(() => { + delete window.location; + window.location = { + ...location, + reload: jest.fn(), + }; + }); + + afterAll(() => { + window.location = location; + }); + + beforeEach(() => { + setupBody(); + themeInput = createThemeInput(); + form = createForm(themeInput); + }); + + it('reloads the page when switching from light to dark mode', async () => { + selectThemeId(lightModeThemeId1); + setupWrapper(); + + selectThemeId(darkModeThemeId); + dispatchBeforeSendEvent(); + await nextTick(); + + dispatchSuccessEvent(); + await nextTick(); + + expect(window.location.reload).toHaveBeenCalledTimes(1); + }); + + it('reloads the page when switching from dark to light mode', async () => { + selectThemeId(darkModeThemeId); + setupWrapper(); + + selectThemeId(lightModeThemeId1); + dispatchBeforeSendEvent(); + await nextTick(); + + dispatchSuccessEvent(); + await nextTick(); + + expect(window.location.reload).toHaveBeenCalledTimes(1); + }); + + it('does not reload the page when switching between light mode themes', async () => { + selectThemeId(lightModeThemeId1); + setupWrapper(); + + selectThemeId(lightModeThemeId2); + dispatchBeforeSendEvent(); + await nextTick(); + + dispatchSuccessEvent(); + await nextTick(); + + expect(window.location.reload).not.toHaveBeenCalled(); + }); + }); }); diff --git a/spec/frontend/profile/preferences/mock_data.js b/spec/frontend/profile/preferences/mock_data.js index ce33fc79a39..91cfdfadc78 100644 --- a/spec/frontend/profile/preferences/mock_data.js +++ b/spec/frontend/profile/preferences/mock_data.js @@ -18,3 +18,15 @@ export const userFields = { }; export const bodyClasses = 'ui-light-indigo ui-light gl-dark'; + +export const themes = [ + { id: 1, css_class: 'foo' }, + { id: 2, css_class: 'bar' }, + { id: 3, css_class: 'gl-dark' }, +]; + +export const lightModeThemeId1 = 1; + +export const lightModeThemeId2 = 2; + +export const darkModeThemeId = 3; |