diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-20 13:18:24 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-20 13:18:24 +0000 |
commit | 0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch) | |
tree | 4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /spec/models/user_spec.rb | |
parent | 744144d28e3e7fddc117924fef88de5d9674fe4c (diff) | |
download | gitlab-ce-0653e08efd039a5905f3fa4f6e9cef9f5d2f799c.tar.gz |
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'spec/models/user_spec.rb')
-rw-r--r-- | spec/models/user_spec.rb | 537 |
1 files changed, 361 insertions, 176 deletions
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d73bc95a2f2..334f9b4ae30 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -65,9 +65,6 @@ RSpec.describe User do it { is_expected.to delegate_method(:render_whitespace_in_code).to(:user_preference) } it { is_expected.to delegate_method(:render_whitespace_in_code=).to(:user_preference).with_arguments(:args) } - it { is_expected.to delegate_method(:experience_level).to(:user_preference) } - it { is_expected.to delegate_method(:experience_level=).to(:user_preference).with_arguments(:args) } - it { is_expected.to delegate_method(:markdown_surround_selection).to(:user_preference) } it { is_expected.to delegate_method(:markdown_surround_selection=).to(:user_preference).with_arguments(:args) } @@ -82,7 +79,6 @@ RSpec.describe User do it { is_expected.to delegate_method(:bio).to(:user_detail).allow_nil } it { is_expected.to delegate_method(:bio=).to(:user_detail).with_arguments(:args).allow_nil } - it { is_expected.to delegate_method(:bio_html).to(:user_detail).allow_nil } end describe 'associations' do @@ -110,7 +106,6 @@ RSpec.describe User do it { is_expected.to have_many(:spam_logs).dependent(:destroy) } it { is_expected.to have_many(:todos) } it { is_expected.to have_many(:award_emoji).dependent(:destroy) } - it { is_expected.to have_many(:triggers).dependent(:destroy) } it { is_expected.to have_many(:builds).dependent(:nullify) } it { is_expected.to have_many(:pipelines).dependent(:nullify) } it { is_expected.to have_many(:chat_names).dependent(:destroy) } @@ -125,6 +120,8 @@ RSpec.describe User do it { is_expected.to have_many(:created_custom_emoji).inverse_of(:creator) } it { is_expected.to have_many(:in_product_marketing_emails) } it { is_expected.to have_many(:timelogs) } + it { is_expected.to have_many(:callouts).class_name('UserCallout') } + it { is_expected.to have_many(:group_callouts).class_name('Users::GroupCallout') } describe "#user_detail" do it 'does not persist `user_detail` by default' do @@ -404,7 +401,7 @@ RSpec.describe User do user = build(:user, username: "test.#{type}") expect(user).not_to be_valid - expect(user.errors.full_messages).to include('Username ending with MIME type format is not allowed.') + expect(user.errors.full_messages).to include('Username ending with a file extension is not allowed.') expect(build(:user, username: "test#{type}")).to be_valid end end @@ -438,12 +435,12 @@ RSpec.describe User do subject { create(:user).tap { |user| user.emails << build(:email, email: email_value, confirmed_at: Time.current) } } end - describe '#commit_email' do + describe '#commit_email_or_default' do subject(:user) { create(:user) } it 'defaults to the primary email' do expect(user.email).to be_present - expect(user.commit_email).to eq(user.email) + expect(user.commit_email_or_default).to eq(user.email) end it 'defaults to the primary email when the column in the database is null' do @@ -451,38 +448,37 @@ RSpec.describe User do found_user = described_class.find_by(id: user.id) - expect(found_user.commit_email).to eq(user.email) + expect(found_user.commit_email_or_default).to eq(user.email) end it 'returns the private commit email when commit_email has _private' do user.update_column(:commit_email, Gitlab::PrivateCommitEmail::TOKEN) - expect(user.commit_email).to eq(user.private_commit_email) + expect(user.commit_email_or_default).to eq(user.private_commit_email) end + end + + describe '#commit_email=' do + subject(:user) { create(:user) } it 'can be set to a confirmed email' do confirmed = create(:email, :confirmed, user: user) user.commit_email = confirmed.email expect(user).to be_valid - expect(user.commit_email).to eq(confirmed.email) end it 'can not be set to an unconfirmed email' do unconfirmed = create(:email, user: user) user.commit_email = unconfirmed.email - # This should set the commit_email attribute to the primary email - expect(user).to be_valid - expect(user.commit_email).to eq(user.email) + expect(user).not_to be_valid end it 'can not be set to a non-existent email' do user.commit_email = 'non-existent-email@nonexistent.nonexistent' - # This should set the commit_email attribute to the primary email - expect(user).to be_valid - expect(user.commit_email).to eq(user.email) + expect(user).not_to be_valid end it 'can not be set to an invalid email, even if confirmed' do @@ -692,70 +688,26 @@ RSpec.describe User do end end - context 'owns_notification_email' do - it 'accepts temp_oauth_email emails' do - user = build(:user, email: "temp-email-for-oauth@example.com") - expect(user).to be_valid - end - - it 'does not accept not verified emails' do - email = create(:email) - user = email.user - user.notification_email = email.email + context 'when secondary email is same as primary' do + let(:user) { create(:user, email: 'user@example.com') } - expect(user).to be_invalid - expect(user.errors[:notification_email]).to include(_('must be an email you have verified')) - end - end + it 'lets user change primary email without failing validations' do + user.commit_email = user.email + user.notification_email = user.email + user.public_email = user.email + user.save! - context 'owns_public_email' do - it 'accepts verified emails' do - email = create(:email, :confirmed, email: 'test@test.com') - user = email.user - user.notification_email = email.email + user.email = 'newemail@example.com' + user.confirm expect(user).to be_valid end - - it 'does not accept not verified emails' do - email = create(:email) - user = email.user - user.public_email = email.email - - expect(user).to be_invalid - expect(user.errors[:public_email]).to include(_('must be an email you have verified')) - end end - context 'set_commit_email' do - it 'keeps commit email when private commit email is being used' do - user = create(:user, commit_email: Gitlab::PrivateCommitEmail::TOKEN) - - expect(user.read_attribute(:commit_email)).to eq(Gitlab::PrivateCommitEmail::TOKEN) - end - - it 'keeps the commit email when nil' do - user = create(:user, commit_email: nil) - - expect(user.read_attribute(:commit_email)).to be_nil - end - - it 'reverts to nil when email is not verified' do - user = create(:user, commit_email: "foo@bar.com") - - expect(user.read_attribute(:commit_email)).to be_nil - end - end - - context 'owns_commit_email' do - it 'accepts private commit email' do - user = build(:user, commit_email: Gitlab::PrivateCommitEmail::TOKEN) - - expect(user).to be_valid - end - - it 'accepts nil commit email' do - user = build(:user, commit_email: nil) + context 'when commit_email is changed to _private' do + it 'passes user validations' do + user = create(:user) + user.commit_email = '_private' expect(user).to be_valid end @@ -931,12 +883,8 @@ RSpec.describe User do end context 'maximum value' do - before do - allow(Devise.password_length).to receive(:max).and_return(201) - end - it 'is determined by the current value of `Devise.password_length.max`' do - expect(password_length.max).to eq(201) + expect(password_length.max).to eq(Devise.password_length.max) end end end @@ -1311,53 +1259,57 @@ RSpec.describe User do end end - describe '#update_notification_email' do - # Regression: https://gitlab.com/gitlab-org/gitlab-foss/issues/22846 - context 'when changing :email' do - let(:user) { create(:user) } - let(:new_email) { 'new-email@example.com' } + describe 'when changing email' do + let(:user) { create(:user) } + let(:new_email) { 'new-email@example.com' } + context 'if notification_email was nil' do it 'sets :unconfirmed_email' do expect do user.tap { |u| u.update!(email: new_email) }.reload end.to change(user, :unconfirmed_email).to(new_email) end - it 'does not change :notification_email' do + + it 'does not change notification_email or notification_email_or_default before email is confirmed' do expect do user.tap { |u| u.update!(email: new_email) }.reload - end.not_to change(user, :notification_email) + end.not_to change(user, :notification_email_or_default) + + expect(user.notification_email).to be_nil end - it 'updates :notification_email to the new email once confirmed' do + it 'updates notification_email_or_default to the new email once confirmed' do user.update!(email: new_email) expect do user.tap(&:confirm).reload - end.to change(user, :notification_email).to eq(new_email) + end.to change(user, :notification_email_or_default).to eq(new_email) + + expect(user.notification_email).to be_nil end + end - context 'and :notification_email is set to a secondary email' do - let!(:email_attrs) { attributes_for(:email, :confirmed, user: user) } - let(:secondary) { create(:email, :confirmed, email: 'secondary@example.com', user: user) } + context 'when notification_email is set to a secondary email' do + let!(:email_attrs) { attributes_for(:email, :confirmed, user: user) } + let(:secondary) { create(:email, :confirmed, email: 'secondary@example.com', user: user) } - before do - user.emails.create!(email_attrs) - user.tap { |u| u.update!(notification_email: email_attrs[:email]) }.reload - end + before do + user.emails.create!(email_attrs) + user.tap { |u| u.update!(notification_email: email_attrs[:email]) }.reload + end - it 'does not change :notification_email to :email' do - expect do - user.tap { |u| u.update!(email: new_email) }.reload - end.not_to change(user, :notification_email) - end + it 'does not change notification_email to email before email is confirmed' do + expect do + user.tap { |u| u.update!(email: new_email) }.reload + end.not_to change(user, :notification_email) + end - it 'does not change :notification_email to :email once confirmed' do - user.update!(email: new_email) + it 'does not change notification_email to email once confirmed' do + user.update!(email: new_email) - expect do - user.tap(&:confirm).reload - end.not_to change(user, :notification_email) - end + expect do + user.tap(&:confirm).reload + end.not_to change(user, :notification_email) end end end @@ -1833,14 +1785,26 @@ RSpec.describe User do end describe '#manageable_groups' do - it 'includes all the namespaces the user can manage' do - expect(user.manageable_groups).to contain_exactly(group, subgroup) + shared_examples 'manageable groups examples' do + it 'includes all the namespaces the user can manage' do + expect(user.manageable_groups).to contain_exactly(group, subgroup) + end + + it 'does not include duplicates if a membership was added for the subgroup' do + subgroup.add_owner(user) + + expect(user.manageable_groups).to contain_exactly(group, subgroup) + end end - it 'does not include duplicates if a membership was added for the subgroup' do - subgroup.add_owner(user) + it_behaves_like 'manageable groups examples' + + context 'when feature flag :linear_user_manageable_groups is disabled' do + before do + stub_feature_flags(linear_user_manageable_groups: false) + end - expect(user.manageable_groups).to contain_exactly(group, subgroup) + it_behaves_like 'manageable groups examples' end end @@ -1925,12 +1889,25 @@ RSpec.describe User do expect(user.deactivated?).to be_truthy end - it 'sends deactivated user an email' do - expect_next_instance_of(NotificationService) do |notification| - allow(notification).to receive(:user_deactivated).with(user.name, user.notification_email) + context "when user deactivation emails are disabled" do + before do + stub_application_setting(user_deactivation_emails_enabled: false) end + it 'does not send deactivated user an email' do + expect(NotificationService).not_to receive(:new) - user.deactivate + user.deactivate + end + end + + context "when user deactivation emails are enabled" do + it 'sends deactivated user an email' do + expect_next_instance_of(NotificationService) do |notification| + allow(notification).to receive(:user_deactivated).with(user.name, user.notification_email_or_default) + end + + user.deactivate + end end end @@ -1997,15 +1974,15 @@ RSpec.describe User do user.ban! end - it 'activates the user' do - user.activate + it 'unbans the user' do + user.unban expect(user.banned?).to eq(false) expect(user.active?).to eq(true) end it 'deletes the BannedUser record' do - expect { user.activate }.to change { Users::BannedUser.count }.by(-1) + expect { user.unban }.to change { Users::BannedUser.count }.by(-1) expect(Users::BannedUser.where(user_id: user.id)).not_to exist end end @@ -3125,15 +3102,15 @@ RSpec.describe User do end end - describe '#notification_email' do + describe '#notification_email_or_default' do let(:email) { 'gonzo@muppets.com' } context 'when the column in the database is null' do subject { create(:user, email: email, notification_email: nil) } it 'defaults to the primary email' do - expect(subject.read_attribute(:notification_email)).to be nil - expect(subject.notification_email).to eq(email) + expect(subject.notification_email).to be nil + expect(subject.notification_email_or_default).to eq(email) end end end @@ -3467,17 +3444,32 @@ RSpec.describe User do end describe '#membership_groups' do - let!(:user) { create(:user) } - let!(:parent_group) { create(:group) } - let!(:child_group) { create(:group, parent: parent_group) } + let_it_be(:user) { create(:user) } - before do - parent_group.add_user(user, Gitlab::Access::MAINTAINER) + let_it_be(:parent_group) do + create(:group).tap do |g| + g.add_user(user, Gitlab::Access::MAINTAINER) + end end + let_it_be(:child_group) { create(:group, parent: parent_group) } + let_it_be(:other_group) { create(:group) } + subject { user.membership_groups } - it { is_expected.to contain_exactly parent_group, child_group } + shared_examples 'returns groups where the user is a member' do + specify { is_expected.to contain_exactly(parent_group, child_group) } + end + + it_behaves_like 'returns groups where the user is a member' + + context 'when feature flag :linear_user_membership_groups is disabled' do + before do + stub_feature_flags(linear_user_membership_groups: false) + end + + it_behaves_like 'returns groups where the user is a member' + end end describe '#authorizations_for_projects' do @@ -3686,6 +3678,11 @@ RSpec.describe User do it 'loads all the runners in the tree of groups' do expect(user.ci_owned_runners).to contain_exactly(runner, group_runner) end + + it 'returns true for owns_runner?' do + expect(user.owns_runner?(runner)).to eq(true) + expect(user.owns_runner?(group_runner)).to eq(true) + end end end @@ -3698,6 +3695,10 @@ RSpec.describe User do it 'loads the runners in the group' do expect(user.ci_owned_runners).to contain_exactly(group_runner) end + + it 'returns true for owns_runner?' do + expect(user.owns_runner?(group_runner)).to eq(true) + end end end @@ -3706,6 +3707,10 @@ RSpec.describe User do it 'loads the runner belonging to the project' do expect(user.ci_owned_runners).to contain_exactly(runner) end + + it 'returns true for owns_runner?' do + expect(user.owns_runner?(runner)).to eq(true) + end end end @@ -3718,6 +3723,10 @@ RSpec.describe User do it 'loads the runners of the project' do expect(user.ci_owned_runners).to contain_exactly(project_runner) end + + it 'returns true for owns_runner?' do + expect(user.owns_runner?(project_runner)).to eq(true) + end end context 'when the user is a developer' do @@ -3728,6 +3737,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(project_runner)).to eq(false) + end end context 'when the user is a reporter' do @@ -3738,6 +3751,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(project_runner)).to eq(false) + end end context 'when the user is a guest' do @@ -3748,6 +3765,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(project_runner)).to eq(false) + end end end @@ -3760,6 +3781,10 @@ RSpec.describe User do it 'does not load the runners of the group' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(runner)).to eq(false) + end end context 'when the user is a developer' do @@ -3770,6 +3795,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(runner)).to eq(false) + end end context 'when the user is a reporter' do @@ -3780,6 +3809,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(runner)).to eq(false) + end end context 'when the user is a guest' do @@ -3790,6 +3823,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(runner)).to eq(false) + end end end @@ -3797,6 +3834,10 @@ RSpec.describe User do it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end + + it 'returns false for owns_runner?' do + expect(user.owns_runner?(create(:ci_runner))).to eq(false) + end end context 'with runner in a personal project' do @@ -5312,7 +5353,7 @@ RSpec.describe User do let(:group) { nil } it 'returns global notification email' do - is_expected.to eq(user.notification_email) + is_expected.to eq(user.notification_email_or_default) end end @@ -5320,7 +5361,7 @@ RSpec.describe User do it 'returns global notification email' do create(:notification_setting, user: user, source: group, notification_email: '') - is_expected.to eq(user.notification_email) + is_expected.to eq(user.notification_email_or_default) end end @@ -5521,22 +5562,17 @@ RSpec.describe User do end describe '#dismissed_callout?' do - subject(:user) { create(:user) } - - let(:feature_name) { UserCallout.feature_names.each_key.first } + let_it_be(:user, refind: true) { create(:user) } + let_it_be(:feature_name) { UserCallout.feature_names.each_key.first } context 'when no callout dismissal record exists' do it 'returns false when no ignore_dismissal_earlier_than provided' do expect(user.dismissed_callout?(feature_name: feature_name)).to eq false end - - it 'returns false when ignore_dismissal_earlier_than provided' do - expect(user.dismissed_callout?(feature_name: feature_name, ignore_dismissal_earlier_than: 3.months.ago)).to eq false - end end context 'when dismissed callout exists' do - before do + before_all do create(:user_callout, user: user, feature_name: feature_name, dismissed_at: 4.months.ago) end @@ -5554,6 +5590,123 @@ RSpec.describe User do end end + describe '#find_or_initialize_callout' do + let_it_be(:user, refind: true) { create(:user) } + let_it_be(:feature_name) { UserCallout.feature_names.each_key.first } + + subject(:find_or_initialize_callout) { user.find_or_initialize_callout(feature_name) } + + context 'when callout exists' do + let!(:callout) { create(:user_callout, user: user, feature_name: feature_name) } + + it 'returns existing callout' do + expect(find_or_initialize_callout).to eq(callout) + end + end + + context 'when callout does not exist' do + context 'when feature name is valid' do + it 'initializes a new callout' do + expect(find_or_initialize_callout).to be_a_new(UserCallout) + end + + it 'is valid' do + expect(find_or_initialize_callout).to be_valid + end + end + + context 'when feature name is not valid' do + let(:feature_name) { 'notvalid' } + + it 'initializes a new callout' do + expect(find_or_initialize_callout).to be_a_new(UserCallout) + end + + it 'is not valid' do + expect(find_or_initialize_callout).not_to be_valid + end + end + end + end + + describe '#dismissed_callout_for_group?' do + let_it_be(:user, refind: true) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:feature_name) { Users::GroupCallout.feature_names.each_key.first } + + context 'when no callout dismissal record exists' do + it 'returns false when no ignore_dismissal_earlier_than provided' do + expect(user.dismissed_callout_for_group?(feature_name: feature_name, group: group)).to eq false + end + end + + context 'when dismissed callout exists' do + before_all do + create(:group_callout, + user: user, + group_id: group.id, + feature_name: feature_name, + dismissed_at: 4.months.ago) + end + + it 'returns true when no ignore_dismissal_earlier_than provided' do + expect(user.dismissed_callout_for_group?(feature_name: feature_name, group: group)).to eq true + end + + it 'returns true when ignore_dismissal_earlier_than is earlier than dismissed_at' do + expect(user.dismissed_callout_for_group?(feature_name: feature_name, group: group, ignore_dismissal_earlier_than: 6.months.ago)).to eq true + end + + it 'returns false when ignore_dismissal_earlier_than is later than dismissed_at' do + expect(user.dismissed_callout_for_group?(feature_name: feature_name, group: group, ignore_dismissal_earlier_than: 3.months.ago)).to eq false + end + end + end + + describe '#find_or_initialize_group_callout' do + let_it_be(:user, refind: true) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:feature_name) { Users::GroupCallout.feature_names.each_key.first } + + subject(:callout_with_source) do + user.find_or_initialize_group_callout(feature_name, group.id) + end + + context 'when callout exists' do + let!(:callout) do + create(:group_callout, user: user, feature_name: feature_name, group_id: group.id) + end + + it 'returns existing callout' do + expect(callout_with_source).to eq(callout) + end + end + + context 'when callout does not exist' do + context 'when feature name is valid' do + it 'initializes a new callout' do + expect(callout_with_source).to be_a_new(Users::GroupCallout) + end + + it 'is valid' do + expect(callout_with_source).to be_valid + end + end + + context 'when feature name is not valid' do + let(:feature_name) { 'notvalid' } + + it 'initializes a new callout' do + expect(callout_with_source).to be_a_new(Users::GroupCallout) + end + + it 'is not valid' do + expect(callout_with_source).not_to be_valid + end + end + end + end + describe '#hook_attrs' do it 'includes id, name, username, avatar_url, and email' do user = create(:user) @@ -5916,45 +6069,6 @@ RSpec.describe User do end end - describe '#find_or_initialize_callout' do - subject(:find_or_initialize_callout) { user.find_or_initialize_callout(feature_name) } - - let(:user) { create(:user) } - let(:feature_name) { UserCallout.feature_names.each_key.first } - - context 'when callout exists' do - let!(:callout) { create(:user_callout, user: user, feature_name: feature_name) } - - it 'returns existing callout' do - expect(find_or_initialize_callout).to eq(callout) - end - end - - context 'when callout does not exist' do - context 'when feature name is valid' do - it 'initializes a new callout' do - expect(find_or_initialize_callout).to be_a_new(UserCallout) - end - - it 'is valid' do - expect(find_or_initialize_callout).to be_valid - end - end - - context 'when feature name is not valid' do - let(:feature_name) { 'notvalid' } - - it 'initializes a new callout' do - expect(find_or_initialize_callout).to be_a_new(UserCallout) - end - - it 'is not valid' do - expect(find_or_initialize_callout).not_to be_valid - end - end - end - end - describe '#default_dashboard?' do it 'is the default dashboard' do user = build(:user) @@ -6024,4 +6138,75 @@ RSpec.describe User do expect(described_class.by_provider_and_extern_uid(:github, 'my_github_id')).to match_array([expected_user]) end end + + describe '#unset_secondary_emails_matching_deleted_email!' do + let(:deleted_email) { 'kermit@muppets.com' } + + subject { build(:user, commit_email: commit_email) } + + context 'when no secondary email matches the deleted email' do + let(:commit_email) { 'fozzie@muppets.com' } + + it 'does nothing' do + expect(subject).not_to receive(:save) + subject.unset_secondary_emails_matching_deleted_email!(deleted_email) + expect(subject.commit_email).to eq commit_email + end + end + + context 'when a secondary email matches the deleted_email' do + let(:commit_email) { deleted_email } + + it 'un-sets the secondary email' do + expect(subject).to receive(:save) + subject.unset_secondary_emails_matching_deleted_email!(deleted_email) + expect(subject.commit_email).to be nil + end + end + end + + describe '#groups_with_developer_maintainer_project_access' do + let_it_be(:user) { create(:user) } + let_it_be(:group1) { create(:group) } + + let_it_be(:developer_group1) do + create(:group).tap do |g| + g.add_developer(user) + end + end + + let_it_be(:developer_group2) do + create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS).tap do |g| + g.add_developer(user) + end + end + + let_it_be(:guest_group1) do + create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS).tap do |g| + g.add_guest(user) + end + end + + let_it_be(:developer_group1) do + create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS).tap do |g| + g.add_maintainer(user) + end + end + + subject { user.send(:groups_with_developer_maintainer_project_access) } + + shared_examples 'groups_with_developer_maintainer_project_access examples' do + specify { is_expected.to contain_exactly(developer_group2) } + end + + it_behaves_like 'groups_with_developer_maintainer_project_access examples' + + context 'when feature flag :linear_user_groups_with_developer_maintainer_project_access is disabled' do + before do + stub_feature_flags(linear_user_groups_with_developer_maintainer_project_access: false) + end + + it_behaves_like 'groups_with_developer_maintainer_project_access examples' + end + end end |