diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-05 15:09:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-05 15:09:28 +0000 |
commit | 4046c3447e0a01fe48e224e72e12b27859b92822 (patch) | |
tree | 63b8293134d5cc6030abc7a5d2aeb34a34f54925 /spec/frontend/notifications | |
parent | 64f7eb2b37aebbb713463b2f6971b13191c1b0db (diff) | |
download | gitlab-ce-4046c3447e0a01fe48e224e72e12b27859b92822.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/notifications')
-rw-r--r-- | spec/frontend/notifications/components/custom_notifications_modal_spec.js | 267 | ||||
-rw-r--r-- | spec/frontend/notifications/components/notifications_dropdown_spec.js | 34 |
2 files changed, 301 insertions, 0 deletions
diff --git a/spec/frontend/notifications/components/custom_notifications_modal_spec.js b/spec/frontend/notifications/components/custom_notifications_modal_spec.js new file mode 100644 index 00000000000..192fc194015 --- /dev/null +++ b/spec/frontend/notifications/components/custom_notifications_modal_spec.js @@ -0,0 +1,267 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { shallowMount } from '@vue/test-utils'; +import { GlSprintf, GlModal, GlFormGroup, GlFormCheckbox, GlLoadingIcon } from '@gitlab/ui'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import httpStatus from '~/lib/utils/http_status'; +import CustomNotificationsModal from '~/notifications/components/custom_notifications_modal.vue'; +import { i18n } from '~/notifications/constants'; + +const mockNotificationSettingsResponses = { + default: { + level: 'custom', + events: { + new_release: true, + new_note: false, + }, + }, + updated: { + level: 'custom', + events: { + new_release: true, + new_note: true, + }, + }, +}; + +const mockToastShow = jest.fn(); + +describe('CustomNotificationsModal', () => { + let wrapper; + let mockAxios; + + function createComponent(options = {}) { + const { injectedProperties = {}, props = {} } = options; + return extendedWrapper( + shallowMount(CustomNotificationsModal, { + props: { + ...props, + }, + provide: { + ...injectedProperties, + }, + mocks: { + $toast: { + show: mockToastShow, + }, + }, + stubs: { + GlModal, + GlFormGroup, + GlFormCheckbox, + }, + }), + ); + } + + const findModalBodyDescription = () => wrapper.find(GlSprintf); + const findAllCheckboxes = () => wrapper.findAll(GlFormCheckbox); + const findCheckboxAt = (index) => findAllCheckboxes().at(index); + + beforeEach(() => { + gon.api_version = 'v4'; + mockAxios = new MockAdapter(axios); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + mockAxios.restore(); + }); + + describe('template', () => { + beforeEach(() => { + wrapper = createComponent(); + }); + + it('displays the body title and the body message', () => { + expect(wrapper.findByTestId('modalBodyTitle').text()).toBe( + i18n.customNotificationsModal.bodyTitle, + ); + expect(findModalBodyDescription().attributes('message')).toContain( + i18n.customNotificationsModal.bodyMessage, + ); + }); + + describe('checkbox items', () => { + beforeEach(async () => { + wrapper = createComponent(); + + wrapper.setData({ + events: [ + { id: 'new_release', enabled: true, name: 'New release', loading: false }, + { id: 'new_note', enabled: false, name: 'New note', loading: true }, + ], + }); + + await wrapper.vm.$nextTick(); + }); + + it.each` + index | eventId | eventName | enabled | loading + ${0} | ${'new_release'} | ${'New release'} | ${true} | ${false} + ${1} | ${'new_note'} | ${'New note'} | ${false} | ${true} + `( + 'renders a checkbox for "$eventName" with checked=$enabled', + async ({ index, eventName, enabled, loading }) => { + const checkbox = findCheckboxAt(index); + expect(checkbox.text()).toContain(eventName); + expect(checkbox.vm.$attrs.checked).toBe(enabled); + expect(checkbox.find(GlLoadingIcon).exists()).toBe(loading); + }, + ); + }); + }); + + describe('API calls', () => { + describe('load notification settings', () => { + beforeEach(() => { + jest.spyOn(axios, 'get'); + }); + + it.each` + projectId | groupId | endpointUrl | notificationType | condition + ${1} | ${null} | ${'/api/v4/projects/1/notification_settings'} | ${'project'} | ${'a projectId is given'} + ${null} | ${1} | ${'/api/v4/groups/1/notification_settings'} | ${'group'} | ${'a groupId is given'} + ${null} | ${null} | ${'/api/v4/notification_settings'} | ${'global'} | ${'neither projectId nor groupId are given'} + `( + 'requests $notificationType notification settings when $condition', + async ({ projectId, groupId, endpointUrl }) => { + const injectedProperties = { + projectId, + groupId, + }; + + mockAxios + .onGet(endpointUrl) + .reply(httpStatus.OK, mockNotificationSettingsResponses.default); + + wrapper = createComponent({ injectedProperties }); + + wrapper.find(GlModal).vm.$emit('show'); + + await waitForPromises(); + + expect(axios.get).toHaveBeenCalledWith(endpointUrl); + }, + ); + + it('updates the loading state and the events property', async () => { + const endpointUrl = '/api/v4/notification_settings'; + + mockAxios + .onGet(endpointUrl) + .reply(httpStatus.OK, mockNotificationSettingsResponses.default); + + wrapper = createComponent(); + + wrapper.find(GlModal).vm.$emit('show'); + expect(wrapper.vm.isLoading).toBe(true); + + await waitForPromises(); + + expect(axios.get).toHaveBeenCalledWith(endpointUrl); + expect(wrapper.vm.isLoading).toBe(false); + expect(wrapper.vm.events).toEqual([ + { id: 'new_release', enabled: true, name: 'New release', loading: false }, + { id: 'new_note', enabled: false, name: 'New note', loading: false }, + ]); + }); + + it('shows a toast message when the request fails', async () => { + mockAxios.onGet('/api/v4/notification_settings').reply(httpStatus.NOT_FOUND, {}); + wrapper = createComponent(); + + wrapper.find(GlModal).vm.$emit('show'); + + await waitForPromises(); + + expect( + mockToastShow, + ).toHaveBeenCalledWith( + 'An error occured while loading the notification settings. Please try again.', + { type: 'error' }, + ); + }); + }); + + describe('update notification settings', () => { + beforeEach(() => { + jest.spyOn(axios, 'put'); + }); + + it.each` + projectId | groupId | endpointUrl | notificationType | condition + ${1} | ${null} | ${'/api/v4/projects/1/notification_settings'} | ${'project'} | ${'a projectId is given'} + ${null} | ${1} | ${'/api/v4/groups/1/notification_settings'} | ${'group'} | ${'a groupId is given'} + ${null} | ${null} | ${'/api/v4/notification_settings'} | ${'global'} | ${'neither projectId nor groupId are given'} + `( + 'updates the $notificationType notification settings when $condition and the user clicks the checkbox ', + async ({ projectId, groupId, endpointUrl }) => { + mockAxios + .onGet(endpointUrl) + .reply(httpStatus.OK, mockNotificationSettingsResponses.default); + + mockAxios + .onPut(endpointUrl) + .reply(httpStatus.OK, mockNotificationSettingsResponses.updated); + + const injectedProperties = { + projectId, + groupId, + }; + + wrapper = createComponent({ injectedProperties }); + + wrapper.setData({ + events: [ + { id: 'new_release', enabled: true, name: 'New release', loading: false }, + { id: 'new_note', enabled: false, name: 'New note', loading: false }, + ], + }); + + await wrapper.vm.$nextTick(); + + findCheckboxAt(1).vm.$emit('change', true); + + await waitForPromises(); + + expect(axios.put).toHaveBeenCalledWith(endpointUrl, { + new_note: true, + }); + + expect(wrapper.vm.events).toEqual([ + { id: 'new_release', enabled: true, name: 'New release', loading: false }, + { id: 'new_note', enabled: true, name: 'New note', loading: false }, + ]); + }, + ); + + it('shows a toast message when the request fails', async () => { + mockAxios.onPut('/api/v4/notification_settings').reply(httpStatus.NOT_FOUND, {}); + wrapper = createComponent(); + + wrapper.setData({ + events: [ + { id: 'new_release', enabled: true, name: 'New release', loading: false }, + { id: 'new_note', enabled: false, name: 'New note', loading: false }, + ], + }); + + await wrapper.vm.$nextTick(); + + findCheckboxAt(1).vm.$emit('change', true); + + await waitForPromises(); + + expect( + mockToastShow, + ).toHaveBeenCalledWith( + 'An error occured while updating the notification settings. Please try again.', + { type: 'error' }, + ); + }); + }); + }); +}); diff --git a/spec/frontend/notifications/components/notifications_dropdown_spec.js b/spec/frontend/notifications/components/notifications_dropdown_spec.js index 2fe8e9c677e..37926f6f1bc 100644 --- a/spec/frontend/notifications/components/notifications_dropdown_spec.js +++ b/spec/frontend/notifications/components/notifications_dropdown_spec.js @@ -7,6 +7,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import httpStatus from '~/lib/utils/http_status'; import NotificationsDropdown from '~/notifications/components/notifications_dropdown.vue'; import NotificationsDropdownItem from '~/notifications/components/notifications_dropdown_item.vue'; +import CustomNotificationsModal from '~/notifications/components/custom_notifications_modal.vue'; const mockDropdownItems = ['global', 'watch', 'participating', 'mention', 'disabled']; const mockToastShow = jest.fn(); @@ -14,17 +15,26 @@ const mockToastShow = jest.fn(); describe('NotificationsDropdown', () => { let wrapper; let mockAxios; + let glModalDirective; function createComponent(injectedProperties = {}) { + glModalDirective = jest.fn(); + return shallowMount(NotificationsDropdown, { stubs: { GlButtonGroup, GlDropdown, GlDropdownItem, NotificationsDropdownItem, + CustomNotificationsModal, }, directives: { GlTooltip: createMockDirective(), + glModal: { + bind(_, { value }) { + glModalDirective(value); + }, + }, }, provide: { dropdownItems: mockDropdownItems, @@ -94,6 +104,19 @@ describe('NotificationsDropdown', () => { expect(findButton().text()).toBe(''); }); + + it('opens the modal when the user clicks the button', async () => { + jest.spyOn(axios, 'put'); + mockAxios.onPut('/api/v4/notification_settings').reply(httpStatus.OK, {}); + + wrapper = createComponent({ + initialNotificationLevel: 'custom', + }); + + findButton().vm.$emit('click'); + + expect(glModalDirective).toHaveBeenCalled(); + }); }); describe('when notification level is not "custom"', () => { @@ -236,5 +259,16 @@ describe('NotificationsDropdown', () => { { type: 'error' }, ); }); + + it('opens the modal when the user clicks on the "Custom" dropdown item', async () => { + mockAxios.onPut('/api/v4/notification_settings').reply(httpStatus.OK, {}); + wrapper = createComponent(); + + const mockModalShow = jest.spyOn(wrapper.vm.$refs.customNotificationsModal, 'open'); + + await clickDropdownItemAt(5); + + expect(mockModalShow).toHaveBeenCalled(); + }); }); }); |