diff options
Diffstat (limited to 'spec/frontend/sidebar')
12 files changed, 552 insertions, 276 deletions
diff --git a/spec/frontend/sidebar/__snapshots__/confidential_issue_sidebar_spec.js.snap b/spec/frontend/sidebar/__snapshots__/confidential_issue_sidebar_spec.js.snap index da571af3a0d..4c1ab4a499c 100644 --- a/spec/frontend/sidebar/__snapshots__/confidential_issue_sidebar_spec.js.snap +++ b/spec/frontend/sidebar/__snapshots__/confidential_issue_sidebar_spec.js.snap @@ -49,8 +49,6 @@ exports[`Confidential Issue Sidebar Block renders for confidential = false and i </div> </div> - - <!----> </div> `; @@ -111,8 +109,6 @@ exports[`Confidential Issue Sidebar Block renders for confidential = false and i </div> </div> - - <!----> </div> `; @@ -164,8 +160,6 @@ exports[`Confidential Issue Sidebar Block renders for confidential = true and is </div> </div> - - <!----> </div> `; @@ -225,7 +219,5 @@ exports[`Confidential Issue Sidebar Block renders for confidential = true and is </div> </div> - - <!----> </div> `; diff --git a/spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap b/spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap new file mode 100644 index 00000000000..d33f6c7f389 --- /dev/null +++ b/spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Edit Form Dropdown when confidential renders on or off text based on confidentiality 1`] = ` +<div + class="dropdown show" + toggleform="function () {}" + updateconfidentialattribute="function () {}" +> + <div + class="dropdown-menu sidebar-item-warning-message" + > + <div> + <p> + <gl-sprintf-stub + message="You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}." + /> + </p> + + <edit-form-buttons-stub + confidential="true" + fullpath="" + /> + </div> + </div> +</div> +`; + +exports[`Edit Form Dropdown when not confidential renders "You are going to turn on the confidentiality." in the 1`] = ` +<div + class="dropdown show" + toggleform="function () {}" + updateconfidentialattribute="function () {}" +> + <div + class="dropdown-menu sidebar-item-warning-message" + > + <div> + <p> + <gl-sprintf-stub + message="You are going to turn on the confidentiality. This means that only team members with %{strongStart}at least Reporter access%{strongEnd} are able to see and leave comments on the %{issuableType}." + /> + </p> + + <edit-form-buttons-stub + fullpath="" + /> + </div> + </div> +</div> +`; diff --git a/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js b/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js index 15493d3087f..2f11c6a07c2 100644 --- a/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js +++ b/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js @@ -1,10 +1,10 @@ import { shallowMount } from '@vue/test-utils'; import { GlLoadingIcon } from '@gitlab/ui'; +import waitForPromises from 'helpers/wait_for_promises'; import EditFormButtons from '~/sidebar/components/confidential/edit_form_buttons.vue'; import eventHub from '~/sidebar/event_hub'; import createStore from '~/notes/stores'; -import waitForPromises from 'helpers/wait_for_promises'; -import flash from '~/flash'; +import { deprecatedCreateFlash as flash } from '~/flash'; jest.mock('~/sidebar/event_hub', () => ({ $emit: jest.fn() })); jest.mock('~/flash'); @@ -14,12 +14,7 @@ describe('Edit Form Buttons', () => { let store; const findConfidentialToggle = () => wrapper.find('[data-testid="confidential-toggle"]'); - const createComponent = ({ - props = {}, - data = {}, - confidentialApolloSidebar = false, - resolved = true, - }) => { + const createComponent = ({ props = {}, data = {}, resolved = true }) => { store = createStore(); if (resolved) { jest.spyOn(store, 'dispatch').mockResolvedValue(); @@ -38,11 +33,6 @@ describe('Edit Form Buttons', () => { ...data, }; }, - provide: { - glFeatures: { - confidentialApolloSidebar, - }, - }, store, }); }; @@ -54,9 +44,11 @@ describe('Edit Form Buttons', () => { describe('when isLoading', () => { beforeEach(() => { - createComponent({}); - - wrapper.vm.$store.state.noteableData.confidential = false; + createComponent({ + props: { + confidential: false, + }, + }); }); it('renders "Applying" in the toggle button', () => { @@ -78,6 +70,9 @@ describe('Edit Form Buttons', () => { data: { isLoading: false, }, + props: { + confidential: false, + }, }); expect(findConfidentialToggle().text()).toBe('Turn On'); @@ -90,70 +85,63 @@ describe('Edit Form Buttons', () => { data: { isLoading: false, }, + props: { + confidential: true, + }, }); - - wrapper.vm.$store.state.noteableData.confidential = true; }); it('renders on or off text based on confidentiality', () => { expect(findConfidentialToggle().text()).toBe('Turn Off'); }); - - describe('when clicking on the confidential toggle', () => { - it('emits updateConfidentialAttribute', () => { - findConfidentialToggle().trigger('click'); - - expect(eventHub.$emit).toHaveBeenCalledWith('updateConfidentialAttribute'); - }); - }); }); - describe('when confidentialApolloSidebar is turned on', () => { - const isConfidential = true; + describe('when succeeds', () => { + beforeEach(() => { + createComponent({ data: { isLoading: false }, props: { confidential: true } }); + findConfidentialToggle().trigger('click'); + }); - describe('when succeeds', () => { - beforeEach(() => { - createComponent({ data: { isLoading: false }, confidentialApolloSidebar: true }); - wrapper.vm.$store.state.noteableData.confidential = isConfidential; - findConfidentialToggle().trigger('click'); + it('dispatches the correct action', () => { + expect(store.dispatch).toHaveBeenCalledWith('updateConfidentialityOnIssuable', { + confidential: false, + fullPath: '', }); + }); - it('dispatches the correct action', () => { - expect(store.dispatch).toHaveBeenCalledWith('updateConfidentialityOnIssue', { - confidential: !isConfidential, - fullPath: '', - }); + it('resets loading', () => { + return waitForPromises().then(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); }); + }); - it('resets loading', () => { - return waitForPromises().then(() => { - expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); - }); + it('emits close form', () => { + return waitForPromises().then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('closeConfidentialityForm'); }); + }); - it('emits close form', () => { - return waitForPromises().then(() => { - expect(eventHub.$emit).toHaveBeenCalledWith('closeConfidentialityForm'); - }); + it('emits updateOnConfidentiality event', () => { + return waitForPromises().then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('updateIssuableConfidentiality', false); }); }); + }); - describe('when fails', () => { - beforeEach(() => { - createComponent({ - data: { isLoading: false }, - confidentialApolloSidebar: true, - resolved: false, - }); - wrapper.vm.$store.state.noteableData.confidential = isConfidential; - findConfidentialToggle().trigger('click'); + describe('when fails', () => { + beforeEach(() => { + createComponent({ + data: { isLoading: false }, + props: { confidential: true }, + resolved: false, }); + findConfidentialToggle().trigger('click'); + }); - it('calls flash with the correct message', () => { - expect(flash).toHaveBeenCalledWith( - 'Something went wrong trying to change the confidentiality of this issue', - ); - }); + it('calls flash with the correct message', () => { + expect(flash).toHaveBeenCalledWith( + 'Something went wrong trying to change the confidentiality of this issue', + ); }); }); }); diff --git a/spec/frontend/sidebar/confidential/edit_form_spec.js b/spec/frontend/sidebar/confidential/edit_form_spec.js index a22bbe5ae0d..56f163eecd1 100644 --- a/spec/frontend/sidebar/confidential/edit_form_spec.js +++ b/spec/frontend/sidebar/confidential/edit_form_spec.js @@ -12,6 +12,7 @@ describe('Edit Form Dropdown', () => { ...props, isLoading: false, fullPath: '', + issuableType: 'issue', }, }); }; @@ -22,26 +23,26 @@ describe('Edit Form Dropdown', () => { }); describe('when not confidential', () => { - it('renders "You are going to turn off the confidentiality." in the ', () => { + it('renders "You are going to turn on the confidentiality." in the ', () => { createComponent({ - isConfidential: false, + confidential: false, toggleForm, updateConfidentialAttribute, }); - expect(wrapper.find('p').text()).toContain('You are going to turn on the confidentiality.'); + expect(wrapper.element).toMatchSnapshot(); }); }); describe('when confidential', () => { it('renders on or off text based on confidentiality', () => { createComponent({ - isConfidential: true, + confidential: true, toggleForm, updateConfidentialAttribute, }); - expect(wrapper.find('p').text()).toContain('You are going to turn off the confidentiality.'); + expect(wrapper.element).toMatchSnapshot(); }); }); }); diff --git a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js index 06cf1e6166c..bc2df9305d0 100644 --- a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js +++ b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js @@ -1,13 +1,10 @@ import { shallowMount } from '@vue/test-utils'; import { mockTracking, triggerEvent } from 'helpers/tracking_helper'; +import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import ConfidentialIssueSidebar from '~/sidebar/components/confidential/confidential_issue_sidebar.vue'; import EditForm from '~/sidebar/components/confidential/edit_form.vue'; -import SidebarService from '~/sidebar/services/sidebar_service'; -import createFlash from '~/flash'; -import RecaptchaModal from '~/vue_shared/components/recaptcha_modal.vue'; import createStore from '~/notes/stores'; -import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; -import eventHub from '~/sidebar/event_hub'; +import * as types from '~/notes/stores/mutation_types'; jest.mock('~/flash'); jest.mock('~/sidebar/services/sidebar_service'); @@ -20,32 +17,14 @@ describe('Confidential Issue Sidebar Block', () => { .fn() .mockResolvedValue({ data: { issueSetConfidential: { issue: { confidential: true } } } }); - const findRecaptchaModal = () => wrapper.find(RecaptchaModal); - - const triggerUpdateConfidentialAttribute = () => { - wrapper.setData({ edit: true }); - return ( - // wait for edit form to become visible - wrapper.vm - .$nextTick() - .then(() => { - eventHub.$emit('updateConfidentialAttribute'); - }) - // wait for reCAPTCHA modal to render - .then(() => wrapper.vm.$nextTick()) - ); - }; - const createComponent = ({ propsData, data = {} }) => { const store = createStore(); - const service = new SidebarService(); wrapper = shallowMount(ConfidentialIssueSidebar, { store, data() { return data; }, propsData: { - service, iid: '', fullPath: '', ...propsData, @@ -133,61 +112,48 @@ describe('Confidential Issue Sidebar Block', () => { property: 'confidentiality', }); }); - - describe('for successful update', () => { - beforeEach(() => { - SidebarService.prototype.update.mockResolvedValue({ data: 'irrelevant' }); + }); + describe('computed confidential', () => { + beforeEach(() => { + createComponent({ + propsData: { + isEditable: true, + }, }); + }); - it('reloads the page', () => - triggerUpdateConfidentialAttribute().then(() => { - expect(window.location.reload).toHaveBeenCalled(); - })); + it('returns false when noteableData is not present', () => { + wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, null); - it('does not show an error message', () => - triggerUpdateConfidentialAttribute().then(() => { - expect(createFlash).not.toHaveBeenCalled(); - })); + expect(wrapper.vm.confidential).toBe(false); }); - describe('for update error', () => { - beforeEach(() => { - SidebarService.prototype.update.mockRejectedValue(new Error('updating failed!')); - }); - - it('does not reload the page', () => - triggerUpdateConfidentialAttribute().then(() => { - expect(window.location.reload).not.toHaveBeenCalled(); - })); + it('returns true when noteableData has confidential attr as true', () => { + wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, {}); + wrapper.vm.$store.commit(types.SET_ISSUE_CONFIDENTIAL, true); - it('shows an error message', () => - triggerUpdateConfidentialAttribute().then(() => { - expect(createFlash).toHaveBeenCalled(); - })); + expect(wrapper.vm.confidential).toBe(true); }); - describe('for spam error', () => { - beforeEach(() => { - SidebarService.prototype.update.mockRejectedValue({ name: 'SpamError' }); - }); + it('returns false when noteableData has confidential attr as false', () => { + wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, {}); + wrapper.vm.$store.commit(types.SET_ISSUE_CONFIDENTIAL, false); + + expect(wrapper.vm.confidential).toBe(false); + }); - it('does not reload the page', () => - triggerUpdateConfidentialAttribute().then(() => { - expect(window.location.reload).not.toHaveBeenCalled(); - })); + it('returns true when confidential attr is true', () => { + wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, {}); + wrapper.vm.$store.commit(types.SET_ISSUE_CONFIDENTIAL, true); - it('does not show an error message', () => - triggerUpdateConfidentialAttribute().then(() => { - expect(createFlash).not.toHaveBeenCalled(); - })); + expect(wrapper.vm.confidential).toBe(true); + }); - it('shows a reCAPTCHA modal', () => { - expect(findRecaptchaModal().exists()).toBe(false); + it('returns false when confidential attr is false', () => { + wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, {}); + wrapper.vm.$store.commit(types.SET_ISSUE_CONFIDENTIAL, false); - return triggerUpdateConfidentialAttribute().then(() => { - expect(findRecaptchaModal().exists()).toBe(true); - }); - }); + expect(wrapper.vm.confidential).toBe(false); }); }); }); 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); - }); -}); diff --git a/spec/frontend/sidebar/todo_spec.js b/spec/frontend/sidebar/todo_spec.js index 18b621cd12d..e56a78989eb 100644 --- a/spec/frontend/sidebar/todo_spec.js +++ b/spec/frontend/sidebar/todo_spec.js @@ -36,7 +36,7 @@ describe('SidebarTodo', () => { it.each` isTodo | iconClass | label | icon - ${false} | ${''} | ${'Add a To Do'} | ${'todo-add'} + ${false} | ${''} | ${'Add a To-Do'} | ${'todo-add'} ${true} | ${'todo-undone'} | ${'Mark as done'} | ${'todo-done'} `( 'renders proper button when `isTodo` prop is `$isTodo`', |