diff options
Diffstat (limited to 'spec/frontend/projects/commit/components')
3 files changed, 365 insertions, 0 deletions
diff --git a/spec/frontend/projects/commit/components/branches_dropdown_spec.js b/spec/frontend/projects/commit/components/branches_dropdown_spec.js new file mode 100644 index 00000000000..9fa7d658405 --- /dev/null +++ b/spec/frontend/projects/commit/components/branches_dropdown_spec.js @@ -0,0 +1,166 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import { shallowMount } from '@vue/test-utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; +import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue'; + +Vue.use(Vuex); + +describe('BranchesDropdown', () => { + let wrapper; + let store; + const spyFetchBranches = jest.fn(); + + const createComponent = (term, state = { isFetching: false }) => { + store = new Vuex.Store({ + getters: { + joinedBranches: () => ['_master_', '_branch_1_', '_branch_2_'], + }, + actions: { + fetchBranches: spyFetchBranches, + }, + state, + }); + + wrapper = extendedWrapper( + shallowMount(BranchesDropdown, { + store, + propsData: { + value: term, + }, + }), + ); + }; + + const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); + const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType); + const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index); + const findNoResults = () => wrapper.findByTestId('empty-result-message'); + const findLoading = () => wrapper.findByTestId('dropdown-text-loading-icon'); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + spyFetchBranches.mockReset(); + }); + + describe('On mount', () => { + beforeEach(() => { + createComponent(''); + }); + + it('invokes fetchBranches', () => { + expect(spyFetchBranches).toHaveBeenCalled(); + }); + }); + + describe('Loading states', () => { + it('shows loading icon while fetching', () => { + createComponent('', { isFetching: true }); + + expect(findLoading().isVisible()).toBe(true); + }); + + it('does not show loading icon', () => { + createComponent(''); + + expect(findLoading().isVisible()).toBe(false); + }); + }); + + describe('No branches found', () => { + beforeEach(() => { + createComponent('_non_existent_branch_'); + }); + + it('renders empty results message', () => { + expect(findNoResults().text()).toBe('No matching results'); + }); + + it('shows GlSearchBoxByType with default attributes', () => { + expect(findSearchBoxByType().exists()).toBe(true); + expect(findSearchBoxByType().vm.$attrs).toMatchObject({ + placeholder: 'Search branches', + debounce: 250, + }); + }); + }); + + describe('Search term is empty', () => { + beforeEach(() => { + createComponent(''); + }); + + it('renders all branches when search term is empty', () => { + expect(findAllDropdownItems()).toHaveLength(3); + expect(findDropdownItemByIndex(0).text()).toBe('_master_'); + expect(findDropdownItemByIndex(1).text()).toBe('_branch_1_'); + expect(findDropdownItemByIndex(2).text()).toBe('_branch_2_'); + }); + + it('should not be selected on the inactive branch', () => { + expect(wrapper.vm.isSelected('_master_')).toBe(false); + }); + }); + + describe('When searching', () => { + beforeEach(() => { + createComponent(''); + }); + + it('invokes fetchBranches', async () => { + const spy = jest.spyOn(wrapper.vm, 'fetchBranches'); + + findSearchBoxByType().vm.$emit('input', '_anything_'); + + await wrapper.vm.$nextTick(); + + expect(spy).toHaveBeenCalledWith('_anything_'); + expect(wrapper.vm.searchTerm).toBe('_anything_'); + }); + }); + + describe('Branches found', () => { + beforeEach(() => { + createComponent('_branch_1_', { branch: '_branch_1_' }); + }); + + it('renders only the branch searched for', () => { + expect(findAllDropdownItems()).toHaveLength(1); + expect(findDropdownItemByIndex(0).text()).toBe('_branch_1_'); + }); + + it('should not display empty results message', () => { + expect(findNoResults().exists()).toBe(false); + }); + + it('should signify this branch is selected', () => { + expect(wrapper.vm.isSelected('_branch_1_')).toBe(true); + }); + + it('should signify the branch is not selected', () => { + expect(wrapper.vm.isSelected('_not_selected_branch_')).toBe(false); + }); + + describe('Custom events', () => { + it('should emit selectBranch if an branch is clicked', () => { + findDropdownItemByIndex(0).vm.$emit('click'); + + expect(wrapper.emitted('selectBranch')).toEqual([['_branch_1_']]); + expect(wrapper.vm.searchTerm).toBe('_branch_1_'); + }); + }); + }); + + describe('Case insensitive for search term', () => { + beforeEach(() => { + createComponent('_BrAnCh_1_'); + }); + + it('renders only the branch searched for', () => { + expect(findAllDropdownItems()).toHaveLength(1); + expect(findDropdownItemByIndex(0).text()).toBe('_branch_1_'); + }); + }); +}); diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js new file mode 100644 index 00000000000..1c37b82fed3 --- /dev/null +++ b/spec/frontend/projects/commit/components/form_modal_spec.js @@ -0,0 +1,155 @@ +import MockAdapter from 'axios-mock-adapter'; +import { shallowMount, mount, createWrapper } from '@vue/test-utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { GlModal, GlForm, GlFormCheckbox, GlSprintf } from '@gitlab/ui'; +import { within } from '@testing-library/dom'; +import axios from '~/lib/utils/axios_utils'; +import eventHub from '~/projects/commit/event_hub'; +import CommitFormModal from '~/projects/commit/components/form_modal.vue'; +import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue'; +import createStore from '~/projects/commit/store'; +import mockData from '../mock_data'; + +describe('CommitFormModal', () => { + let wrapper; + let store; + let axiosMock; + + const createComponent = (method, state = {}, provide = {}) => { + store = createStore({ ...mockData.mockModal, ...state }); + wrapper = extendedWrapper( + method(CommitFormModal, { + provide, + propsData: { ...mockData.modalPropsData }, + store, + attrs: { + static: true, + visible: true, + }, + }), + ); + }; + + const findModal = () => wrapper.findComponent(GlModal); + const findStartBranch = () => wrapper.find('#start_branch'); + const findDropdown = () => wrapper.findComponent(BranchesDropdown); + const findForm = () => findModal().findComponent(GlForm); + const findCheckBox = () => findForm().findComponent(GlFormCheckbox); + const findPrependedText = () => wrapper.findByTestId('prepended-text'); + const findAppendedText = () => wrapper.findByTestId('appended-text'); + const getByText = (text, options) => + createWrapper(within(findModal().element).getByText(text, options)); + + beforeEach(() => { + axiosMock = new MockAdapter(axios); + }); + + afterEach(() => { + wrapper.destroy(); + axiosMock.restore(); + }); + + describe('Basic interactions', () => { + it('Listens for opening of modal on mount', () => { + jest.spyOn(eventHub, '$on'); + + createComponent(shallowMount); + + expect(eventHub.$on).toHaveBeenCalledWith(mockData.modalPropsData.openModal, wrapper.vm.show); + }); + + it('Shows modal', () => { + createComponent(shallowMount); + const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit'); + + wrapper.vm.show(); + + expect(rootEmit).toHaveBeenCalledWith('bv::show::modal', mockData.modalPropsData.modalId); + }); + + it('Clears the modal state once modal is hidden', () => { + createComponent(shallowMount); + jest.spyOn(store, 'dispatch').mockImplementation(); + wrapper.vm.checked = false; + + findModal().vm.$emit('hidden'); + + expect(store.dispatch).toHaveBeenCalledWith('clearModal'); + expect(store.dispatch).toHaveBeenCalledWith('setSelectedBranch', ''); + expect(wrapper.vm.checked).toBe(true); + }); + + it('Shows the checkbox for new merge request', () => { + createComponent(shallowMount); + + expect(findCheckBox().exists()).toBe(true); + }); + + it('Shows the prepended text', () => { + createComponent(shallowMount, {}, { prependedText: '_prepended_text_' }); + + expect(findPrependedText().exists()).toBe(true); + expect(findPrependedText().find(GlSprintf).attributes('message')).toBe('_prepended_text_'); + }); + + it('Does not show prepended text', () => { + createComponent(shallowMount); + + expect(findPrependedText().exists()).toBe(false); + }); + + it('Does not show extra message text', () => { + createComponent(shallowMount); + + expect(findModal().find('[data-testid="appended-text"]').exists()).toBe(false); + }); + + it('Does not show the checkbox for new merge request', () => { + createComponent(shallowMount, { pushCode: false }); + + expect(findCheckBox().exists()).toBe(false); + }); + + it('Shows the branch in fork message', () => { + createComponent(shallowMount, { pushCode: false }); + + expect(findAppendedText().exists()).toBe(true); + expect(findAppendedText().find(GlSprintf).attributes('message')).toContain( + mockData.modalPropsData.i18n.branchInFork, + ); + }); + + it('Shows the branch collaboration message', () => { + createComponent(shallowMount, { pushCode: false, branchCollaboration: true }); + + expect(findAppendedText().exists()).toBe(true); + expect(findAppendedText().find(GlSprintf).attributes('message')).toContain( + mockData.modalPropsData.i18n.existingBranch, + ); + }); + }); + + describe('Taking action on the form', () => { + beforeEach(() => { + createComponent(mount); + }); + + it('Action primary button dispatches submit action', () => { + const submitSpy = jest.spyOn(findForm().element, 'submit'); + + getByText(mockData.modalPropsData.i18n.actionPrimaryText).trigger('click'); + + expect(submitSpy).toHaveBeenCalled(); + + submitSpy.mockRestore(); + }); + + it('Changes the start_branch input value', async () => { + findDropdown().vm.$emit('selectBranch', '_changed_branch_value_'); + + await wrapper.vm.$nextTick(); + + expect(findStartBranch().attributes('value')).toBe('_changed_branch_value_'); + }); + }); +}); diff --git a/spec/frontend/projects/commit/components/form_trigger_spec.js b/spec/frontend/projects/commit/components/form_trigger_spec.js new file mode 100644 index 00000000000..ca51419d6a5 --- /dev/null +++ b/spec/frontend/projects/commit/components/form_trigger_spec.js @@ -0,0 +1,44 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlLink } from '@gitlab/ui'; +import FormTrigger from '~/projects/commit/components/form_trigger.vue'; +import eventHub from '~/projects/commit/event_hub'; + +const displayText = '_display_text_'; + +const createComponent = () => { + return shallowMount(FormTrigger, { + provide: { displayText }, + propsData: { openModal: '_open_modal_' }, + }); +}; + +describe('FormTrigger', () => { + let wrapper; + let spy; + + beforeEach(() => { + spy = jest.spyOn(eventHub, '$emit'); + wrapper = createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + const findLink = () => wrapper.find(GlLink); + + describe('displayText', () => { + it('includes the correct displayText for the link', () => { + expect(findLink().text()).toBe(displayText); + }); + }); + + describe('clicking the link', () => { + it('emits openModal', () => { + findLink().vm.$emit('click'); + + expect(spy).toHaveBeenCalledWith('_open_modal_'); + }); + }); +}); |