require 'spec_helper'
describe PivotalTracker::Story do
before do
@project = PivotalTracker::Project.find(102622)
end
context ".all" do
it "should return all stories" do
@project.stories.all.should be_a(Array)
@project.stories.all.first.should be_a(PivotalTracker::Story)
end
it "should allow filtering" do
@project.stories.all(:story_type => ['bug']).should be_a(Array)
@project.stories.all(:story_type => ['feature']).should be_a(Array)
end
it "should cache stories" do
count = @project.stories.all.count
@project.stories.all.count.should == count
bugs_count = @project.stories.all(:story_type => ['bug']).count
bugs_count.should_not == count
@project.stories.all(:story_type => ['bug']).count.should == bugs_count
end
end
context ".find" do
it "should return the matching story" do
@project.stories.find(4459994).should be_a(PivotalTracker::Story)
end
end
context ".create" do
it "should return the created story" do
@project.stories.create(:name => 'Create Stuff').should be_a(PivotalTracker::Story)
end
context "on failure" do
before do
FakeWeb.register_uri(:post, "#{PivotalTracker::Client.api_url}/projects/#{@project.id}/stories",
:body => %{
error#1 message
error#2 message
%},
:status => "422")
end
it "should not raise an exception" do
expect { @project.stories.create }.to_not raise_error(Exception)
end
it "should report errors encountered" do
story = @project.stories.create :name => "Invalid story"
story.errors.messages.should =~ ["error#1 message", "error#2 message"]
end
end
end
context ".attachments" do
it "should return an array of attachments" do
@story = @project.stories.find(4460598)
@story.attachments.should be_a(Array)
@story.attachments.first.should be_a(PivotalTracker::Attachment)
end
end
context ".move" do
let(:project_id) { @project.id }
let(:top_story_id) {4460598}
let(:bottom_story_id) {4459994}
let(:top_story) { @project.stories.find(top_story_id) }
let(:bottom_story) { @project.stories.find(bottom_story_id) }
it "should return the moved story when moved before" do
expected_uri = "#{PivotalTracker::Client.api_url}/projects/#{project_id}/stories/#{top_story_id}/moves?move\[move\]=before&move\[target\]=#{bottom_story_id}"
FakeWeb.register_uri(:post, expected_uri, :body => %{#{top_story_id}})
@moved_story = top_story.move(:before, bottom_story)
@moved_story.should be_a(PivotalTracker::Story)
@moved_story.id.should be(top_story_id)
end
it "should return the moved story when moved after" do
expected_uri = "#{PivotalTracker::Client.api_url}/projects/#{project_id}/stories/#{bottom_story_id}/moves?move\[move\]=after&move\[target\]=#{top_story_id}"
FakeWeb.register_uri(:post, expected_uri, :body => %{#{bottom_story_id}})
@moved_story = bottom_story.move(:after, top_story)
@moved_story.should be_a(PivotalTracker::Story)
@moved_story.id.should be(bottom_story_id)
end
it "should raise an error when trying to move in an invalid position" do
expect { top_story.move(:next_to, bottom_story) }.to raise_error(ArgumentError)
end
end
context ".move_to_project" do
let(:expected_uri) {"#{PivotalTracker::Client.api_url}/projects/#{project_id}/stories/#{story_id}"}
let(:project_id) { @project.id }
let(:movable_story) { @project.stories.find(4459994) }
let(:story_id) { movable_story.id }
let(:target_project) { PivotalTracker::Project.new(:id => 103014) }
before do
FakeWeb.register_uri(:put, expected_uri, :body => %{
#{target_project.id}
})
end
it "should return an updated story from the target project when passed a PivotalTracker::Story" do
target_story = PivotalTracker::Story.new(:project_id => target_project.id)
response = movable_story.move_to_project(target_story)
response.should_not be_nil
response.project_id.should == target_story.project_id
end
it "should return an updated story from the target project when passed a PivotalTracker::Project" do
response = movable_story.move_to_project(target_project)
response.project_id.should == target_project.id
end
it "should return an updated story from the target project when passed a String" do
response = movable_story.move_to_project(target_project.id.to_s)
response.project_id.should == target_project.id
end
it "should return an updated story from the target project when passed an Integer"do
response = movable_story.move_to_project(target_project.id.to_i)
response.project_id.should == target_project.id
end
end
context ".new" do
def story_for(attrs)
story = @project.stories.new(attrs)
@story = Crack::XML.parse(story.send(:to_xml))['story']
end
describe "attributes that are not sent to the tracker" do
it "should include id" do
story_for(:id => 10)["id"].should be_nil
end
it "should include url" do
story_for(:url => "somewhere")["url"].should be_nil
end
end
describe "attributes that are sent to the tracker" do
it "should include name" do
story_for(:name => "A user should...")["name"].should == "A user should..."
end
it "should include description" do
story_for(:description => "desc...")["description"].should == "desc..."
end
it "should include story_type" do
story_for(:story_type => "feature")["story_type"].should == "feature"
end
it "should include estimate" do
story_for(:estimate => 5)["estimate"].should == "5"
end
it "should include current_state" do
story_for(:current_state => "accepted")["current_state"].should == "accepted"
end
it "should include requested_by" do
story_for(:requested_by => "Joe Doe")["requested_by"].should == "Joe Doe"
end
it "should include owned_by" do
story_for(:owned_by => "Joe Doe")["owned_by"].should == "Joe Doe"
end
it "should include labels" do
story_for(:labels => "abc")["labels"].should == "abc"
end
it "should include other_id" do
story_for(:other_id => 10)["other_id"].should == "10"
end
it "should include integration_id" do
story_for(:integration_id => 1000)["integration_id"].should == '1000'
end
# the tracker returns 422 when this is included, even if it is not used
# it "should include jira_id" do
# story_for(:jira_id => 10)["jira_id"].should == "10"
# end
#
# it "should include jira_url" do
# story_for(:jira_url => "somewhere")["jira_url"].should == "somewhere"
# end
context "date attributes" do
before do
@datestring = "1984-09-20T10:23:00+00:00"
@date = DateTime.new(1984, 9, 20, 10, 23, 0, 0)
end
[:created_at, :accepted_at].each do |date_attribute|
it "should include #{date_attribute} date when given a string" do
story_for(:created_at => @date.to_s)["created_at"].should == @datestring
end
it "should include #{date_attribute} date when given a Time" do
story_for(:created_at => Time.parse(@date.to_s).utc)["created_at"].should == @datestring
end
it "should include #{date_attribute} date when given a DateTime" do
story_for(:created_at => @date)["created_at"].should == @datestring
end
it "should include #{date_attribute} date when given a Date" do
# Dates don't have time zones, but the time will be in local time, so we convert the date to create the expectation
story_for(:created_at => Date.new(1984, 9, 20))["created_at"].should == DateTime.new(1984, 9, 20).to_s
end
end
end
end
end
end