group_spec.rb 22.2 KB
Newer Older
1 2
require 'spec_helper'

3
describe Group do
4
  let!(:group) { create(:group, :access_requestable) }
5

6
  describe 'associations' do
7
    it { is_expected.to have_many :projects }
8 9
    it { is_expected.to have_many(:group_members).dependent(:destroy) }
    it { is_expected.to have_many(:users).through(:group_members) }
10 11
    it { is_expected.to have_many(:owners).through(:group_members) }
    it { is_expected.to have_many(:requesters).dependent(:destroy) }
12
    it { is_expected.to have_many(:members_and_requesters) }
13 14 15
    it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
    it { is_expected.to have_many(:shared_projects).through(:project_group_links) }
    it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
16
    it { is_expected.to have_many(:labels).class_name('GroupLabel') }
Shinya Maeda's avatar
Shinya Maeda committed
17
    it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
Jan Provaznik's avatar
Jan Provaznik committed
18
    it { is_expected.to have_many(:uploads) }
19
    it { is_expected.to have_one(:chat_team) }
20
    it { is_expected.to have_many(:custom_attributes).class_name('GroupCustomAttribute') }
21
    it { is_expected.to have_many(:badges).class_name('GroupBadge') }
22 23 24 25 26 27 28 29 30

    describe '#members & #requesters' do
      let(:requester) { create(:user) }
      let(:developer) { create(:user) }
      before do
        group.request_access(requester)
        group.add_developer(developer)
      end

31 32
      it_behaves_like 'members and requesters associations' do
        let(:namespace) { group }
33 34
      end
    end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
35 36
  end

37 38 39 40 41 42 43 44 45 46
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(Referable) }
  end

  describe 'validations' do
    it { is_expected.to validate_presence_of :name }
    it { is_expected.to validate_presence_of :path }
    it { is_expected.not_to validate_presence_of :owner }
47 48
    it { is_expected.to validate_presence_of :two_factor_grace_period }
    it { is_expected.to validate_numericality_of(:two_factor_grace_period).is_greater_than_or_equal_to(0) }
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

    describe 'path validation' do
      it 'rejects paths reserved on the root namespace when the group has no parent' do
        group = build(:group, path: 'api')

        expect(group).not_to be_valid
      end

      it 'allows root paths when the group has a parent' do
        group = build(:group, path: 'api', parent: create(:group))

        expect(group).to be_valid
      end

      it 'rejects any wildcard paths when not a top level group' do
        group = build(:group, path: 'tree', parent: create(:group))

        expect(group).not_to be_valid
      end
    end
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

    describe '#visibility_level_allowed_by_parent' do
      let(:parent) { create(:group, :internal) }
      let(:sub_group) { build(:group, parent_id: parent.id) }

      context 'without a parent' do
        it 'is valid' do
          sub_group.parent_id = nil

          expect(sub_group).to be_valid
        end
      end

      context 'with a parent' do
        context 'when visibility of sub group is greater than the parent' do
          it 'is invalid' do
            sub_group.visibility_level = Gitlab::VisibilityLevel::PUBLIC

            expect(sub_group).to be_invalid
          end
        end

        context 'when visibility of sub group is lower or equal to the parent' do
          [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE].each do |level|
            it 'is valid' do
              sub_group.visibility_level = level

              expect(sub_group).to be_valid
            end
          end
        end
      end
    end
102 103 104 105 106 107 108 109 110 111

    describe '#visibility_level_allowed_by_projects' do
      let!(:internal_group) { create(:group, :internal) }
      let!(:internal_project) { create(:project, :internal, group: internal_group) }

      context 'when group has a lower visibility' do
        it 'is invalid' do
          internal_group.visibility_level = Gitlab::VisibilityLevel::PRIVATE

          expect(internal_group).to be_invalid
