milestone_spec.rb 5.85 KB
Newer Older
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
1 2 3 4
# == Schema Information
#
# Table name: milestones
#
5 6 7
#  id          :integer          not null, primary key
#  title       :string(255)      not null
#  project_id  :integer          not null
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
8 9
#  description :text
#  due_date    :date
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
10 11
#  created_at  :datetime
#  updated_at  :datetime
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
12
#  state       :string(255)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
13
#  iid         :integer
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
14 15
#

16 17
require 'spec_helper'

Douwe Maan's avatar
Douwe Maan committed
18
describe Milestone, models: true do
19
  describe "Associations" do
20 21
    it { is_expected.to belong_to(:project) }
    it { is_expected.to have_many(:issues) }
22 23 24
  end

  describe "Validation" do
25 26 27 28
    before do
      allow(subject).to receive(:set_iid).and_return(false)
    end

29 30
    it { is_expected.to validate_presence_of(:title) }
    it { is_expected.to validate_presence_of(:project) }
31 32
  end

33 34
  let(:milestone) { create(:milestone) }
  let(:issue) { create(:issue) }
35
  let(:user) { create(:user) }
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50
  describe "unique milestone title per project" do
    it "shouldn't accept the same title in a project twice" do
      new_milestone = Milestone.new(project: milestone.project, title: milestone.title)
      expect(new_milestone).not_to be_valid
    end

    it "should accept the same title in another project" do
      project = build(:project)
      new_milestone = Milestone.new(project: project, title: milestone.title)

      expect(new_milestone).to be_valid
    end
  end

51 52
  describe "#percent_complete" do
    it "should not count open issues" do
53
      milestone.issues << issue
54
      expect(milestone.percent_complete(user)).to eq(0)
55 56
    end

57
    it "should count closed issues" do
Andrew8xx8's avatar
Andrew8xx8 committed
58
      issue.close
59
      milestone.issues << issue
60
      expect(milestone.percent_complete(user)).to eq(100)
61
    end
62

63
    it "should recover from dividing by zero" do
64
      expect(milestone.percent_complete(user)).to eq(0)
65 66 67
    end
  end

68 69 70
  describe "#expires_at" do
    it "should be nil when due_date is unset" do
      milestone.update_attributes(due_date: nil)
71
      expect(milestone.expires_at).to be_nil
72 73
    end

74 75
    it "should not be nil when due_date is set" do
      milestone.update_attributes(due_date: Date.tomorrow)
76
      expect(milestone.expires_at).to be_present
77
    end
78
  end
79 80 81 82

  describe :expired? do
    context "expired" do
      before do
83
        allow(milestone).to receive(:due_date).and_return(Date.today.prev_year)
84 85
      end

86
      it { expect(milestone.expired?).to be_truthy }
87 88 89 90
    end

    context "not expired" do
      before do
91
        allow(milestone).to receive(:due_date).and_return(Date.today.next_year)
92 93
      end

94
      it { expect(milestone.expired?).to be_falsey }
95 96 97 98 99
    end
  end

  describe :percent_complete do
    before do
100
      allow(milestone).to receive_messages(
101 102 103 104 105
        closed_items_count: 3,
        total_items_count: 4
      )
    end

106
    it { expect(milestone.percent_complete(user)).to eq(75) }
107 108 109 110 111
  end

  describe :items_count do
    before do
      milestone.issues << create(:issue)
Andrew8xx8's avatar
Andrew8xx8 committed
112
      milestone.issues << create(:closed_issue)
113 114 115
      milestone.merge_requests << create(:merge_request)
    end

116 117 118
    it { expect(milestone.closed_items_count(user)).to eq(1) }
    it { expect(milestone.total_items_count(user)).to eq(3) }
    it { expect(milestone.is_empty?(user)).to be_falsey }
119 120 121
  end

  describe :can_be_closed? do
122
    it { expect(milestone.can_be_closed?).to be_truthy }
123
  end
124

125
  describe :total_items_count do
126
    before do
127 128
      create :closed_issue, milestone: milestone
      create :merge_request, milestone: milestone
129
    end
130

131
    it 'Should return total count of issues and merge requests assigned to milestone' do
132
      expect(milestone.total_items_count(user)).to eq 2
133 134 135 136
    end
  end

  describe :can_be_closed? do
137
    before do
138
      milestone = create :milestone
139 140
      create :closed_issue, milestone: milestone

141
      create :issue
142
    end
143

Johannes Schleifenbaum's avatar
Johannes Schleifenbaum committed
144
    it 'should be true if milestone active and all nested issues closed' do
145
      expect(milestone.can_be_closed?).to be_truthy
146 147
    end

Johannes Schleifenbaum's avatar
Johannes Schleifenbaum committed
148
    it 'should be false if milestone active and not all nested issues closed' do
149
      issue.milestone = milestone
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
150
      issue.save
151

152
      expect(milestone.can_be_closed?).to be_falsey
153 154 155
    end
  end

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
  describe '#sort_issues' do
    let(:milestone) { create(:milestone) }

    let(:issue1) { create(:issue, milestone: milestone, position: 1) }
    let(:issue2) { create(:issue, milestone: milestone, position: 2) }
    let(:issue3) { create(:issue, milestone: milestone, position: 3) }
    let(:issue4) { create(:issue, position: 42) }

    it 'sorts the given issues' do
      milestone.sort_issues([issue3.id, issue2.id, issue1.id])

      issue1.reload
      issue2.reload
      issue3.reload

      expect(issue1.position).to eq(3)
      expect(issue2.position).to eq(2)
      expect(issue3.position).to eq(1)
    end

    it 'ignores issues not part of the milestone' do
      milestone.sort_issues([issue3.id, issue2.id, issue1.id, issue4.id])

      issue4.reload

      expect(issue4.position).to eq(42)
    end
  end
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213

  describe '.search' do
    let(:milestone) { create(:milestone, title: 'foo', description: 'bar') }

    it 'returns milestones with a matching title' do
      expect(described_class.search(milestone.title)).to eq([milestone])
    end

    it 'returns milestones with a partially matching title' do
      expect(described_class.search(milestone.title[0..2])).to eq([milestone])
    end

    it 'returns milestones with a matching title regardless of the casing' do
      expect(described_class.search(milestone.title.upcase)).to eq([milestone])
    end

    it 'returns milestones with a matching description' do
      expect(described_class.search(milestone.description)).to eq([milestone])
    end

    it 'returns milestones with a partially matching description' do
      expect(described_class.search(milestone.description[0..2])).
        to eq([milestone])
    end

    it 'returns milestones with a matching description regardless of the casing' do
      expect(described_class.search(milestone.description.upcase)).
        to eq([milestone])
    end
  end
214
end