Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/sidebar')
-rw-r--r--spec/frontend/sidebar/__snapshots__/confidential_issue_sidebar_spec.js.snap199
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js71
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js173
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js159
-rw-r--r--spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js93
-rw-r--r--spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js18
-rw-r--r--spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap50
-rw-r--r--spec/frontend/sidebar/confidential/edit_form_buttons_spec.js146
-rw-r--r--spec/frontend/sidebar/confidential/edit_form_spec.js48
-rw-r--r--spec/frontend/sidebar/confidential_issue_sidebar_spec.js159
-rw-r--r--spec/frontend/sidebar/mock_data.js25
-rw-r--r--spec/frontend/sidebar/subscriptions_spec.js9
-rw-r--r--spec/frontend/sidebar/user_data_mock.js1
13 files changed, 546 insertions, 605 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
deleted file mode 100644
index 2367667544d..00000000000
--- a/spec/frontend/sidebar/__snapshots__/confidential_issue_sidebar_spec.js.snap
+++ /dev/null
@@ -1,199 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Confidential Issue Sidebar Block renders for confidential = false and isEditable = false 1`] = `
-<div
- class="block issuable-sidebar-item confidentiality"
- iid=""
->
- <div
- class="sidebar-collapsed-icon"
- title="Not confidential"
- >
- <gl-icon-stub
- name="eye"
- size="16"
- />
- </div>
-
- <div
- class="title hide-collapsed"
- >
-
- Confidentiality
-
- <!---->
- </div>
-
- <div
- class="value sidebar-item-value hide-collapsed"
- >
- <!---->
-
- <div
- class="no-value sidebar-item-value"
- data-testid="not-confidential"
- >
- <gl-icon-stub
- class="sidebar-item-icon inline"
- name="eye"
- size="16"
- />
-
- Not confidential
-
- </div>
- </div>
-</div>
-`;
-
-exports[`Confidential Issue Sidebar Block renders for confidential = false and isEditable = true 1`] = `
-<div
- class="block issuable-sidebar-item confidentiality"
- iid=""
->
- <div
- class="sidebar-collapsed-icon"
- title="Not confidential"
- >
- <gl-icon-stub
- name="eye"
- size="16"
- />
- </div>
-
- <div
- class="title hide-collapsed"
- >
-
- Confidentiality
-
- <a
- class="float-right confidential-edit"
- data-track-event="click_edit_button"
- data-track-label="right_sidebar"
- data-track-property="confidentiality"
- href="#"
- >
- Edit
- </a>
- </div>
-
- <div
- class="value sidebar-item-value hide-collapsed"
- >
- <!---->
-
- <div
- class="no-value sidebar-item-value"
- data-testid="not-confidential"
- >
- <gl-icon-stub
- class="sidebar-item-icon inline"
- name="eye"
- size="16"
- />
-
- Not confidential
-
- </div>
- </div>
-</div>
-`;
-
-exports[`Confidential Issue Sidebar Block renders for confidential = true and isEditable = false 1`] = `
-<div
- class="block issuable-sidebar-item confidentiality"
- iid=""
->
- <div
- class="sidebar-collapsed-icon"
- title="Confidential"
- >
- <gl-icon-stub
- name="eye-slash"
- size="16"
- />
- </div>
-
- <div
- class="title hide-collapsed"
- >
-
- Confidentiality
-
- <!---->
- </div>
-
- <div
- class="value sidebar-item-value hide-collapsed"
- >
- <!---->
-
- <div
- class="value sidebar-item-value hide-collapsed"
- >
- <gl-icon-stub
- class="sidebar-item-icon inline is-active"
- name="eye-slash"
- size="16"
- />
-
- This issue is confidential
-
- </div>
- </div>
-</div>
-`;
-
-exports[`Confidential Issue Sidebar Block renders for confidential = true and isEditable = true 1`] = `
-<div
- class="block issuable-sidebar-item confidentiality"
- iid=""
->
- <div
- class="sidebar-collapsed-icon"
- title="Confidential"
- >
- <gl-icon-stub
- name="eye-slash"
- size="16"
- />
- </div>
-
- <div
- class="title hide-collapsed"
- >
-
- Confidentiality
-
- <a
- class="float-right confidential-edit"
- data-track-event="click_edit_button"
- data-track-label="right_sidebar"
- data-track-property="confidentiality"
- href="#"
- >
- Edit
- </a>
- </div>
-
- <div
- class="value sidebar-item-value hide-collapsed"
- >
- <!---->
-
- <div
- class="value sidebar-item-value hide-collapsed"
- >
- <gl-icon-stub
- class="sidebar-item-icon inline is-active"
- name="eye-slash"
- size="16"
- />
-
- This issue is confidential
-
- </div>
- </div>
-</div>
-`;
diff --git a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js
new file mode 100644
index 00000000000..8844e1626cd
--- /dev/null
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js
@@ -0,0 +1,71 @@
+import { GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import SidebarConfidentialityContent from '~/sidebar/components/confidential/sidebar_confidentiality_content.vue';
+
+describe('Sidebar Confidentiality Content', () => {
+ let wrapper;
+
+ const findIcon = () => wrapper.findComponent(GlIcon);
+ const findText = () => wrapper.find('[data-testid="confidential-text"]');
+ const findCollapsedIcon = () => wrapper.find('[data-testid="sidebar-collapsed-icon"]');
+
+ const createComponent = ({ confidential = false, issuableType = 'issue' } = {}) => {
+ wrapper = shallowMount(SidebarConfidentialityContent, {
+ propsData: {
+ confidential,
+ issuableType,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('emits `expandSidebar` event on collapsed icon click', () => {
+ createComponent();
+ findCollapsedIcon().trigger('click');
+
+ expect(wrapper.emitted('expandSidebar')).toHaveLength(1);
+ });
+
+ describe('when issue is non-confidential', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders a non-confidential icon', () => {
+ expect(findIcon().props('name')).toBe('eye');
+ });
+
+ it('does not add `is-active` class to the icon', () => {
+ expect(findIcon().classes()).not.toContain('is-active');
+ });
+
+ it('displays a non-confidential text', () => {
+ expect(findText().text()).toBe('Not confidential');
+ });
+ });
+
+ describe('when issue is confidential', () => {
+ it('renders a confidential icon', () => {
+ createComponent({ confidential: true });
+ expect(findIcon().props('name')).toBe('eye-slash');
+ });
+
+ it('adds `is-active` class to the icon', () => {
+ createComponent({ confidential: true });
+ expect(findIcon().classes()).toContain('is-active');
+ });
+
+ it('displays a correct confidential text for issue', () => {
+ createComponent({ confidential: true });
+ expect(findText().text()).toBe('This issue is confidential');
+ });
+
+ it('displays a correct confidential text for epic', () => {
+ createComponent({ confidential: true, issuableType: 'epic' });
+ expect(findText().text()).toBe('This epic is confidential');
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
new file mode 100644
index 00000000000..d5e6310ed38
--- /dev/null
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
@@ -0,0 +1,173 @@
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import createFlash from '~/flash';
+import SidebarConfidentialityForm from '~/sidebar/components/confidential/sidebar_confidentiality_form.vue';
+import { confidentialityQueries } from '~/sidebar/constants';
+
+jest.mock('~/flash');
+
+describe('Sidebar Confidentiality Form', () => {
+ let wrapper;
+
+ const findWarningMessage = () => wrapper.find(`[data-testid="warning-message"]`);
+ const findConfidentialToggle = () => wrapper.find(`[data-testid="confidential-toggle"]`);
+ const findCancelButton = () => wrapper.find(`[data-testid="confidential-cancel"]`);
+
+ const createComponent = ({
+ props = {},
+ mutate = jest.fn().mockResolvedValue('Success'),
+ } = {}) => {
+ wrapper = shallowMount(SidebarConfidentialityForm, {
+ provide: {
+ fullPath: 'group/project',
+ iid: '1',
+ },
+ propsData: {
+ confidential: false,
+ issuableType: 'issue',
+ ...props,
+ },
+ mocks: {
+ $apollo: {
+ mutate,
+ },
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('emits a `closeForm` event when Cancel button is clicked', () => {
+ createComponent();
+ findCancelButton().vm.$emit('click');
+
+ expect(wrapper.emitted().closeForm).toHaveLength(1);
+ });
+
+ it('renders a loading state after clicking on turn on/off button', async () => {
+ createComponent();
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled();
+ await nextTick();
+ expect(findConfidentialToggle().props('loading')).toBe(true);
+ });
+
+ it('creates a flash if mutation is rejected', async () => {
+ createComponent({ mutate: jest.fn().mockRejectedValue('Error!') });
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+ await waitForPromises();
+
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'Something went wrong while setting issue confidentiality.',
+ });
+ });
+
+ it('creates a flash if mutation contains errors', async () => {
+ createComponent({
+ mutate: jest.fn().mockResolvedValue({
+ data: { issuableSetConfidential: { errors: ['Houston, we have a problem!'] } },
+ }),
+ });
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+ await waitForPromises();
+
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'Houston, we have a problem!',
+ });
+ });
+
+ describe('when issue is not confidential', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders a message about making an issue confidential', () => {
+ expect(findWarningMessage().text()).toBe(
+ 'You are going to turn on confidentiality. Only team members with at least Reporter access will be able to see and leave comments on the issue.',
+ );
+ });
+
+ it('has a `Turn on` button text', () => {
+ expect(findConfidentialToggle().text()).toBe('Turn on');
+ });
+
+ it('calls a mutation to set confidential to true on button click', () => {
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: confidentialityQueries[wrapper.vm.issuableType].mutation,
+ variables: {
+ input: {
+ confidential: true,
+ iid: '1',
+ projectPath: 'group/project',
+ },
+ },
+ });
+ });
+ });
+
+ describe('when issue is confidential', () => {
+ beforeEach(() => {
+ createComponent({ props: { confidential: true } });
+ });
+
+ it('renders a message about making an issue non-confidential', () => {
+ expect(findWarningMessage().text()).toBe(
+ 'You are going to turn off the confidentiality. This means everyone will be able to see and leave a comment on this issue.',
+ );
+ });
+
+ it('has a `Turn off` button text', () => {
+ expect(findConfidentialToggle().text()).toBe('Turn off');
+ });
+
+ it('calls a mutation to set confidential to false on button click', () => {
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: confidentialityQueries[wrapper.vm.issuableType].mutation,
+ variables: {
+ input: {
+ confidential: false,
+ iid: '1',
+ projectPath: 'group/project',
+ },
+ },
+ });
+ });
+ });
+
+ describe('when issuable type is `epic`', () => {
+ beforeEach(() => {
+ createComponent({ props: { confidential: true, issuableType: 'epic' } });
+ });
+
+ it('renders a message about making an epic non-confidential', () => {
+ expect(findWarningMessage().text()).toBe(
+ 'You are going to turn off the confidentiality. This means everyone will be able to see and leave a comment on this epic.',
+ );
+ });
+
+ it('calls a mutation to set epic confidentiality with correct parameters', () => {
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: confidentialityQueries[wrapper.vm.issuableType].mutation,
+ variables: {
+ input: {
+ confidential: false,
+ iid: '1',
+ groupPath: 'group/project',
+ },
+ },
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js
new file mode 100644
index 00000000000..20a5be9b518
--- /dev/null
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js
@@ -0,0 +1,159 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import createFlash from '~/flash';
+import SidebarConfidentialityContent from '~/sidebar/components/confidential/sidebar_confidentiality_content.vue';
+import SidebarConfidentialityForm from '~/sidebar/components/confidential/sidebar_confidentiality_form.vue';
+import SidebarConfidentialityWidget, {
+ confidentialWidget,
+} from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
+import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
+import issueConfidentialQuery from '~/sidebar/queries/issue_confidential.query.graphql';
+import { issueConfidentialityResponse } from '../../mock_data';
+
+jest.mock('~/flash');
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('Sidebar Confidentiality Widget', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const findEditableItem = () => wrapper.findComponent(SidebarEditableItem);
+ const findConfidentialityForm = () => wrapper.findComponent(SidebarConfidentialityForm);
+ const findConfidentialityContent = () => wrapper.findComponent(SidebarConfidentialityContent);
+
+ const createComponent = ({
+ confidentialQueryHandler = jest.fn().mockResolvedValue(issueConfidentialityResponse()),
+ } = {}) => {
+ fakeApollo = createMockApollo([[issueConfidentialQuery, confidentialQueryHandler]]);
+
+ wrapper = shallowMount(SidebarConfidentialityWidget, {
+ localVue,
+ apolloProvider: fakeApollo,
+ provide: {
+ fullPath: 'group/project',
+ iid: '1',
+ canUpdate: true,
+ },
+ propsData: {
+ issuableType: 'issue',
+ },
+ stubs: {
+ SidebarEditableItem,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ fakeApollo = null;
+ });
+
+ it('passes a `loading` prop as true to editable item when query is loading', () => {
+ createComponent();
+
+ expect(findEditableItem().props('loading')).toBe(true);
+ });
+
+ it('exposes a method via external observable', () => {
+ createComponent();
+
+ expect(confidentialWidget.setConfidentiality).toEqual(wrapper.vm.setConfidentiality);
+ });
+
+ describe('when issue is not confidential', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('passes a `loading` prop as false to editable item', () => {
+ expect(findEditableItem().props('loading')).toBe(false);
+ });
+
+ it('passes false to `confidential` prop of child components', () => {
+ expect(findConfidentialityForm().props('confidential')).toBe(false);
+ expect(findConfidentialityContent().props('confidential')).toBe(false);
+ });
+
+ it('changes confidentiality to true after setConfidentiality is called', async () => {
+ confidentialWidget.setConfidentiality();
+ await nextTick();
+ expect(findConfidentialityForm().props('confidential')).toBe(true);
+ expect(findConfidentialityContent().props('confidential')).toBe(true);
+ });
+
+ it('emits `confidentialityUpdated` event with a `false` payload', () => {
+ expect(wrapper.emitted('confidentialityUpdated')).toEqual([[false]]);
+ });
+ });
+
+ describe('when issue is confidential', () => {
+ beforeEach(async () => {
+ createComponent({
+ confidentialQueryHandler: jest.fn().mockResolvedValue(issueConfidentialityResponse(true)),
+ });
+ await waitForPromises();
+ });
+
+ it('passes a `loading` prop as false to editable item', () => {
+ expect(findEditableItem().props('loading')).toBe(false);
+ });
+
+ it('passes false to `confidential` prop of child components', () => {
+ expect(findConfidentialityForm().props('confidential')).toBe(true);
+ expect(findConfidentialityContent().props('confidential')).toBe(true);
+ });
+
+ it('changes confidentiality to false after setConfidentiality is called', async () => {
+ confidentialWidget.setConfidentiality();
+ await nextTick();
+ expect(findConfidentialityForm().props('confidential')).toBe(false);
+ expect(findConfidentialityContent().props('confidential')).toBe(false);
+ });
+
+ it('emits `confidentialityUpdated` event with a `true` payload', () => {
+ expect(wrapper.emitted('confidentialityUpdated')).toEqual([[true]]);
+ });
+ });
+
+ it('displays a flash message when query is rejected', async () => {
+ createComponent({
+ confidentialQueryHandler: jest.fn().mockRejectedValue('Houston, we have a problem'),
+ });
+ await waitForPromises();
+
+ expect(createFlash).toHaveBeenCalled();
+ });
+
+ it('closes the form and dispatches an event when `closeForm` is emitted', async () => {
+ createComponent();
+ const el = wrapper.vm.$el;
+ jest.spyOn(el, 'dispatchEvent');
+
+ await waitForPromises();
+ wrapper.vm.$refs.editable.expand();
+ await nextTick();
+
+ expect(findConfidentialityForm().isVisible()).toBe(true);
+
+ findConfidentialityForm().vm.$emit('closeForm');
+ await nextTick();
+ expect(findConfidentialityForm().isVisible()).toBe(false);
+
+ expect(el.dispatchEvent).toHaveBeenCalled();
+ expect(wrapper.emitted('closeForm')).toHaveLength(1);
+ });
+
+ it('emits `expandSidebar` event when it is emitted from child component', async () => {
+ createComponent();
+ await waitForPromises();
+ findConfidentialityContent().vm.$emit('expandSidebar');
+
+ expect(wrapper.emitted('expandSidebar')).toHaveLength(1);
+ });
+});
diff --git a/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js b/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js
new file mode 100644
index 00000000000..1dbb7702a15
--- /dev/null
+++ b/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js
@@ -0,0 +1,93 @@
+import { GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { IssuableType } from '~/issue_show/constants';
+import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue';
+import issueReferenceQuery from '~/sidebar/queries/issue_reference.query.graphql';
+import mergeRequestReferenceQuery from '~/sidebar/queries/merge_request_reference.query.graphql';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { issueReferenceResponse } from '../../mock_data';
+
+describe('Sidebar Reference Widget', () => {
+ let wrapper;
+ let fakeApollo;
+ const referenceText = 'reference';
+
+ const createComponent = ({
+ issuableType,
+ referenceQuery = issueReferenceQuery,
+ referenceQueryHandler = jest.fn().mockResolvedValue(issueReferenceResponse(referenceText)),
+ } = {}) => {
+ Vue.use(VueApollo);
+
+ fakeApollo = createMockApollo([[referenceQuery, referenceQueryHandler]]);
+
+ wrapper = shallowMount(SidebarReferenceWidget, {
+ apolloProvider: fakeApollo,
+ provide: {
+ fullPath: 'group/project',
+ iid: '1',
+ },
+ propsData: {
+ issuableType,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe.each([
+ [IssuableType.Issue, issueReferenceQuery],
+ [IssuableType.MergeRequest, mergeRequestReferenceQuery],
+ ])('when issuableType is %s', (issuableType, referenceQuery) => {
+ it('displays the reference text', async () => {
+ createComponent({
+ issuableType,
+ referenceQuery,
+ });
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toContain(referenceText);
+ });
+
+ it('displays loading icon while fetching and hides clipboard icon', async () => {
+ createComponent({
+ issuableType,
+ referenceQuery,
+ });
+
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.find(ClipboardButton).exists()).toBe(false);
+ });
+
+ it('calls createFlash with correct parameters', async () => {
+ const mockError = new Error('mayday');
+
+ createComponent({
+ issuableType,
+ referenceQuery,
+ referenceQueryHandler: jest.fn().mockRejectedValue(mockError),
+ });
+
+ await waitForPromises();
+
+ const [
+ [
+ {
+ message,
+ error: { networkError },
+ },
+ ],
+ ] = wrapper.emitted('fetch-error');
+ expect(message).toBe('An error occurred while fetching reference');
+ expect(networkError).toEqual(mockError);
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
index 7c67149b517..9f6878db785 100644
--- a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
@@ -7,6 +7,8 @@ import userDataMock from '../../user_data_mock';
describe('UncollapsedReviewerList component', () => {
let wrapper;
+ const reviewerApprovalIcons = () => wrapper.findAll('[data-testid="re-approved"]');
+
function createComponent(props = {}) {
const propsData = {
users: [],
@@ -58,19 +60,29 @@ describe('UncollapsedReviewerList component', () => {
const user = userDataMock();
createComponent({
- users: [user, { ...user, id: 2, username: 'hello-world' }],
+ users: [user, { ...user, id: 2, username: 'hello-world', approved: true }],
});
});
- it('only has one user', () => {
+ it('has both users', () => {
expect(wrapper.findAll(ReviewerAvatarLink).length).toBe(2);
});
- it('shows one user with avatar, username and author name', () => {
+ it('shows both users with avatar, username and author name', () => {
expect(wrapper.text()).toContain(`@root`);
expect(wrapper.text()).toContain(`@hello-world`);
});
+ it('renders approval icon', () => {
+ expect(reviewerApprovalIcons().length).toBe(1);
+ });
+
+ it('shows that hello-world approved', () => {
+ const icon = reviewerApprovalIcons().at(0);
+
+ expect(icon.attributes('title')).toEqual('Approved by @hello-world');
+ });
+
it('renders re-request loading icon', async () => {
await wrapper.setData({ loadingStates: { 2: 'loading' } });
diff --git a/spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap b/spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap
deleted file mode 100644
index d33f6c7f389..00000000000
--- a/spec/frontend/sidebar/confidential/__snapshots__/edit_form_spec.js.snap
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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
deleted file mode 100644
index 427e3a89c29..00000000000
--- a/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js
+++ /dev/null
@@ -1,146 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import waitForPromises from 'helpers/wait_for_promises';
-import { deprecatedCreateFlash as flash } from '~/flash';
-import createStore from '~/notes/stores';
-import EditFormButtons from '~/sidebar/components/confidential/edit_form_buttons.vue';
-import eventHub from '~/sidebar/event_hub';
-
-jest.mock('~/sidebar/event_hub', () => ({ $emit: jest.fn() }));
-jest.mock('~/flash');
-
-describe('Edit Form Buttons', () => {
- let wrapper;
- let store;
- const findConfidentialToggle = () => wrapper.find('[data-testid="confidential-toggle"]');
-
- const createComponent = ({ props = {}, data = {}, resolved = true }) => {
- store = createStore();
- if (resolved) {
- jest.spyOn(store, 'dispatch').mockResolvedValue();
- } else {
- jest.spyOn(store, 'dispatch').mockRejectedValue();
- }
-
- wrapper = shallowMount(EditFormButtons, {
- propsData: {
- fullPath: '',
- ...props,
- },
- data() {
- return {
- isLoading: true,
- ...data,
- };
- },
- store,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('when isLoading', () => {
- beforeEach(() => {
- createComponent({
- props: {
- confidential: false,
- },
- });
- });
-
- it('renders "Applying" in the toggle button', () => {
- expect(findConfidentialToggle().text()).toBe('Applying');
- });
-
- it('disables the toggle button', () => {
- expect(findConfidentialToggle().props('disabled')).toBe(true);
- });
-
- it('sets loading on the toggle button', () => {
- expect(findConfidentialToggle().props('loading')).toBe(true);
- });
- });
-
- describe('when not confidential', () => {
- it('renders Turn On in the toggle button', () => {
- createComponent({
- data: {
- isLoading: false,
- },
- props: {
- confidential: false,
- },
- });
-
- expect(findConfidentialToggle().text()).toBe('Turn On');
- });
- });
-
- describe('when confidential', () => {
- beforeEach(() => {
- createComponent({
- data: {
- isLoading: false,
- },
- props: {
- confidential: true,
- },
- });
- });
-
- it('renders on or off text based on confidentiality', () => {
- expect(findConfidentialToggle().text()).toBe('Turn Off');
- });
- });
-
- describe('when succeeds', () => {
- beforeEach(() => {
- createComponent({ data: { isLoading: false }, props: { confidential: true } });
- findConfidentialToggle().vm.$emit('click', new Event('click'));
- });
-
- it('dispatches the correct action', () => {
- expect(store.dispatch).toHaveBeenCalledWith('updateConfidentialityOnIssuable', {
- confidential: false,
- fullPath: '',
- });
- });
-
- it('resets loading on the toggle button', () => {
- return waitForPromises().then(() => {
- expect(findConfidentialToggle().props('loading')).toBe(false);
- });
- });
-
- 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 },
- props: { confidential: true },
- resolved: false,
- });
- findConfidentialToggle().vm.$emit('click', new Event('click'));
- });
-
- 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
deleted file mode 100644
index 6b571df10ae..00000000000
--- a/spec/frontend/sidebar/confidential/edit_form_spec.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import EditForm from '~/sidebar/components/confidential/edit_form.vue';
-
-describe('Edit Form Dropdown', () => {
- let wrapper;
- const toggleForm = () => {};
- const updateConfidentialAttribute = () => {};
-
- const createComponent = (props) => {
- wrapper = shallowMount(EditForm, {
- propsData: {
- ...props,
- isLoading: false,
- fullPath: '',
- issuableType: 'issue',
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('when not confidential', () => {
- it('renders "You are going to turn on the confidentiality." in the ', () => {
- createComponent({
- confidential: false,
- toggleForm,
- updateConfidentialAttribute,
- });
-
- expect(wrapper.element).toMatchSnapshot();
- });
- });
-
- describe('when confidential', () => {
- it('renders on or off text based on confidentiality', () => {
- createComponent({
- confidential: true,
- toggleForm,
- updateConfidentialAttribute,
- });
-
- expect(wrapper.element).toMatchSnapshot();
- });
- });
-});
diff --git a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
deleted file mode 100644
index 93a6401b1fc..00000000000
--- a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
+++ /dev/null
@@ -1,159 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
-import { mockTracking, triggerEvent } from 'helpers/tracking_helper';
-import createStore from '~/notes/stores';
-import * as types from '~/notes/stores/mutation_types';
-import ConfidentialIssueSidebar from '~/sidebar/components/confidential/confidential_issue_sidebar.vue';
-import EditForm from '~/sidebar/components/confidential/edit_form.vue';
-
-jest.mock('~/flash');
-jest.mock('~/sidebar/services/sidebar_service');
-
-describe('Confidential Issue Sidebar Block', () => {
- useMockLocationHelper();
-
- let wrapper;
- const mutate = jest
- .fn()
- .mockResolvedValue({ data: { issueSetConfidential: { issue: { confidential: true } } } });
-
- const createComponent = ({ propsData, data = {} }) => {
- const store = createStore();
- wrapper = shallowMount(ConfidentialIssueSidebar, {
- store,
- data() {
- return data;
- },
- propsData: {
- iid: '',
- fullPath: '',
- ...propsData,
- },
- mocks: {
- $apollo: {
- mutate,
- },
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it.each`
- confidential | isEditable
- ${false} | ${false}
- ${false} | ${true}
- ${true} | ${false}
- ${true} | ${true}
- `(
- 'renders for confidential = $confidential and isEditable = $isEditable',
- ({ confidential, isEditable }) => {
- createComponent({
- propsData: {
- isEditable,
- },
- });
- wrapper.vm.$store.state.noteableData.confidential = confidential;
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.element).toMatchSnapshot();
- });
- },
- );
-
- describe('if editable', () => {
- beforeEach(() => {
- createComponent({
- propsData: {
- isEditable: true,
- },
- });
- wrapper.vm.$store.state.noteableData.confidential = true;
- });
-
- it('displays the edit form when editable', () => {
- wrapper.setData({ edit: false });
-
- return wrapper.vm
- .$nextTick()
- .then(() => {
- wrapper.find({ ref: 'editLink' }).trigger('click');
- return wrapper.vm.$nextTick();
- })
- .then(() => {
- expect(wrapper.find(EditForm).exists()).toBe(true);
- });
- });
-
- it('displays the edit form when opened from collapsed state', () => {
- wrapper.setData({ edit: false });
-
- return wrapper.vm
- .$nextTick()
- .then(() => {
- wrapper.find({ ref: 'collapseIcon' }).trigger('click');
- return wrapper.vm.$nextTick();
- })
- .then(() => {
- expect(wrapper.find(EditForm).exists()).toBe(true);
- });
- });
-
- it('tracks the event when "Edit" is clicked', () => {
- const spy = mockTracking('_category_', wrapper.element, jest.spyOn);
-
- const editLink = wrapper.find({ ref: 'editLink' });
- triggerEvent(editLink.element);
-
- expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
- label: 'right_sidebar',
- property: 'confidentiality',
- });
- });
- });
- describe('computed confidential', () => {
- beforeEach(() => {
- createComponent({
- propsData: {
- isEditable: true,
- },
- });
- });
-
- it('returns false when noteableData is not present', () => {
- wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, null);
-
- expect(wrapper.vm.confidential).toBe(false);
- });
-
- 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);
-
- expect(wrapper.vm.confidential).toBe(true);
- });
-
- 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('returns true when confidential attr is true', () => {
- wrapper.vm.$store.commit(types.SET_NOTEABLE_DATA, {});
- wrapper.vm.$store.commit(types.SET_ISSUE_CONFIDENTIAL, true);
-
- expect(wrapper.vm.confidential).toBe(true);
- });
-
- 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);
-
- expect(wrapper.vm.confidential).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js
index 3dde40260eb..e751f1239c8 100644
--- a/spec/frontend/sidebar/mock_data.js
+++ b/spec/frontend/sidebar/mock_data.js
@@ -220,4 +220,29 @@ const mockData = {
},
};
+export const issueConfidentialityResponse = (confidential = false) => ({
+ data: {
+ workspace: {
+ __typename: 'Project',
+ issuable: {
+ __typename: 'Issue',
+ id: 'gid://gitlab/Issue/4',
+ confidential,
+ },
+ },
+ },
+});
+
+export const issueReferenceResponse = (reference) => ({
+ data: {
+ workspace: {
+ __typename: 'Project',
+ issuable: {
+ __typename: 'Issue',
+ id: 'gid://gitlab/Issue/4',
+ reference,
+ },
+ },
+ },
+});
export default mockData;
diff --git a/spec/frontend/sidebar/subscriptions_spec.js b/spec/frontend/sidebar/subscriptions_spec.js
index e7ae59e26cf..6ab8e1e0ebc 100644
--- a/spec/frontend/sidebar/subscriptions_spec.js
+++ b/spec/frontend/sidebar/subscriptions_spec.js
@@ -84,6 +84,15 @@ describe('Subscriptions', () => {
spy.mockRestore();
});
+ it('has visually hidden label', () => {
+ wrapper = mountComponent();
+
+ expect(findToggleButton().props()).toMatchObject({
+ label: 'Notifications',
+ labelPosition: 'hidden',
+ });
+ });
+
describe('given project emails are disabled', () => {
const subscribeDisabledDescription = 'Notifications have been disabled';
diff --git a/spec/frontend/sidebar/user_data_mock.js b/spec/frontend/sidebar/user_data_mock.js
index 41d0331f34a..7c11551b0be 100644
--- a/spec/frontend/sidebar/user_data_mock.js
+++ b/spec/frontend/sidebar/user_data_mock.js
@@ -10,4 +10,5 @@ export default () => ({
can_merge: true,
can_update_merge_request: true,
reviewed: true,
+ approved: false,
});