112
          expect(internal_group.errors[:visibility_level]).to include('private is not allowed since this group contains projects with higher visibility.')
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
        end
      end

      context 'when group has a higher visibility' do
        it 'is valid' do
          internal_group.visibility_level = Gitlab::VisibilityLevel::PUBLIC

          expect(internal_group).to be_valid
        end
      end
    end

    describe '#visibility_level_allowed_by_sub_groups' do
      let!(:internal_group) { create(:group, :internal) }
      let!(:internal_sub_group) { create(:group, :internal, parent: internal_group) }

      context 'when parent group has a lower visibility' do
        it 'is invalid' do
          internal_group.visibility_level = Gitlab::VisibilityLevel::PRIVATE

          expect(internal_group).to be_invalid
134
          expect(internal_group.errors[:visibility_level]).to include('private is not allowed since there are sub-groups with higher visibility.')
135 136 137 138 139 140 141 142 143 144 145
        end
      end

      context 'when parent group has a higher visibility' do
        it 'is valid' do
          internal_group.visibility_level = Gitlab::VisibilityLevel::PUBLIC

          expect(internal_group).to be_valid
        end
      end
    end
146 147
  end

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
  describe '.visible_to_user' do
    let!(:group) { create(:group) }
    let!(:user)  { create(:user) }

    subject { described_class.visible_to_user(user) }

    describe 'when the user has access to a group' do
      before do
        group.add_user(user, Gitlab::Access::MASTER)
      end

      it { is_expected.to eq([group]) }
    end

    describe 'when the user does not have access to any groups' do
      it { is_expected.to eq([]) }
    end
  end

167
  describe 'scopes' do
168 169
    let!(:private_group)  { create(:group, :private)  }
    let!(:internal_group) { create(:group, :internal) }
170 171

    describe 'public_only' do
172
      subject { described_class.public_only.to_a }
173

174
      it { is_expected.to eq([group]) }
175 176 177
    end

    describe 'public_and_internal_only' do
Douwe Maan's avatar
Douwe Maan committed
178
      subject { described_class.public_and_internal_only.to_a }
179

180 181 182 183 184 185 186
      it { is_expected.to match_array([group, internal_group]) }
    end

    describe 'non_public_only' do
      subject { described_class.non_public_only.to_a }

      it { is_expected.to match_array([private_group, internal_group]) }
187 188 189
    end
  end

190 191 192 193 194
  describe '#to_reference' do
    it 'returns a String reference to the object' do
      expect(group.to_reference).to eq "@#{group.name}"
    end
  end
195

196
  describe '#users' do
197
    it { expect(group.users).to eq(group.owners) }
198 199
  end

200
  describe '#human_name' do
201
    it { expect(group.human_name).to eq(group.name) }
202
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
203

204
  describe '#add_user' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
205
    let(:user) { create(:user) }
206 207 208 209

    before do
      group.add_user(user, GroupMember::MASTER)
    end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
210

211
    it { expect(group.group_members.masters.map(&:user)).to include(user) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
212
  end
213

214
  describe '#add_users' do
215
    let(:user) { create(:user) }
216 217 218 219

    before do
      group.add_users([user.id], GroupMember::GUEST)
    end
220

221
    it "updates the group permission" do
222
      expect(group.group_members.guests.map(&:user)).to include(user)
223
      group.add_users([user.id], GroupMember::DEVELOPER)
224 225
      expect(group.group_members.developers.map(&:user)).to include(user)
      expect(group.group_members.guests.map(&:user)).not_to include(user)
226 227
    end
  end
Steven Thonus's avatar
Steven Thonus committed
228

229
  describe '#avatar_type' do
Steven Thonus's avatar
Steven Thonus committed
230
    let(:user) { create(:user) }
231 232 233 234

    before do
      group.add_user(user, GroupMember::MASTER)
    end
Steven Thonus's avatar
Steven Thonus committed
235

236
    it "is true if avatar is image" do
Steven Thonus's avatar
Steven Thonus committed
237
      group.update_attribute(:avatar, 'uploads/avatar.png')
238
      expect(group.avatar_type).to be_truthy
Steven Thonus's avatar
Steven Thonus committed
239 240
    end

241
    it "is false if avatar is html page" do
Steven Thonus's avatar
Steven Thonus committed
242
      group.update_attribute(:avatar, 'uploads/avatar.html')
243
      expect(group.avatar_type).to eq(["file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff"])
Steven Thonus's avatar
Steven Thonus committed
244 245
    end
  end
246

247 248 249 250 251
  describe '#avatar_url' do
    let!(:group) { create(:group, :access_requestable, :with_avatar) }
    let(:user) { create(:user) }

    context 'when avatar file is uploaded' do
252 253 254
      before do
        group.add_master(user)
      end
255

256
      it 'shows correct avatar url' do
257 258
        expect(group.avatar_url).to eq(group.avatar.url)
        expect(group.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, group.avatar.url].join)
