diff options
Diffstat (limited to 'spec/frontend/sidebar/lock')
-rw-r--r-- | spec/frontend/sidebar/lock/__snapshots__/edit_form_spec.js.snap | 79 | ||||
-rw-r--r-- | spec/frontend/sidebar/lock/constants.js | 2 | ||||
-rw-r--r-- | spec/frontend/sidebar/lock/edit_form_buttons_spec.js | 171 | ||||
-rw-r--r-- | spec/frontend/sidebar/lock/edit_form_spec.js | 67 | ||||
-rw-r--r-- | spec/frontend/sidebar/lock/issuable_lock_form_spec.js | 133 | ||||
-rw-r--r-- | spec/frontend/sidebar/lock/lock_issue_sidebar_spec.js | 99 |
6 files changed, 415 insertions, 136 deletions
diff --git a/spec/frontend/sidebar/lock/__snapshots__/edit_form_spec.js.snap b/spec/frontend/sidebar/lock/__snapshots__/edit_form_spec.js.snap new file mode 100644 index 00000000000..18d4df297df --- /dev/null +++ b/spec/frontend/sidebar/lock/__snapshots__/edit_form_spec.js.snap @@ -0,0 +1,79 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Edit Form Dropdown In issue page when locked the appropriate warning text is rendered 1`] = ` +<div + class="dropdown-menu sidebar-item-warning-message" + data-testid="warning-text" +> + <p + class="text" + > + <gl-sprintf-stub + message="Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment." + /> + </p> + + <edit-form-buttons-stub + islocked="true" + issuabledisplayname="issue" + /> +</div> +`; + +exports[`Edit Form Dropdown In issue page when unlocked the appropriate warning text is rendered 1`] = ` +<div + class="dropdown-menu sidebar-item-warning-message" + data-testid="warning-text" +> + <p + class="text" + > + <gl-sprintf-stub + message="Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment." + /> + </p> + + <edit-form-buttons-stub + issuabledisplayname="issue" + /> +</div> +`; + +exports[`Edit Form Dropdown In merge request page when locked the appropriate warning text is rendered 1`] = ` +<div + class="dropdown-menu sidebar-item-warning-message" + data-testid="warning-text" +> + <p + class="text" + > + <gl-sprintf-stub + message="Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment." + /> + </p> + + <edit-form-buttons-stub + islocked="true" + issuabledisplayname="merge request" + /> +</div> +`; + +exports[`Edit Form Dropdown In merge request page when unlocked the appropriate warning text is rendered 1`] = ` +<div + class="dropdown-menu sidebar-item-warning-message" + data-testid="warning-text" +> + <p + class="text" + > + <gl-sprintf-stub + message="Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment." + /> + </p> + + <edit-form-buttons-stub + issuabledisplayname="merge request" + /> +</div> +`; diff --git a/spec/frontend/sidebar/lock/constants.js b/spec/frontend/sidebar/lock/constants.js new file mode 100644 index 00000000000..b9f08e9286d --- /dev/null +++ b/spec/frontend/sidebar/lock/constants.js @@ -0,0 +1,2 @@ +export const ISSUABLE_TYPE_ISSUE = 'issue'; +export const ISSUABLE_TYPE_MR = 'merge request'; diff --git a/spec/frontend/sidebar/lock/edit_form_buttons_spec.js b/spec/frontend/sidebar/lock/edit_form_buttons_spec.js index 66f9237ce97..de1da3456f8 100644 --- a/spec/frontend/sidebar/lock/edit_form_buttons_spec.js +++ b/spec/frontend/sidebar/lock/edit_form_buttons_spec.js @@ -1,31 +1,178 @@ import { shallowMount } from '@vue/test-utils'; +import { GlLoadingIcon } from '@gitlab/ui'; import EditFormButtons from '~/sidebar/components/lock/edit_form_buttons.vue'; +import eventHub from '~/sidebar/event_hub'; +import { deprecatedCreateFlash as flash } from '~/flash'; +import createStore from '~/notes/stores'; +import { createStore as createMrStore } from '~/mr_notes/stores'; +import { ISSUABLE_TYPE_ISSUE, ISSUABLE_TYPE_MR } from './constants'; + +jest.mock('~/sidebar/event_hub', () => ({ $emit: jest.fn() })); +jest.mock('~/flash'); describe('EditFormButtons', () => { let wrapper; + let store; + let issuableType; + let issuableDisplayName; + + const setIssuableType = pageType => { + issuableType = pageType; + issuableDisplayName = issuableType.replace(/_/g, ' '); + }; + + const findLockToggle = () => wrapper.find('[data-testid="lock-toggle"]'); + const findGlLoadingIcon = () => wrapper.find(GlLoadingIcon); - const mountComponent = propsData => shallowMount(EditFormButtons, { propsData }); + const createComponent = ({ props = {}, data = {}, resolved = true }) => { + store = issuableType === ISSUABLE_TYPE_ISSUE ? createStore() : createMrStore(); + + if (resolved) { + jest.spyOn(store, 'dispatch').mockResolvedValue(); + } else { + jest.spyOn(store, 'dispatch').mockRejectedValue(); + } + + wrapper = shallowMount(EditFormButtons, { + store, + provide: { + fullPath: '', + }, + propsData: { + isLocked: false, + issuableDisplayName, + ...props, + }, + data() { + return { + isLoading: false, + ...data, + }; + }, + }); + }; afterEach(() => { wrapper.destroy(); wrapper = null; }); - it('displays "Unlock" when locked', () => { - wrapper = mountComponent({ - isLocked: true, - updateLockedAttribute: () => {}, + describe.each` + pageType + ${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR} + `('In $pageType page', ({ pageType }) => { + beforeEach(() => { + setIssuableType(pageType); }); - expect(wrapper.text()).toContain('Unlock'); - }); + describe('when isLoading', () => { + beforeEach(() => { + createComponent({ data: { isLoading: true } }); + }); + + it('renders "Applying" in the toggle button', () => { + expect(findLockToggle().text()).toBe('Applying'); + }); + + it('disables the toggle button', () => { + expect(findLockToggle().attributes('disabled')).toBe('disabled'); + }); - it('displays "Lock" when unlocked', () => { - wrapper = mountComponent({ - isLocked: false, - updateLockedAttribute: () => {}, + it('displays the GlLoadingIcon', () => { + expect(findGlLoadingIcon().exists()).toBe(true); + }); }); - expect(wrapper.text()).toContain('Lock'); + describe.each` + isLocked | toggleText | statusText + ${false} | ${'Lock'} | ${'unlocked'} + ${true} | ${'Unlock'} | ${'locked'} + `('when $statusText', ({ isLocked, toggleText }) => { + beforeEach(() => { + createComponent({ + props: { + isLocked, + }, + }); + }); + + it(`toggle button displays "${toggleText}"`, () => { + expect(findLockToggle().text()).toContain(toggleText); + }); + + describe('when toggled', () => { + describe(`when resolved`, () => { + beforeEach(() => { + createComponent({ + props: { + isLocked, + }, + resolved: true, + }); + findLockToggle().trigger('click'); + }); + + it('dispatches the correct action', () => { + expect(store.dispatch).toHaveBeenCalledWith('updateLockedAttribute', { + locked: !isLocked, + fullPath: '', + }); + }); + + it('resets loading', async () => { + await wrapper.vm.$nextTick().then(() => { + expect(findGlLoadingIcon().exists()).toBe(false); + }); + }); + + it('emits close form', () => { + return wrapper.vm.$nextTick().then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('closeLockForm'); + }); + }); + + it('does not flash an error message', () => { + expect(flash).not.toHaveBeenCalled(); + }); + }); + + describe(`when not resolved`, () => { + beforeEach(() => { + createComponent({ + props: { + isLocked, + }, + resolved: false, + }); + findLockToggle().trigger('click'); + }); + + it('dispatches the correct action', () => { + expect(store.dispatch).toHaveBeenCalledWith('updateLockedAttribute', { + locked: !isLocked, + fullPath: '', + }); + }); + + it('resets loading', async () => { + await wrapper.vm.$nextTick().then(() => { + expect(findGlLoadingIcon().exists()).toBe(false); + }); + }); + + it('emits close form', () => { + return wrapper.vm.$nextTick().then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('closeLockForm'); + }); + }); + + it('calls flash with the correct message', () => { + expect(flash).toHaveBeenCalledWith( + `Something went wrong trying to change the locked state of this ${issuableDisplayName}`, + ); + }); + }); + }); + }); }); }); diff --git a/spec/frontend/sidebar/lock/edit_form_spec.js b/spec/frontend/sidebar/lock/edit_form_spec.js index ec10a999a40..b1c3bfe3ef5 100644 --- a/spec/frontend/sidebar/lock/edit_form_spec.js +++ b/spec/frontend/sidebar/lock/edit_form_spec.js @@ -1,37 +1,54 @@ -import Vue from 'vue'; -import editForm from '~/sidebar/components/lock/edit_form.vue'; +import { shallowMount } from '@vue/test-utils'; +import EditForm from '~/sidebar/components/lock/edit_form.vue'; +import { ISSUABLE_TYPE_ISSUE, ISSUABLE_TYPE_MR } from './constants'; -describe('EditForm', () => { - let vm1; - let vm2; +describe('Edit Form Dropdown', () => { + let wrapper; + let issuableType; // Either ISSUABLE_TYPE_ISSUE or ISSUABLE_TYPE_MR + let issuableDisplayName; - beforeEach(() => { - const Component = Vue.extend(editForm); - const toggleForm = () => {}; - const updateLockedAttribute = () => {}; + const setIssuableType = pageType => { + issuableType = pageType; + issuableDisplayName = issuableType.replace(/_/g, ' '); + }; - vm1 = new Component({ - propsData: { - isLocked: true, - toggleForm, - updateLockedAttribute, - issuableType: 'issue', - }, - }).$mount(); + const findWarningText = () => wrapper.find('[data-testid="warning-text"]'); - vm2 = new Component({ + const createComponent = ({ props }) => { + wrapper = shallowMount(EditForm, { propsData: { isLocked: false, - toggleForm, - updateLockedAttribute, - issuableType: 'merge_request', + issuableDisplayName, + ...props, }, - }).$mount(); + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; }); - it('renders on the appropriate warning text', () => { - expect(vm1.$el.innerHTML.includes('Unlock this issue?')).toBe(true); + describe.each` + pageType + ${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR} + `('In $pageType page', ({ pageType }) => { + beforeEach(() => { + setIssuableType(pageType); + }); + + describe.each` + isLocked | lockStatusText + ${false} | ${'unlocked'} + ${true} | ${'locked'} + `('when $lockStatusText', ({ isLocked }) => { + beforeEach(() => { + createComponent({ props: { isLocked } }); + }); - expect(vm2.$el.innerHTML.includes('Lock this merge request?')).toBe(true); + it(`the appropriate warning text is rendered`, () => { + expect(findWarningText().element).toMatchSnapshot(); + }); + }); }); }); diff --git a/spec/frontend/sidebar/lock/issuable_lock_form_spec.js b/spec/frontend/sidebar/lock/issuable_lock_form_spec.js new file mode 100644 index 00000000000..ab1423a9bbb --- /dev/null +++ b/spec/frontend/sidebar/lock/issuable_lock_form_spec.js @@ -0,0 +1,133 @@ +import { shallowMount } from '@vue/test-utils'; +import { mockTracking, triggerEvent } from 'helpers/tracking_helper'; +import IssuableLockForm from '~/sidebar/components/lock/issuable_lock_form.vue'; +import EditForm from '~/sidebar/components/lock/edit_form.vue'; +import createStore from '~/notes/stores'; +import { createStore as createMrStore } from '~/mr_notes/stores'; +import { ISSUABLE_TYPE_ISSUE, ISSUABLE_TYPE_MR } from './constants'; + +describe('IssuableLockForm', () => { + let wrapper; + let store; + let issuableType; // Either ISSUABLE_TYPE_ISSUE or ISSUABLE_TYPE_MR + + const setIssuableType = pageType => { + issuableType = pageType; + }; + + const findSidebarCollapseIcon = () => wrapper.find('[data-testid="sidebar-collapse-icon"]'); + const findLockStatus = () => wrapper.find('[data-testid="lock-status"]'); + const findEditLink = () => wrapper.find('[data-testid="edit-link"]'); + const findEditForm = () => wrapper.find(EditForm); + + const initStore = isLocked => { + if (issuableType === ISSUABLE_TYPE_ISSUE) { + store = createStore(); + store.getters.getNoteableData.targetType = 'issue'; + } else { + store = createMrStore(); + } + store.getters.getNoteableData.discussion_locked = isLocked; + }; + + const createComponent = ({ props = {} }) => { + wrapper = shallowMount(IssuableLockForm, { + store, + propsData: { + isEditable: true, + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe.each` + pageType + ${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR} + `('In $pageType page', ({ pageType }) => { + beforeEach(() => { + setIssuableType(pageType); + }); + + describe.each` + isLocked + ${false} | ${true} + `(`renders for isLocked = $isLocked`, ({ isLocked }) => { + beforeEach(() => { + initStore(isLocked); + createComponent({}); + }); + + it('shows the lock status', () => { + expect(findLockStatus().text()).toBe(isLocked ? 'Locked' : 'Unlocked'); + }); + + describe('edit form', () => { + let isEditable; + beforeEach(() => { + isEditable = false; + createComponent({ props: { isEditable } }); + }); + + describe('when not editable', () => { + it('does not display the edit form when opened if not editable', () => { + expect(findEditForm().exists()).toBe(false); + findSidebarCollapseIcon().trigger('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(findEditForm().exists()).toBe(false); + }); + }); + }); + + describe('when editable', () => { + beforeEach(() => { + isEditable = true; + createComponent({ props: { isEditable } }); + }); + + it('shows the editable status', () => { + expect(findEditLink().exists()).toBe(isEditable); + expect(findEditLink().text()).toBe('Edit'); + }); + + describe("when 'Edit' is clicked", () => { + it('displays the edit form when editable', () => { + expect(findEditForm().exists()).toBe(false); + findEditLink().trigger('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(findEditForm().exists()).toBe(true); + }); + }); + + it('tracks the event ', () => { + const spy = mockTracking('_category_', wrapper.element, jest.spyOn); + triggerEvent(findEditLink().element); + + expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', { + label: 'right_sidebar', + property: 'lock_issue', + }); + }); + }); + + describe('When sidebar is collapsed', () => { + it('displays the edit form when opened', () => { + expect(findEditForm().exists()).toBe(false); + findSidebarCollapseIcon().trigger('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(findEditForm().exists()).toBe(true); + }); + }); + }); + }); + }); + }); + }); +}); diff --git a/spec/frontend/sidebar/lock/lock_issue_sidebar_spec.js b/spec/frontend/sidebar/lock/lock_issue_sidebar_spec.js deleted file mode 100644 index 00997326d87..00000000000 --- a/spec/frontend/sidebar/lock/lock_issue_sidebar_spec.js +++ /dev/null @@ -1,99 +0,0 @@ -import Vue from 'vue'; -import { mockTracking, triggerEvent } from 'helpers/tracking_helper'; -import lockIssueSidebar from '~/sidebar/components/lock/lock_issue_sidebar.vue'; - -describe('LockIssueSidebar', () => { - let vm1; - let vm2; - - beforeEach(() => { - const Component = Vue.extend(lockIssueSidebar); - - const mediator = { - service: { - update: Promise.resolve(true), - }, - - store: { - isLockDialogOpen: false, - }, - }; - - vm1 = new Component({ - propsData: { - isLocked: true, - isEditable: true, - mediator, - issuableType: 'issue', - }, - }).$mount(); - - vm2 = new Component({ - propsData: { - isLocked: false, - isEditable: false, - mediator, - issuableType: 'merge_request', - }, - }).$mount(); - }); - - it('shows if locked and/or editable', () => { - expect(vm1.$el.innerHTML.includes('Edit')).toBe(true); - - expect(vm1.$el.innerHTML.includes('Locked')).toBe(true); - - expect(vm2.$el.innerHTML.includes('Unlocked')).toBe(true); - }); - - it('displays the edit form when editable', done => { - expect(vm1.isLockDialogOpen).toBe(false); - - vm1.$el.querySelector('.lock-edit').click(); - - expect(vm1.isLockDialogOpen).toBe(true); - - vm1.$nextTick(() => { - expect(vm1.$el.innerHTML.includes('Unlock this issue?')).toBe(true); - - done(); - }); - }); - - it('tracks an event when "Edit" is clicked', () => { - const spy = mockTracking('_category_', vm1.$el, jest.spyOn); - triggerEvent('.lock-edit'); - - expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', { - label: 'right_sidebar', - property: 'lock_issue', - }); - }); - - it('displays the edit form when opened from collapsed state', done => { - expect(vm1.isLockDialogOpen).toBe(false); - - vm1.$el.querySelector('.sidebar-collapsed-icon').click(); - - expect(vm1.isLockDialogOpen).toBe(true); - - setImmediate(() => { - expect(vm1.$el.innerHTML.includes('Unlock this issue?')).toBe(true); - - done(); - }); - }); - - it('does not display the edit form when opened from collapsed state if not editable', done => { - expect(vm2.isLockDialogOpen).toBe(false); - - vm2.$el.querySelector('.sidebar-collapsed-icon').click(); - - Vue.nextTick() - .then(() => { - expect(vm2.isLockDialogOpen).toBe(false); - }) - .then(done) - .catch(done.fail); - }); -}); |