summaryrefslogtreecommitdiff
path: root/spec/frontend/profile
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/profile')
-rw-r--r--spec/frontend/profile/account/components/update_username_spec.js33
-rw-r--r--spec/frontend/profile/preferences/components/profile_preferences_spec.js147
-rw-r--r--spec/frontend/profile/preferences/mock_data.js12
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;