259
      end
260 261 262
    end
  end

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
  describe '.search' do
    it 'returns groups with a matching name' do
      expect(described_class.search(group.name)).to eq([group])
    end

    it 'returns groups with a partially matching name' do
      expect(described_class.search(group.name[0..2])).to eq([group])
    end

    it 'returns groups with a matching name regardless of the casing' do
      expect(described_class.search(group.name.upcase)).to eq([group])
    end

    it 'returns groups with a matching path' do
      expect(described_class.search(group.path)).to eq([group])
    end

    it 'returns groups with a partially matching path' do
      expect(described_class.search(group.path[0..2])).to eq([group])
    end

    it 'returns groups with a matching path regardless of the casing' do
      expect(described_class.search(group.path.upcase)).to eq([group])
    end
  end
288 289

  describe '#has_owner?' do
290 291
    before do
      @members = setup_group_members(group)
292
      create(:group_member, :invited, :owner, group: group)
293
    end
294 295 296 297 298 299 300

    it { expect(group.has_owner?(@members[:owner])).to be_truthy }
    it { expect(group.has_owner?(@members[:master])).to be_falsey }
    it { expect(group.has_owner?(@members[:developer])).to be_falsey }
    it { expect(group.has_owner?(@members[:reporter])).to be_falsey }
    it { expect(group.has_owner?(@members[:guest])).to be_falsey }
    it { expect(group.has_owner?(@members[:requester])).to be_falsey }
301
    it { expect(group.has_owner?(nil)).to be_falsey }
302 303 304
  end

  describe '#has_master?' do
305 306
    before do
      @members = setup_group_members(group)
307
      create(:group_member, :invited, :master, group: group)
308
    end
309 310 311 312 313 314 315

    it { expect(group.has_master?(@members[:owner])).to be_falsey }
    it { expect(group.has_master?(@members[:master])).to be_truthy }
    it { expect(group.has_master?(@members[:developer])).to be_falsey }
    it { expect(group.has_master?(@members[:reporter])).to be_falsey }
    it { expect(group.has_master?(@members[:guest])).to be_falsey }
    it { expect(group.has_master?(@members[:requester])).to be_falsey }
316
    it { expect(group.has_master?(nil)).to be_falsey }
317 318
  end

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
  describe '#lfs_enabled?' do
    context 'LFS enabled globally' do
      before do
        allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
      end

      it 'returns true when nothing is set' do
        expect(group.lfs_enabled?).to be_truthy
      end

      it 'returns false when set to false' do
        group.update_attribute(:lfs_enabled, false)

        expect(group.lfs_enabled?).to be_falsey
      end

      it 'returns true when set to true' do
        group.update_attribute(:lfs_enabled, true)

        expect(group.lfs_enabled?).to be_truthy
      end
    end

    context 'LFS disabled globally' do
      before do
        allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
      end

      it 'returns false when nothing is set' do
        expect(group.lfs_enabled?).to be_falsey
      end

      it 'returns false when set to false' do
        group.update_attribute(:lfs_enabled, false)

        expect(group.lfs_enabled?).to be_falsey
      end

      it 'returns false when set to true' do
        group.update_attribute(:lfs_enabled, true)

        expect(group.lfs_enabled?).to be_falsey
      end
    end
  end

