westarete-tracker-tools 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/spec/helper.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ require 'westarete-tracker-tools'
14
+
15
+ include WestAreteTrackerTools
16
+
17
+ require 'vcr_helper'
@@ -0,0 +1,132 @@
1
+ require 'helper'
2
+
3
+ describe Project do
4
+ use_vcr_cassette :record => :new_episodes, :match_requests_on => [:uri, :method]
5
+ before do
6
+ @project = Project.find_by_name('westarete-tracker-tools-test')
7
+ end
8
+ describe '.all' do
9
+ before do
10
+ @projects = Project.all
11
+ end
12
+ it 'returns all active projects' do
13
+ @projects.length.should == 15
14
+ @projects.first.should respond_to(:name)
15
+ @projects.collect(&:name).should == [
16
+ 'altoonabustest.com',
17
+ 'Background Questionnaires',
18
+ 'BellefonteDentistry.com',
19
+ 'Captcha',
20
+ 'centralinsgrp.com',
21
+ 'coolblue.com',
22
+ 'famfound.net',
23
+ 'ionmodern.com',
24
+ 'LifeViz',
25
+ 'oneononefit.com',
26
+ 'PAIG',
27
+ 'pasubway.com',
28
+ 'ReDi Index',
29
+ 'trailspace.com',
30
+ 'westarete-tracker-tools-test'
31
+ ]
32
+ end
33
+ end
34
+ describe '.find_by_name' do
35
+ context 'if the name exists' do
36
+ it 'returns the project' do
37
+ @project.name.should == 'westarete-tracker-tools-test'
38
+ end
39
+ end
40
+ context 'if the name does not exist' do
41
+ before do
42
+ @project = Project.find_by_name('not there')
43
+ end
44
+ it 'returns nil' do
45
+ @project.should be_nil
46
+ end
47
+ end
48
+ end
49
+ describe "#backlog" do
50
+ before do
51
+ @stories = @project.backlog
52
+ end
53
+ it 'returns all of the stories in the backlog, including the current iteration' do
54
+ @stories.length.should == 17
55
+ @stories.each { |s| s.should be_kind_of(Story) }
56
+ @stories.first.name.should == 'Newly accepted feature'
57
+ @stories.last.name.should == 'Release'
58
+ end
59
+ end
60
+ describe '#current' do
61
+ before do
62
+ @stories = @project.current
63
+ end
64
+ it 'returns all of the stories in the current iteration' do
65
+ @stories.collect(&:name).should == [
66
+ 'Newly accepted feature',
67
+ 'Rejected feature',
68
+ 'Delivered feature',
69
+ 'Finished feature',
70
+ 'Started feature',
71
+ ]
72
+ end
73
+ end
74
+ describe '#done' do
75
+ context 'when given no arguments' do
76
+ before do
77
+ @stories = @project.done
78
+ end
79
+ it 'returns all stories that have been completed in any iteration' do
80
+ @stories.collect(&:name).should == [
81
+ 'Old accepted feature',
82
+ 'Accepted feature',
83
+ 'Newly accepted feature',
84
+ ]
85
+ end
86
+ end
87
+ context 'when given a -2' do
88
+ before do
89
+ @stories = @project.done(-2)
90
+ end
91
+ it 'returns all stories that were completed two iterations ago' do
92
+ @stories.collect(&:name).should == ['Old accepted feature']
93
+ end
94
+ end
95
+ context 'when given a -1' do
96
+ before do
97
+ @stories = @project.done(-1)
98
+ end
99
+ it 'returns all stories that were completed in last iteration' do
100
+ @stories.collect(&:name).should == ['Accepted feature']
101
+ end
102
+ end
103
+ context 'when given a 0' do
104
+ before do
105
+ @stories = @project.done(0)
106
+ end
107
+ it 'returns all stories that have been completed during the current iteration' do
108
+ @stories.collect(&:name).should == ['Newly accepted feature']
109
+ end
110
+ end
111
+ context 'when given a 1' do
112
+ it 'raises an ArgumentError' do
113
+ lambda { @project.done(1) }.should raise_error(ArgumentError)
114
+ end
115
+ end
116
+ end
117
+ describe '#name' do
118
+ it "returns the project's name" do
119
+ @project.name.should == 'westarete-tracker-tools-test'
120
+ end
121
+ end
122
+ describe '#tracker_id' do
123
+ it "returns Pivotal Tracker's id for the project" do
124
+ @project.tracker_id.should == 213679
125
+ end
126
+ end
127
+ describe '#url' do
128
+ it "returns Pivotal Tracker's url for the project" do
129
+ @project.url.should == 'http://www.pivotaltracker.com/projects/213679'
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,408 @@
1
+ require 'helper'
2
+
3
+ describe Story do
4
+ use_vcr_cassette :record => :new_episodes, :match_requests_on => [:uri, :method]
5
+ before do
6
+ @project = Project.find_by_name('westarete-tracker-tools-test')
7
+ @backlog = @project.backlog
8
+ @story = @backlog.detect { |s| s.name == 'Valid story' }
9
+ end
10
+ describe 'validations' do
11
+ context 'a bug' do
12
+ subject { @backlog.detect { |s| s.name == 'Bug' } }
13
+ it { should be_valid }
14
+ end
15
+ context 'a chore' do
16
+ subject { @backlog.detect { |s| s.name == 'Chore' } }
17
+ it { should be_valid }
18
+ end
19
+ context 'a feature' do
20
+ context 'that is valid' do
21
+ subject { @story }
22
+ it { should be_valid }
23
+ end
24
+ context 'that has no risk' do
25
+ before do
26
+ @story = @backlog.detect { |s| s.name == 'Story with no risk' }
27
+ end
28
+ it 'complains about the missing risk' do
29
+ @story.should_not be_valid
30
+ @story.errors[:risk].should include("can't be blank")
31
+ end
32
+ end
33
+ context 'that has no price' do
34
+ before do
35
+ @story = @backlog.detect { |s| s.name == 'Story with comments, but no price' }
36
+ end
37
+ it 'complains about the missing price' do
38
+ @story.should_not be_valid
39
+ @story.errors[:price].should include("can't be blank")
40
+ end
41
+ end
42
+ context 'that has no point estimate' do
43
+ before do
44
+ @story = @backlog.detect { |s| s.name == 'Story with no point estimate' }
45
+ end
46
+ it 'complains about the missing point estimate' do
47
+ @story.should_not be_valid
48
+ @story.errors[:points].should include("can't be blank")
49
+ end
50
+ end
51
+ context 'that has no description' do
52
+ before do
53
+ @story = @backlog.detect { |s| s.name == 'Story with no description' }
54
+ end
55
+ it 'complains about the missing description' do
56
+ @story.should_not be_valid
57
+ @story.errors[:description].should include("can't be blank")
58
+ end
59
+ end
60
+ context "that has a description that's too short" do
61
+ before do
62
+ @story = @backlog.detect { |s| s.name == 'Story with a description that is too short' }
63
+ end
64
+ it 'complains about the BS description' do
65
+ @story.should_not be_valid
66
+ @story.errors[:description].should include("is too short (minimum is 70 characters)")
67
+ end
68
+ end
69
+ end
70
+ end
71
+ context 'that is a feature' do
72
+ describe '#feature?' do
73
+ subject { @story.feature? }
74
+ it { should be_true }
75
+ end
76
+ describe '#bug?' do
77
+ subject { @story.bug? }
78
+ it { should be_false }
79
+ end
80
+ describe '#chore?' do
81
+ subject { @story.chore? }
82
+ it { should be_false }
83
+ end
84
+ describe '#release?' do
85
+ subject { @story.release? }
86
+ it { should be_false }
87
+ end
88
+ end
89
+ context 'that is a bug' do
90
+ before do
91
+ @story = @backlog.detect { |s| s.name == 'Bug' }
92
+ end
93
+ describe '#feature?' do
94
+ subject { @story.feature? }
95
+ it { should be_false }
96
+ end
97
+ describe '#bug?' do
98
+ subject { @story.bug? }
99
+ it { should be_true }
100
+ end
101
+ describe '#chore?' do
102
+ subject { @story.chore? }
103
+ it { should be_false }
104
+ end
105
+ describe '#release?' do
106
+ subject { @story.release? }
107
+ it { should be_false }
108
+ end
109
+ describe '#points' do
110
+ subject { @story.points }
111
+ it { should be_nil }
112
+ end
113
+ describe '#price' do
114
+ subject { @story.price }
115
+ it { should be_nil }
116
+ end
117
+ describe '#risk' do
118
+ subject { @story.risk }
119
+ it { should be_nil }
120
+ end
121
+ end
122
+ context 'that is a chore' do
123
+ before do
124
+ @story = @backlog.detect { |s| s.name == 'Chore' }
125
+ end
126
+ describe '#feature?' do
127
+ subject { @story.feature? }
128
+ it { should be_false }
129
+ end
130
+ describe '#bug?' do
131
+ subject { @story.bug? }
132
+ it { should be_false }
133
+ end
134
+ describe '#chore?' do
135
+ subject { @story.chore? }
136
+ it { should be_true }
137
+ end
138
+ describe '#release?' do
139
+ subject { @story.release? }
140
+ it { should be_false }
141
+ end
142
+ describe '#points' do
143
+ subject { @story.points }
144
+ it { should be_nil }
145
+ end
146
+ describe '#price' do
147
+ subject { @story.price }
148
+ it { should be_nil }
149
+ end
150
+ describe '#risk' do
151
+ subject { @story.risk }
152
+ it { should be_nil }
153
+ end
154
+ end
155
+ context 'that is a release' do
156
+ before do
157
+ @story = @backlog.detect { |s| s.name == 'Release' }
158
+ end
159
+ describe '#feature?' do
160
+ subject { @story.feature? }
161
+ it { should be_false }
162
+ end
163
+ describe '#bug?' do
164
+ subject { @story.bug? }
165
+ it { should be_false }
166
+ end
167
+ describe '#chore?' do
168
+ subject { @story.chore? }
169
+ it { should be_false }
170
+ end
171
+ describe '#release?' do
172
+ subject { @story.release? }
173
+ it { should be_true }
174
+ end
175
+ describe '#points' do
176
+ subject { @story.points }
177
+ it { should be_nil }
178
+ end
179
+ describe '#price' do
180
+ subject { @story.price }
181
+ it { should be_nil }
182
+ end
183
+ describe '#risk' do
184
+ subject { @story.risk }
185
+ it { should be_nil }
186
+ end
187
+ end
188
+ describe '#accepted_at' do
189
+ context 'for a story that is not started' do
190
+ subject { @story.accepted_at }
191
+ it { should be_nil }
192
+ end
193
+ context 'for a story that is in progress' do
194
+ subject do
195
+ @project.backlog.detect { |story| story.name == 'Started feature' }.accepted_at
196
+ end
197
+ it { should be_nil }
198
+ end
199
+ context 'for a story that is complete' do
200
+ before do
201
+ @story = @project.done.detect { |story| story.name == 'Accepted feature' }
202
+ end
203
+ it 'returns a date and time' do
204
+ @story.accepted_at.should be_kind_of(DateTime)
205
+ end
206
+ end
207
+ end
208
+ describe '#comments' do
209
+ context 'when there are comments' do
210
+ before do
211
+ @story = @project.backlog.detect { |s| s.name == 'Story with comments and two prices' }
212
+ end
213
+ it 'returns an array of note objects in chronological order' do
214
+ @story.comments.length.should == 2
215
+ @story.comments[0].noted_at.should < @story.comments[1].noted_at
216
+ end
217
+ end
218
+ context 'when there are no comments' do
219
+ before do
220
+ @story = @project.backlog.detect { |s| s.name == 'Story with no comments' }
221
+ end
222
+ it 'returns an empty array' do
223
+ @story.comments.should be_empty
224
+ end
225
+ end
226
+ end
227
+ describe '#complete?' do
228
+ context 'for a story that is not started' do
229
+ subject { @story.complete? }
230
+ it { should be_false }
231
+ end
232
+ context 'for a story that is in progress' do
233
+ subject do
234
+ @project.backlog.detect { |story| story.name == 'Started feature' }.complete?
235
+ end
236
+ it { should be_false }
237
+ end
238
+ context 'for a story that is complete' do
239
+ subject do
240
+ @project.done.detect { |story| story.name == 'Accepted feature' }.complete?
241
+ end
242
+ it { should be_true }
243
+ end
244
+ end
245
+ describe '#current_state' do
246
+ it 'returns a string that describes the current state' do
247
+ @story.current_state.should == 'unstarted'
248
+ end
249
+ end
250
+ describe '#description' do
251
+ it 'returns the description body' do
252
+ @story.description.should =~ /^As a /
253
+ end
254
+ end
255
+ describe '#finished?' do
256
+ context 'for a story that is not yet started' do
257
+ subject do
258
+ @project.backlog.detect { |story| story.name == 'Not yet started feature' }.finished?
259
+ end
260
+ it { should be_false }
261
+ end
262
+ context 'for a story that is started' do
263
+ subject do
264
+ @project.backlog.detect { |story| story.name == 'Started feature' }.finished?
265
+ end
266
+ it { should be_false }
267
+ end
268
+ context 'for a story that is finished' do
269
+ subject do
270
+ @project.backlog.detect { |story| story.name == 'Finished feature' }.finished?
271
+ end
272
+ it { should be_true }
273
+ end
274
+ context 'for a story that is delivered' do
275
+ subject do
276
+ @project.backlog.detect { |story| story.name == 'Delivered feature' }.finished?
277
+ end
278
+ it { should be_true }
279
+ end
280
+ context 'for a story that is rejected' do
281
+ subject do
282
+ @project.backlog.detect { |story| story.name == 'Rejected feature' }.finished?
283
+ end
284
+ it { should be_true }
285
+ end
286
+ context 'for a story that is accepted' do
287
+ subject do
288
+ @project.done.detect { |story| story.name == 'Accepted feature' }.finished?
289
+ end
290
+ it { should be_false }
291
+ end
292
+ end
293
+ describe '#incomplete?' do
294
+ context 'for a story that is not started' do
295
+ subject { @story.incomplete? }
296
+ it { should be_true }
297
+ end
298
+ context 'for a story that is in progress' do
299
+ subject do
300
+ @project.backlog.detect { |story| story.name == 'Started feature' }.incomplete?
301
+ end
302
+ it { should be_true }
303
+ end
304
+ context 'for a story that is complete' do
305
+ subject do
306
+ @project.done.detect { |story| story.name == 'Accepted feature' }.incomplete?
307
+ end
308
+ it { should be_false }
309
+ end
310
+ end
311
+ describe "#name" do
312
+ it "returns the story's name, without the risk rating" do
313
+ @story.name.should == 'Valid story'
314
+ end
315
+ end
316
+ describe '#owner' do
317
+ context 'when there is an owner' do
318
+ before do
319
+ @story = @project.backlog.detect { |story| story.name == 'Started feature' }
320
+ end
321
+ it "should return the owner's full name" do
322
+ @story.owner.should == 'Scott Woods'
323
+ end
324
+ end
325
+ context 'when there is no owner' do
326
+ subject do
327
+ @project.backlog.detect { |story| story.name == 'Not yet started feature' }.owner
328
+ end
329
+ it { should be_nil }
330
+ end
331
+ end
332
+ describe '#points' do
333
+ context 'if the story has been estimated' do
334
+ it 'returns the point estimate for the story' do
335
+ @story.points.should == 2
336
+ end
337
+ end
338
+ context 'if the story has not been estimated' do
339
+ before do
340
+ @story = @backlog.detect { |s| s.name == 'Story with no point estimate' }
341
+ end
342
+ it 'returns nil' do
343
+ @story.points.should be_nil
344
+ end
345
+ end
346
+ end
347
+ describe '#price' do
348
+ context 'when there are no comments' do
349
+ before do
350
+ @story = @backlog.detect { |s| s.name == 'Story with no comments' }
351
+ end
352
+ it 'returns nil' do
353
+ @story.price.should be_nil
354
+ end
355
+ end
356
+ context 'when there are comments, but none mention cost or price' do
357
+ before do
358
+ @story = @backlog.detect { |s| s.name == 'Story with comments, but no price' }
359
+ end
360
+ it 'returns nil' do
361
+ @story.price.should be_nil
362
+ end
363
+ end
364
+ context 'when there are multiple comments that mention price' do
365
+ before do
366
+ @story = @backlog.detect { |s| s.name == 'Story with comments and two prices' }
367
+ end
368
+ it 'uses the most recent comment by Scott Woods' do
369
+ @story.price.should == 100
370
+ end
371
+ end
372
+ end
373
+ describe "#requester" do
374
+ it "returns the requester's name" do
375
+ @story.requester.should == 'Scott Woods'
376
+ end
377
+ end
378
+ describe '#risk' do
379
+ context 'if a risk is present' do
380
+ it 'returns the risk rating for the story' do
381
+ @story.risk.should == 'R'
382
+ end
383
+ end
384
+ context 'if no risk is present' do
385
+ before do
386
+ @story = @backlog.detect { |s| s.name == 'Story with no risk' }
387
+ end
388
+ it 'returns nil' do
389
+ @story.risk.should be_nil
390
+ end
391
+ end
392
+ end
393
+ describe '#story_type' do
394
+ it 'returns a string of the story type' do
395
+ @story.story_type.should == 'feature'
396
+ end
397
+ end
398
+ describe '#tracker_id' do
399
+ it "returns Pivotal Tracker's id for the story" do
400
+ @story.tracker_id.should == 9072189
401
+ end
402
+ end
403
+ describe '#url' do
404
+ it 'returns the URL for the story' do
405
+ @story.url.should == 'http://www.pivotaltracker.com/story/show/9072189'
406
+ end
407
+ end
408
+ end