From acd34d4137a3371b3b20a3fdea8a500a4ff0d97d Mon Sep 17 00:00:00 2001
From: Valerie Burton <vburton@gitlab.com>
Date: Mon, 2 Oct 2023 19:03:10 +0000
Subject: [PATCH] Add Sidebar Confidentiality Widget to Test Cases

Updates the test case sidebar to allow for editing confidentiality.

Changelog: changed
EE: true
---
 .../sidebar_confidentiality_widget.vue        |  1 +
 doc/ci/test_cases/index.md                    | 20 +++-
 .../components/test_case_sidebar.vue          |  9 ++
 .../projects/quality/test_case_show_spec.rb   | 91 ++++++++++++++++---
 .../components/test_case_sidebar_spec.js      | 48 ++++++++++
 5 files changed, 155 insertions(+), 14 deletions(-)

diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
index 295d37671cc0..ecccb0abfd15 100644
--- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
@@ -135,6 +135,7 @@ export default {
     :tracking="$options.tracking"
     :loading="isLoading"
     class="block confidentiality"
+    data-testid="sidebar-confidentiality"
   >
     <template #collapsed>
       <div>
diff --git a/doc/ci/test_cases/index.md b/doc/ci/test_cases/index.md
index d9dcbca08252..3885b450a709 100644
--- a/doc/ci/test_cases/index.md
+++ b/doc/ci/test_cases/index.md
@@ -40,8 +40,9 @@ issue list with a search query, including labels or the test case's title.
 
 Prerequisites:
 
-- In a public project: You don't have to be a member of the project.
-- In a private project: You must have at least the Guest role for the project.
+- Non-confidential test case in a public project: You don't have to be a member of the project.
+- Non-confidential test case in a private project: You must have at least the Guest role for the project.
+- Confidential test case (regardless of project visibility): You must have at least the Reporter role for the project.
 
 To view a test case:
 
@@ -68,6 +69,21 @@ To edit a test case:
 1. Edit the test case's title or description.
 1. Select **Save changes**.
 
+## Make a test case confidential
+
+> Ability to make a test case confidential from the right sidebar [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/422120) in GitLab 16.5.
+
+If you're working on a test case that contains private information, you can make it confidential.
+
+Prerequisites:
+
+- You must have at least the Reporter role.
+
+To make a test case confidential: on the right sidebar, select **Edit** next to **Confidentiality**, and then select **Turn on**.
+
+You can also use the `/confidential` [quick action](../../user/project/quick_actions.md) when both creating a new test case
+or editing an existing one.
+
 ## Archive a test case
 
 When you want to stop using a test case, you can archive it. You can [reopen an archived test case](#reopen-an-archived-test-case) later.
diff --git a/ee/app/assets/javascripts/test_case_show/components/test_case_sidebar.vue b/ee/app/assets/javascripts/test_case_show/components/test_case_sidebar.vue
index ab938db24d59..519e51da1de2 100644
--- a/ee/app/assets/javascripts/test_case_show/components/test_case_sidebar.vue
+++ b/ee/app/assets/javascripts/test_case_show/components/test_case_sidebar.vue
@@ -3,6 +3,7 @@ import { GlTooltipDirective as GlTooltip, GlButton, GlIcon, GlLoadingIcon } from
 import { s__, __ } from '~/locale';
 import ProjectSelect from '~/sidebar/components/move/issuable_move_dropdown.vue';
 import LabelsSelectWidget from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
+import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
 import { TYPE_TEST_CASE, WORKSPACE_PROJECT } from '~/issues/constants';
 import TestCaseGraphQL from '../mixins/test_case_graphql';
 
@@ -15,6 +16,7 @@ export default {
     GlLoadingIcon,
     ProjectSelect,
     LabelsSelectWidget,
+    SidebarConfidentialityWidget,
   },
   directives: {
     GlTooltip,
@@ -210,6 +212,13 @@ export default {
     >
       {{ __('None') }}
     </labels-select-widget>
+    <sidebar-confidentiality-widget
+      :iid="String(testCaseId)"
+      :full-path="projectFullPath"
+      :issuable-type="$options.TYPE_TEST_CASE"
+      @expandSidebar="expandSidebar"
+      @closeForm="handleSidebarDropdownClose"
+    />
     <project-select
       v-if="canMoveTestCase && !moved"
       :projects-fetch-path="projectsFetchPath"
diff --git a/ee/spec/features/projects/quality/test_case_show_spec.rb b/ee/spec/features/projects/quality/test_case_show_spec.rb
index 9a783f3f3b14..3ff8e8dfaa92 100644
--- a/ee/spec/features/projects/quality/test_case_show_spec.rb
+++ b/ee/spec/features/projects/quality/test_case_show_spec.rb
@@ -7,7 +7,17 @@
   let_it_be(:project) { create(:project, :repository) }
   let_it_be(:label_bug) { create(:label, project: project, title: 'bug') }
   let_it_be(:label_doc) { create(:label, project: project, title: 'documentation') }
-  let_it_be(:test_case) { create(:quality_test_case, project: project, author: user, description: 'Sample description', created_at: 5.days.ago, updated_at: 2.days.ago, labels: [label_bug]) }
+  let_it_be_with_reload(:test_case) do
+    create(
+      :quality_test_case,
+      project: project,
+      author: user,
+      description: 'Sample description',
+      created_at: 5.days.ago,
+      updated_at: 2.days.ago,
+      labels: [label_bug]
+    )
+  end
 
   before do
     project.add_developer(user)
@@ -105,21 +115,78 @@
           expect(page).to have_css('.labels-select-wrapper', text: label_bug.title)
         end
 
-        it 'shows labels dropdown on edit click' do
-          click_button('Edit')
+        context 'when editing' do
+          before do
+            within_testid('sidebar-labels') do
+              click_button('Edit')
+            end
+          end
+
+          it 'shows labels dropdown' do
+            expect(page).to have_button(label_bug.title)
+            expect(page).to have_button(label_doc.title)
+            expect(page).to have_button('Create group label')
+            expect(page).to have_link('Manage group labels')
+          end
+
+          it 'applies label using labels dropdown' do
+            click_button(label_doc.title)
+            send_keys(:escape)
+
+            expect(page).to have_css('.labels-select-wrapper', text: label_doc.title)
+          end
+        end
+      end
 
-          expect(page).to have_button(label_bug.title)
-          expect(page).to have_button(label_doc.title)
-          expect(page).to have_button('Create group label')
-          expect(page).to have_link('Manage group labels')
+      context 'confidentiality' do
+        context 'when test case is not confidential' do
+          it 'sets the test case to confidential' do
+            within_testid('sidebar-confidentiality') do
+              click_button('Edit')
+
+              expect(page).to have_content(
+                'You are going to turn on confidentiality. ' \
+                'Only project members with at least the Reporter role ' \
+                'can view or be notified about this test case.'
+              )
+
+              click_button('Turn on')
+
+              wait_for_requests
+
+              expect(test_case.reload.confidential).to eq(true)
+              expect(page).to have_content(
+                'Confidential Only project members with at least the Reporter role ' \
+                'can view or be notified about this test case.'
+              )
+            end
+          end
         end
 
-        it 'applies label using labels dropdown' do
-          click_button('Edit')
-          click_button(label_doc.title)
-          send_keys(:escape)
+        context 'when test case is confidential' do
+          before do
+            test_case.update!(confidential: true)
+            refresh
+            wait_for_requests
+          end
+
+          it 'sets the test case to not confidential' do
+            within_testid('sidebar-confidentiality') do
+              click_button('Edit')
+
+              expect(page).to have_content(
+                'You are going to turn off the confidentiality. ' \
+                'This means everyone will be able to see this test case.' \
+              )
+
+              click_button('Turn off')
+
+              wait_for_requests
 
-          expect(page).to have_css('.labels-select-wrapper', text: label_doc.title)
+              expect(test_case.reload.confidential).to eq(false)
+              expect(page).to have_content('Not confidential')
+            end
+          end
         end
       end
     end
diff --git a/ee/spec/frontend/test_case_show/components/test_case_sidebar_spec.js b/ee/spec/frontend/test_case_show/components/test_case_sidebar_spec.js
index b400acb5981e..6bebe8dacbe3 100644
--- a/ee/spec/frontend/test_case_show/components/test_case_sidebar_spec.js
+++ b/ee/spec/frontend/test_case_show/components/test_case_sidebar_spec.js
@@ -7,6 +7,7 @@ import { mockCurrentUserTodo, mockLabels } from 'jest/vue_shared/issuable/list/m
 import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
 import ProjectSelect from '~/sidebar/components/move/issuable_move_dropdown.vue';
 import LabelsSelectWidget from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
+import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
 import createMockApollo from 'helpers/mock_apollo_helper';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import projectTestCase from 'ee/test_case_show/queries/project_test_case.query.graphql';
@@ -45,6 +46,8 @@ describe('TestCaseSidebar', () => {
   };
 
   const findLabelsSelectWidget = () => wrapper.findComponent(LabelsSelectWidget);
+  const findSidebarConfidentialityWidget = () =>
+    wrapper.findComponent(SidebarConfidentialityWidget);
   const findProjectSelect = () => wrapper.findComponent(ProjectSelect);
   const findCollapsedTodoButton = () => wrapper.findByTestId('collapsed-button');
   const findExpandedTodoEl = () => wrapper.findByTestId('todo');
@@ -138,6 +141,51 @@ describe('TestCaseSidebar', () => {
     });
   });
 
+  describe('Confidentiality widget', () => {
+    describe('when sidebar is expanded by default', () => {
+      beforeEach(() => {
+        createComponent();
+      });
+
+      it('renders confidentiality widget', () => {
+        const { testCaseId, projectFullPath } = mockProvide;
+        const sidebarConfidentialityEl = findSidebarConfidentialityWidget();
+
+        expect(sidebarConfidentialityEl.props()).toMatchObject({
+          iid: testCaseId,
+          fullPath: projectFullPath,
+          issuableType: TYPE_TEST_CASE,
+        });
+      });
+
+      it('does not emit "sidebar-toggle" on closeForm', () => {
+        expect(wrapper.emitted('sidebar-toggle')).toBeUndefined();
+
+        findSidebarConfidentialityWidget().vm.$emit('closeForm');
+
+        expect(wrapper.emitted('sidebar-toggle')).toBeUndefined();
+      });
+    });
+
+    describe('when sidebar has been expanded by click', () => {
+      it('emits "sidebar-toggle" on closeForm', () => {
+        createComponent({
+          sidebarExpanded: false,
+        });
+
+        expect(wrapper.emitted('sidebar-toggle')).toBeUndefined();
+
+        findSidebarConfidentialityWidget().vm.$emit('expandSidebar');
+
+        expect(wrapper.emitted('sidebar-toggle')).toHaveLength(1);
+
+        findSidebarConfidentialityWidget().vm.$emit('closeForm');
+
+        expect(wrapper.emitted('sidebar-toggle')).toHaveLength(2);
+      });
+    });
+  });
+
   describe('Project select', () => {
     it('renders project-select', () => {
       createComponent();
-- 
GitLab