365 366 367 368 369 370 371 372 373 374 375 376
  describe '#owners' do
    let(:owner) { create(:user) }
    let(:developer) { create(:user) }

    it 'returns the owners of a Group' do
      group.add_owner(owner)
      group.add_developer(developer)

      expect(group.owners).to eq([owner])
    end
  end

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
  def setup_group_members(group)
    members = {
      owner: create(:user),
      master: create(:user),
      developer: create(:user),
      reporter: create(:user),
      guest: create(:user),
      requester: create(:user)
    }

    group.add_user(members[:owner], GroupMember::OWNER)
    group.add_user(members[:master], GroupMember::MASTER)
    group.add_user(members[:developer], GroupMember::DEVELOPER)
    group.add_user(members[:reporter], GroupMember::REPORTER)
    group.add_user(members[:guest], GroupMember::GUEST)
    group.request_access(members[:requester])

    members
  end
396 397 398 399 400

  describe '#web_url' do
    it 'returns the canonical URL' do
      expect(group.web_url).to include("groups/#{group.name}")
    end
401 402 403 404 405 406

    context 'nested group' do
      let(:nested_group) { create(:group, :nested) }

      it { expect(nested_group.web_url).to include("groups/#{nested_group.full_path}") }
    end
407
  end
408 409

  describe 'nested group' do
410
    subject { build(:group, :nested) }
411 412

    it { is_expected.to be_valid }
413
    it { expect(subject.parent).to be_kind_of(described_class) }
414
  end
415

416
  describe '#members_with_parents', :nested_groups do
417 418 419 420 421 422 423 424 425
    let!(:group) { create(:group, :nested) }
    let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) }
    let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) }

    it 'returns parents members' do
      expect(group.members_with_parents).to include(developer)
      expect(group.members_with_parents).to include(master)
    end
  end
426

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
  describe '#direct_and_indirect_members', :nested_groups do
    let!(:group) { create(:group, :nested) }
    let!(:sub_group) { create(:group, parent: group) }
    let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) }
    let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) }
    let!(:other_developer) { group.add_user(create(:user), GroupMember::DEVELOPER) }

    it 'returns parents members' do
      expect(group.direct_and_indirect_members).to include(developer)
      expect(group.direct_and_indirect_members).to include(master)
    end

    it 'returns descendant members' do
      expect(group.direct_and_indirect_members).to include(other_developer)
    end
  end

  describe '#users_with_descendants', :nested_groups do
    let(:user_a) { create(:user) }
    let(:user_b) { create(:user) }

    let(:group) { create(:group) }
    let(:nested_group) { create(:group, parent: group) }
    let(:deep_nested_group) { create(:group, parent: nested_group) }

    it 'returns member users on every nest level without duplication' do
      group.add_developer(user_a)
      nested_group.add_developer(user_b)
      deep_nested_group.add_developer(user_a)

      expect(group.users_with_descendants).to contain_exactly(user_a, user_b)
      expect(nested_group.users_with_descendants).to contain_exactly(user_a, user_b)
      expect(deep_nested_group.users_with_descendants).to contain_exactly(user_a)
    end
  end

  describe '#direct_and_indirect_users', :nested_groups do
    let(:user_a) { create(:user) }
    let(:user_b) { create(:user) }
    let(:user_c) { create(:user) }
    let(:user_d) { create(:user) }

    let(:group) { create(:group) }
    let(:nested_group) { create(:group, parent: group) }
    let(:deep_nested_group) { create(:group, parent: nested_group) }
    let(:project) { create(:project, namespace: group) }

    before do
      group.add_developer(user_a)
      group.add_developer(user_c)
      nested_group.add_developer(user_b)
      deep_nested_group.add_developer(user_a)
      project.add_developer(user_d)
    end

    it 'returns member users on every nest level without duplication' do
      expect(group.direct_and_indirect_users).to contain_exactly(user_a, user_b, user_c, user_d)
      expect(nested_group.direct_and_indirect_users).to contain_exactly(user_a, user_b, user_c)
      expect(deep_nested_group.direct_and_indirect_users).to contain_exactly(user_a, user_b, user_c)
    end

    it 'does not return members of projects belonging to ancestor groups' do
      expect(nested_group.direct_and_indirect_users).not_to include(user_d)
    end
  end

  describe '#project_users_with_descendants', :nested_groups do
    let(:user_a) { create(:user) }
    let(:user_b) { create(:user) }
    let(:user_c) { create(:user) }

    let(:group) { create(:group) }
    let(:nested_group) { create(:group, parent: group) }
    let(:deep_nested_group) { create(:group, parent: nested_group) }
    let(:project_a) { create(:project, namespace: group) }
    let(:project_b) { create(:project, namespace: nested_group) }
    let(:project_c) { create(:project, namespace: deep_nested_group) }

    it 'returns members of all projects in group and subgroups' do
      project_a.add_developer(user_a)
      project_b.add_developer(user_b)
      project_c.add_developer(user_c)

      expect(group.project_users_with_descendants).to contain_exactly(user_a, user_b, user_c)
      expect(nested_group.project_users_with_descendants).to contain_exactly(user_b, user_c)
      expect(deep_nested_group.project_users_with_descendants).to contain_exactly(user_c)
    end
  end

