1# frozen_string_literal: true 2 3require 'spec_helper' 4 5RSpec.describe 'Project > Members > Invite group', :js do 6 include Select2Helper 7 include ActionView::Helpers::DateHelper 8 include Spec::Support::Helpers::Features::MembersHelpers 9 include Spec::Support::Helpers::Features::InviteMembersModalHelper 10 11 let(:maintainer) { create(:user) } 12 13 using RSpec::Parameterized::TableSyntax 14 15 where(:invite_members_group_modal_enabled, :expected_invite_group_selector) do 16 true | 'button[data-qa-selector="invite_a_group_button"]' # rubocop:disable QA/SelectorUsage 17 false | '#invite-group-tab' 18 end 19 20 with_them do 21 before do 22 stub_feature_flags(invite_members_group_modal: invite_members_group_modal_enabled) 23 end 24 25 it 'displays either the invite group button or the form with tabs based on the feature flag' do 26 project = create(:project, namespace: create(:group)) 27 28 project.add_maintainer(maintainer) 29 sign_in(maintainer) 30 31 visit project_project_members_path(project) 32 33 expect(page).to have_selector(expected_invite_group_selector) 34 end 35 36 it 'does not display either the form or the button when visiting the page not signed in' do 37 project = create(:project, namespace: create(:group)) 38 39 visit project_project_members_path(project) 40 41 expect(page).not_to have_selector(expected_invite_group_selector) 42 end 43 end 44 45 describe 'Share with group lock' do 46 let(:invite_group_selector) { 'button[data-qa-selector="invite_a_group_button"]' } # rubocop:disable QA/SelectorUsage 47 48 shared_examples 'the project can be shared with groups' do 49 it 'the "Invite a group" button exists' do 50 visit project_project_members_path(project) 51 expect(page).to have_selector(invite_group_selector) 52 end 53 end 54 55 shared_examples 'the project cannot be shared with groups' do 56 it 'the "Invite a group" button does not exist' do 57 visit project_project_members_path(project) 58 expect(page).not_to have_selector(invite_group_selector) 59 end 60 end 61 62 context 'for a project in a root group' do 63 let!(:group_to_share_with) { create(:group) } 64 let(:project) { create(:project, namespace: create(:group)) } 65 66 before do 67 project.add_maintainer(maintainer) 68 group_to_share_with.add_guest(maintainer) 69 sign_in(maintainer) 70 end 71 72 context 'when the group has "Share with group lock" disabled' do 73 it_behaves_like 'the project can be shared with groups' 74 75 it 'the project can be shared with another group when the feature flag invite_members_group_modal is disabled' do 76 stub_feature_flags(invite_members_group_modal: false) 77 78 visit project_project_members_path(project) 79 80 expect(page).not_to have_link 'Groups' 81 82 click_on 'invite-group-tab' 83 84 select2 group_to_share_with.id, from: '#link_group_id' 85 page.find('body').click 86 find('.btn-confirm').click 87 88 click_link 'Groups' 89 90 expect(members_table).to have_content(group_to_share_with.name) 91 end 92 93 it 'the project can be shared with another group when the feature flag invite_members_group_modal is enabled' do 94 stub_feature_flags(invite_members_group_modal: true) 95 96 visit project_project_members_path(project) 97 98 expect(page).not_to have_link 'Groups' 99 100 invite_group(group_to_share_with.name) 101 102 visit project_project_members_path(project) 103 104 click_link 'Groups' 105 106 expect(members_table).to have_content(group_to_share_with.name) 107 end 108 end 109 110 context 'when the group has "Share with group lock" enabled' do 111 before do 112 project.namespace.update_column(:share_with_group_lock, true) 113 end 114 115 it_behaves_like 'the project cannot be shared with groups' 116 end 117 end 118 119 context 'for a project in a subgroup' do 120 let!(:group_to_share_with) { create(:group) } 121 let(:root_group) { create(:group) } 122 let(:subgroup) { create(:group, parent: root_group) } 123 let(:project) { create(:project, namespace: subgroup) } 124 125 before do 126 project.add_maintainer(maintainer) 127 sign_in(maintainer) 128 end 129 130 context 'when the root_group has "Share with group lock" disabled' do 131 context 'when the subgroup has "Share with group lock" disabled' do 132 it_behaves_like 'the project can be shared with groups' 133 end 134 135 context 'when the subgroup has "Share with group lock" enabled' do 136 before do 137 subgroup.update_column(:share_with_group_lock, true) 138 end 139 140 it_behaves_like 'the project cannot be shared with groups' 141 end 142 end 143 144 context 'when the root_group has "Share with group lock" enabled' do 145 before do 146 root_group.update_column(:share_with_group_lock, true) 147 end 148 149 context 'when the subgroup has "Share with group lock" disabled (parent overridden)' do 150 it_behaves_like 'the project can be shared with groups' 151 end 152 153 context 'when the subgroup has "Share with group lock" enabled' do 154 before do 155 subgroup.update_column(:share_with_group_lock, true) 156 end 157 158 it_behaves_like 'the project cannot be shared with groups' 159 end 160 end 161 end 162 end 163 164 describe 'setting an expiration date for a group link' do 165 let(:project) { create(:project) } 166 let!(:group) { create(:group) } 167 168 let_it_be(:expiration_date) { 5.days.from_now.to_date } 169 170 around do |example| 171 freeze_time { example.run } 172 end 173 174 def setup 175 project.add_maintainer(maintainer) 176 group.add_guest(maintainer) 177 sign_in(maintainer) 178 179 visit project_project_members_path(project) 180 181 invite_group(group.name, role: 'Guest', expires_at: expiration_date) 182 end 183 184 it 'the group link shows the expiration time with a warning class' do 185 setup 186 click_link 'Groups' 187 188 expect(page).to have_field('Expiration date', with: expiration_date) 189 end 190 end 191 192 describe 'the groups dropdown' do 193 context 'with multiple groups to choose from' do 194 let(:project) { create(:project) } 195 196 it 'includes multiple groups' do 197 project.add_maintainer(maintainer) 198 sign_in(maintainer) 199 200 group1 = create(:group) 201 group1.add_owner(maintainer) 202 group2 = create(:group) 203 group2.add_owner(maintainer) 204 205 visit project_project_members_path(project) 206 207 click_on 'Invite a group' 208 click_on 'Select a group' 209 wait_for_requests 210 211 expect(page).to have_button(group1.name) 212 expect(page).to have_button(group2.name) 213 end 214 end 215 216 context 'for a project in a nested group' do 217 let(:group) { create(:group) } 218 let!(:nested_group) { create(:group, parent: group) } 219 let!(:group_to_share_with) { create(:group) } 220 let!(:project) { create(:project, namespace: nested_group) } 221 222 before do 223 project.add_maintainer(maintainer) 224 sign_in(maintainer) 225 group.add_maintainer(maintainer) 226 group_to_share_with.add_maintainer(maintainer) 227 end 228 229 # This behavior should be changed to exclude the ancestor and project 230 # group from the options once issue is fixed for the modal: 231 # https://gitlab.com/gitlab-org/gitlab/-/issues/329835 232 it 'the groups dropdown does show ancestors and the project group' do 233 visit project_project_members_path(project) 234 235 click_on 'Invite a group' 236 click_on 'Select a group' 237 wait_for_requests 238 239 expect(page).to have_button(group_to_share_with.name) 240 expect(page).to have_button(group.name) 241 expect(page).to have_button(nested_group.name) 242 end 243 end 244 end 245end 246