516 517 518 519 520 521 522 523
  describe '#user_ids_for_project_authorizations' do
    it 'returns the user IDs for which to refresh authorizations' do
      master = create(:user)
      developer = create(:user)

      group.add_user(master, GroupMember::MASTER)
      group.add_user(developer, GroupMember::DEVELOPER)

524 525
      expect(group.user_ids_for_project_authorizations)
        .to include(master.id, developer.id)
526 527
    end
  end
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567

  describe '#update_two_factor_requirement' do
    let(:user) { create(:user) }

    before do
      group.add_user(user, GroupMember::OWNER)
    end

    it 'is called when require_two_factor_authentication is changed' do
      expect_any_instance_of(User).to receive(:update_two_factor_requirement)

      group.update!(require_two_factor_authentication: true)
    end

    it 'is called when two_factor_grace_period is changed' do
      expect_any_instance_of(User).to receive(:update_two_factor_requirement)

      group.update!(two_factor_grace_period: 23)
    end

    it 'is not called when other attributes are changed' do
      expect_any_instance_of(User).not_to receive(:update_two_factor_requirement)

      group.update!(description: 'foobar')
    end

    it 'calls #update_two_factor_requirement on each group member' do
      other_user = create(:user)
      group.add_user(other_user, GroupMember::OWNER)

      calls = 0
      allow_any_instance_of(User).to receive(:update_two_factor_requirement) do
        calls += 1
      end

      group.update!(require_two_factor_authentication: true, two_factor_grace_period: 23)

      expect(calls).to eq 2
    end
  end
Shinya Maeda's avatar
Shinya Maeda committed
568

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
  describe '#path_changed_hook' do
    let(:system_hook_service) { SystemHooksService.new }

    context 'for a new group' do
      let(:group) { build(:group) }

      before do
        expect(group).to receive(:system_hook_service).and_return(system_hook_service)
      end

      it 'does not trigger system hook' do
        expect(system_hook_service).to receive(:execute_hooks_for).with(group, :create)

        group.save!
      end
    end

    context 'for an existing group' do
      let(:group) { create(:group, path: 'old-path') }

      context 'when the path is changed' do
        let(:new_path) { 'very-new-path' }

        it 'triggers the rename system hook' do
          expect(group).to receive(:system_hook_service).and_return(system_hook_service)
          expect(system_hook_service).to receive(:execute_hooks_for).with(group, :rename)

          group.update_attributes!(path: new_path)
        end
      end

      context 'when the path is not changed' do
        it 'does not trigger system hook' do
          expect(group).not_to receive(:system_hook_service)

          group.update_attributes!(name: 'new name')
        end
      end
    end
  end

Shinya Maeda's avatar
Shinya Maeda committed
610
  describe '#secret_variables_for' do
611
    let(:project) { create(:project, group: group) }
Shinya Maeda's avatar
Shinya Maeda committed
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641

    let!(:secret_variable) do
      create(:ci_group_variable, value: 'secret', group: group)
    end

    let!(:protected_variable) do
      create(:ci_group_variable, :protected, value: 'protected', group: group)
    end

    subject { group.secret_variables_for('ref', project) }

    shared_examples 'ref is protected' do
      it 'contains all the variables' do
        is_expected.to contain_exactly(secret_variable, protected_variable)
      end
    end

    context 'when the ref is not protected' do
      before do
        stub_application_setting(
          default_branch_protection: Gitlab::Access::PROTECTION_NONE)
      end

      it 'contains only the secret variables' do
        is_expected.to contain_exactly(secret_variable)
      end
    end

    context 'when the ref is a protected branch' do
      before do
642
        allow(project).to receive(:protected_for?).with('ref').and_return(true)
Shinya Maeda's avatar
Shinya Maeda committed
643 644 645 646 647 648 649
      end

      it_behaves_like 'ref is protected'
    end

    context 'when the ref is a protected tag' do
      before do
650
        allow(project).to receive(:protected_for?).with('ref').and_return(true)
Shinya Maeda's avatar
Shinya Maeda committed
651 652 653 654 655
      end

      it_behaves_like 'ref is protected'
    end

656 657 658 659 660 661 662
    context 'when group has children', :postgresql do
      let(:group_child)      { create(:group, parent: group) }
      let(:group_child_2)    { create(:group, parent: group_child) }
      let(:group_child_3)    { create(:group, parent: group_child_2) }
      let(:variable_child)   { create(:ci_group_variable, group: group_child) }
      let(:variable_child_2) { create(:ci_group_variable, group: group_child_2) }
      let(:variable_child_3) { create(:ci_group_variable, group: group_child_3) }
Shinya Maeda's avatar
Shinya Maeda committed
663

664 665 666 667
      before do
        allow(project).to receive(:protected_for?).with('ref').and_return(true)
      end

Shinya Maeda's avatar
Shinya Maeda committed
668
      it 'returns all variables belong to the group and parent groups' do
669 670 671 672 673 674
        expected_array1 = [protected_variable, secret_variable]
        expected_array2 = [variable_child, variable_child_2, variable_child_3]
        got_array = group_child_3.secret_variables_for('ref', project).to_a

        expect(got_array.shift(2)).to contain_exactly(*expected_array1)
        expect(got_array).to eq(expected_array2)
Shinya Maeda's avatar
Shinya Maeda committed
675 676 677
      end
    end
  end
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693

  describe '#has_parent?' do
    context 'when the group has a parent' do
      it 'should be truthy' do
        group = create(:group, :nested)
        expect(group.has_parent?).to be_truthy
      end
    end

    context 'when the group has no parent' do
      it 'should be falsy' do
        group = create(:group, parent: nil)
        expect(group.has_parent?).to be_falsy
      end
    end
  end
Jan Provaznik's avatar
Jan Provaznik committed
694 695 696 697 698 699 700 701

  context 'with uploads' do
    it_behaves_like 'model with mounted uploader', true do
      let(:model_object) { create(:group, :with_avatar) }
      let(:upload_attribute) { :avatar }
      let(:uploader_class) { AttachmentUploader }
    end
  end
702
end