forecasted 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.gitignore +39 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +19 -0
- data/HISTORY.md +19 -0
- data/MIT-LICENSE +20 -0
- data/README.md +109 -0
- data/Rakefile +22 -0
- data/examples/basics.rb +35 -0
- data/examples/clear_account.rb +28 -0
- data/examples/project_create_script.rb +93 -0
- data/examples/task_assignments.rb +27 -0
- data/examples/user_assignments.rb +24 -0
- data/forecasted.gemspec +25 -0
- data/lib/ext/array.rb +52 -0
- data/lib/ext/date.rb +9 -0
- data/lib/ext/hash.rb +17 -0
- data/lib/ext/time.rb +5 -0
- data/lib/forecast/aggregate.rb +8 -0
- data/lib/forecast/api/account.rb +22 -0
- data/lib/forecast/api/aggregates.rb +20 -0
- data/lib/forecast/api/assignments.rb +63 -0
- data/lib/forecast/api/base.rb +68 -0
- data/lib/forecast/api/clients.rb +10 -0
- data/lib/forecast/api/expense_categories.rb +9 -0
- data/lib/forecast/api/expenses.rb +27 -0
- data/lib/forecast/api/invoice_categories.rb +26 -0
- data/lib/forecast/api/invoice_messages.rb +75 -0
- data/lib/forecast/api/invoice_payments.rb +31 -0
- data/lib/forecast/api/invoices.rb +35 -0
- data/lib/forecast/api/milestones.rb +21 -0
- data/lib/forecast/api/projects.rb +23 -0
- data/lib/forecast/api/reports.rb +53 -0
- data/lib/forecast/api/tasks.rb +36 -0
- data/lib/forecast/api/time.rb +48 -0
- data/lib/forecast/api/user_assignments.rb +34 -0
- data/lib/forecast/api/users.rb +21 -0
- data/lib/forecast/assignment.rb +7 -0
- data/lib/forecast/base.rb +111 -0
- data/lib/forecast/behavior/activatable.rb +31 -0
- data/lib/forecast/behavior/crud.rb +75 -0
- data/lib/forecast/client.rb +22 -0
- data/lib/forecast/credentials.rb +42 -0
- data/lib/forecast/errors.rb +26 -0
- data/lib/forecast/expense.rb +27 -0
- data/lib/forecast/expense_category.rb +10 -0
- data/lib/forecast/hardy_client.rb +80 -0
- data/lib/forecast/invoice.rb +107 -0
- data/lib/forecast/invoice_category.rb +9 -0
- data/lib/forecast/invoice_message.rb +8 -0
- data/lib/forecast/invoice_payment.rb +8 -0
- data/lib/forecast/line_item.rb +4 -0
- data/lib/forecast/model.rb +154 -0
- data/lib/forecast/project.rb +37 -0
- data/lib/forecast/rate_limit_status.rb +23 -0
- data/lib/forecast/task.rb +22 -0
- data/lib/forecast/time_entry.rb +25 -0
- data/lib/forecast/timezones.rb +130 -0
- data/lib/forecast/trackable_project.rb +38 -0
- data/lib/forecast/user_assignment.rb +30 -0
- data/lib/forecast/version.rb +3 -0
- data/lib/forecasted.rb +87 -0
- data/spec/factories.rb +17 -0
- data/spec/forecast/base_spec.rb +11 -0
- data/spec/functional/aggregates_spec.rb +64 -0
- data/spec/functional/assignments_spec.rb +131 -0
- data/spec/functional/errors_spec.rb +22 -0
- data/spec/functional/hardy_client_spec.rb +33 -0
- data/spec/functional/milestones_spec.rb +82 -0
- data/spec/functional/people_spec.rb +85 -0
- data/spec/functional/project_spec.rb +41 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/forecast_credentials.example.yml +6 -0
- data/spec/support/forecasted_helpers.rb +66 -0
- data/spec/support/json_examples.rb +9 -0
- metadata +189 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'forecast assignments' do
|
4
|
+
|
5
|
+
describe 'all' do
|
6
|
+
it 'works' do
|
7
|
+
cassette('assignments-all') do
|
8
|
+
assignments = forecast.assignments.all
|
9
|
+
|
10
|
+
expect(assignments.class).to be(Array)
|
11
|
+
expect(assignments.first.class).to be(Forecast::Assignment)
|
12
|
+
expect(assignments.size > 1).to eq(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'query by start_date' do
|
17
|
+
cassette('assignments-query-start_date') do
|
18
|
+
assignments = forecast.assignments.all({start_date: '2016-01-01'})
|
19
|
+
|
20
|
+
expect(assignments.class).to be(Array)
|
21
|
+
expect(assignments.first.class).to be(Forecast::Assignment)
|
22
|
+
expect(assignments.size > 1).to eq(true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'query by end_date' do
|
27
|
+
cassette('assignments-all-query-end_date') do
|
28
|
+
assignments = forecast.assignments.all({end_date: '2017-01-01'})
|
29
|
+
|
30
|
+
expect(assignments.class).to be(Array)
|
31
|
+
expect(assignments.first.class).to be(Forecast::Assignment)
|
32
|
+
expect(assignments.size > 1).to eq(true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'query by start_and end_date' do
|
37
|
+
cassette('assignments-all-query-start_date-and-end_date') do
|
38
|
+
assignments = forecast.assignments.all({start_date: '2016-01-01', end_date: '2017-01-01'})
|
39
|
+
|
40
|
+
expect(assignments.class).to be(Array)
|
41
|
+
expect(assignments.first.class).to be(Forecast::Assignment)
|
42
|
+
expect(assignments.size > 1).to eq(true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'query by status' do
|
47
|
+
cassette('assignments-all-query-status') do
|
48
|
+
assignments = forecast.assignments.all({state: 'active'})
|
49
|
+
|
50
|
+
expect(assignments.class).to be(Array)
|
51
|
+
expect(assignments.first.class).to be(Forecast::Assignment)
|
52
|
+
expect(assignments.size > 1).to eq(true)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'query by project_id' do
|
57
|
+
cassette('assignments-all-query-project_id') do
|
58
|
+
x = forecast.assignments.all({project_id: mm_forecast_project_id})
|
59
|
+
|
60
|
+
expect(x.class).to be(Array)
|
61
|
+
expect(x.first.class).to be(Forecast::Assignment)
|
62
|
+
expect(x.size > 1).to eq(true)
|
63
|
+
|
64
|
+
expect_belong_to_one_project(x)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'find' do
|
70
|
+
it 'works' do
|
71
|
+
cassette('assignments-find') do
|
72
|
+
assignment_id = forecast.assignments.all.first.id
|
73
|
+
assignment = forecast.assignments.find(assignment_id)
|
74
|
+
|
75
|
+
expect(assignment.class).to be(Forecast::Assignment)
|
76
|
+
expect(assignment.id > 1).to eq(true)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'by_project' do
|
82
|
+
it 'works' do
|
83
|
+
cassette('assignments-by_project') do
|
84
|
+
query = {
|
85
|
+
start_date: "2016-01-01",
|
86
|
+
end_date: "2018-01-01",
|
87
|
+
}
|
88
|
+
|
89
|
+
x = forecast.assignments.by_project(mm_forecast_project_id, query)
|
90
|
+
|
91
|
+
expect(x.class).to be(Array)
|
92
|
+
expect(x.first.class).to be(Forecast::Assignment)
|
93
|
+
expect(x.size > 1).to eq(true)
|
94
|
+
|
95
|
+
expect_belong_to_one_project(x)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'last_by_project' do
|
101
|
+
it 'works' do
|
102
|
+
cassette('assignments-last_by_project') do
|
103
|
+
x = forecast.assignments.last_by_project(mm_forecast_project_id)
|
104
|
+
|
105
|
+
expect(x.class).to be(Forecast::Assignment)
|
106
|
+
expect(x.project_id).to eq(mm_forecast_project_id)
|
107
|
+
|
108
|
+
# manually checked it
|
109
|
+
expect(x.end_date).to eq("2016-12-01")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe 'sum_allocation_seconds' do
|
115
|
+
it 'works' do
|
116
|
+
cassette('assignments-sum_allocation_seconds') do
|
117
|
+
query = {project_id: mm_forecast_project_id}
|
118
|
+
|
119
|
+
x = forecast.assignments.sum_allocation_seconds(query)
|
120
|
+
|
121
|
+
expect(x).to eq(62.0 * 3600)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def expect_belong_to_one_project(x)
|
127
|
+
project_ids = x.collect(&:project_id)
|
128
|
+
uniq_project_ids = project_ids.uniq
|
129
|
+
expect(uniq_project_ids.size).to eq(1)
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'forecast errors' do
|
4
|
+
before { WebMock.disable_net_connect! }
|
5
|
+
|
6
|
+
it "wraps errors" do
|
7
|
+
stub_request(:get, /\/projects/).to_return({:status => ['400', 'Bad Request']}, {:body => "[]", :status => 200})
|
8
|
+
expect { forecast.projects.all }.to raise_error(Forecast::BadRequest)
|
9
|
+
|
10
|
+
stub_request(:get, /\/projects/).to_return({:status => ['404', 'Not Found']}, {:body => "[]", :status => 200})
|
11
|
+
expect { forecast.projects.all }.to raise_error(Forecast::NotFound)
|
12
|
+
|
13
|
+
stub_request(:get, /\/projects/).to_return({:status => ['500', 'Server Error']}, {:body => "[]", :status => 200})
|
14
|
+
expect { forecast.projects.all }.to raise_error(Forecast::ServerError)
|
15
|
+
|
16
|
+
stub_request(:get, /\/projects/).to_return({:status => ['502', 'Bad Gateway']}, {:body => "[]", :status => 200})
|
17
|
+
expect { forecast.projects.all }.to raise_error(Forecast::Unavailable)
|
18
|
+
|
19
|
+
stub_request(:get, /\/projects/).to_return({:status => ['503', 'Rate Limited']}, {:body => "[]", :status => 200})
|
20
|
+
expect { forecast.projects.all }.to raise_error(Forecast::RateLimited)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'forecat hardy client' do
|
4
|
+
before do
|
5
|
+
WebMock.disable_net_connect!
|
6
|
+
@time = Time.now
|
7
|
+
end
|
8
|
+
|
9
|
+
# it "waits the alloted time out when over rate limit" do
|
10
|
+
# stub_request(:get, /\/clients/).to_return({:status => ['503', 'Rate Limited'], :headers => {"Retry-After" => "5"}}, {:body => "[]", :status => 200})
|
11
|
+
# hardy_harvest.clients.all
|
12
|
+
# Time.now.should be_within(10).of(@time)
|
13
|
+
# end
|
14
|
+
|
15
|
+
# it "waits a default time when over the rate limit" do
|
16
|
+
# stub_request(:get, /\/clients/).to_return({:status => ['503', 'Rate Limited']}, {:body => "[]", :status => 200})
|
17
|
+
# hardy_harvest.clients.all
|
18
|
+
# Time.now.should be_within(20).of(@time)
|
19
|
+
# end
|
20
|
+
|
21
|
+
# it "retries after known errors" do
|
22
|
+
# stub_request(:get, /\/rate_limit_status/).to_return({:body => '{"lockout_seconds":2,"last_access_at":"2011-06-18T17:13:22+00:00","max_calls":100,"count":1,"timeframe_limit":15}'})
|
23
|
+
|
24
|
+
# stub_request(:get, /\/clients/).to_return({:status => ['502', 'Bad Gateway']}).times(2).then.to_return({:body => "[]", :status => 200})
|
25
|
+
# hardy_harvest.clients.all.should == []
|
26
|
+
|
27
|
+
# stub_request(:get, /\/clients/).to_raise(Net::HTTPError.new("custom error", "")).times(2).then.to_return({:body => "[]", :status => 200})
|
28
|
+
# hardy_harvest.clients.all.should == []
|
29
|
+
|
30
|
+
# stub_request(:get, /\/clients/).to_return({:status => ['502', 'Bad Gateway']}).times(6).then.to_return({:body => "[]", :status => 200})
|
31
|
+
# expect { hardy_harvest.clients.all }.to raise_error(Harvest::Unavailable)
|
32
|
+
# end
|
33
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'forecast milestones' do
|
4
|
+
# it 'allows adding, updating and removing tasks' do
|
5
|
+
# cassette('tasks') do
|
6
|
+
# task = harvest.tasks.create(
|
7
|
+
# "name" => "A crud task",
|
8
|
+
# "billable_by_default" => true,
|
9
|
+
# "default_hourly_rate" => 120
|
10
|
+
# )
|
11
|
+
# task.default_hourly_rate.should == 120.0
|
12
|
+
|
13
|
+
# task.default_hourly_rate = 140
|
14
|
+
# task = harvest.tasks.update(task)
|
15
|
+
# task.default_hourly_rate.should == 140.0
|
16
|
+
|
17
|
+
# harvest.tasks.delete(task)
|
18
|
+
# harvest.tasks.all.select {|t| t.name == "A crud task"}.should == []
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
# context "task assignments" do
|
23
|
+
# it "allows adding, updating, and removing tasks from projects" do
|
24
|
+
# cassette('tasks2') do
|
25
|
+
# client = harvest.clients.create(FactoryGirl.attributes_for(:client))
|
26
|
+
|
27
|
+
# project = harvest.projects.create(
|
28
|
+
# "name" => "Test Project2",
|
29
|
+
# "active" => true,
|
30
|
+
# "notes" => "project to test the api",
|
31
|
+
# "client_id" => client.id
|
32
|
+
# )
|
33
|
+
|
34
|
+
# task1 = harvest.tasks.create(
|
35
|
+
# "name" => "A task for joe",
|
36
|
+
# "billable_by_default" => true,
|
37
|
+
# "default_hourly_rate" => 120
|
38
|
+
# )
|
39
|
+
|
40
|
+
# # need to keep at least one task on the project
|
41
|
+
# task2 = harvest.tasks.create(
|
42
|
+
# "name" => "A task for joe2",
|
43
|
+
# "billable_by_default" => true,
|
44
|
+
# "default_hourly_rate" => 100
|
45
|
+
# )
|
46
|
+
|
47
|
+
# harvest.task_assignments.create("project" => project, "task" => task1)
|
48
|
+
# harvest.task_assignments.create("project" => project, "task" => task2)
|
49
|
+
|
50
|
+
# all_assignments = harvest.task_assignments.all(project)
|
51
|
+
# assignment1 = all_assignments.detect {|a| a.task_id == task1.id }
|
52
|
+
# assignment2 = all_assignments.detect {|a| a.task_id == task2.id }
|
53
|
+
|
54
|
+
# assignment1.hourly_rate = 100
|
55
|
+
# assignment1 = harvest.task_assignments.update(assignment1)
|
56
|
+
# assignment1.hourly_rate.should == 100.0
|
57
|
+
|
58
|
+
# harvest.task_assignments.delete(assignment1)
|
59
|
+
# all_assignments = harvest.task_assignments.all(project)
|
60
|
+
# all_assignments.size.should == 1
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
|
64
|
+
# it "allows creating and assigning the task at the same time" do
|
65
|
+
# cassette('tasks3') do
|
66
|
+
# client = harvest.clients.create(FactoryGirl.attributes_for(:client))
|
67
|
+
|
68
|
+
# project = harvest.projects.create(
|
69
|
+
# "name" => "Test Project3",
|
70
|
+
# "active" => true,
|
71
|
+
# "notes" => "project to test the api",
|
72
|
+
# "client_id" => client.id
|
73
|
+
# )
|
74
|
+
|
75
|
+
# project2 = harvest.projects.create_task(project, "A simple task")
|
76
|
+
# project2.should == project
|
77
|
+
|
78
|
+
# harvest.task_assignments.all(project).size.should == 1
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'forecast users' do
|
4
|
+
# it "allows adding, updating, and removing users" do
|
5
|
+
# cassette("users") do
|
6
|
+
# user = harvest.users.create(
|
7
|
+
# "first_name" => "Edgar",
|
8
|
+
# "last_name" => "Ruth",
|
9
|
+
# "email" => "edgar@ruth.com",
|
10
|
+
# "timezone" => "cst",
|
11
|
+
# "is_admin" => "false",
|
12
|
+
# "telephone" => "444-4444"
|
13
|
+
# )
|
14
|
+
# user.id.should_not be_nil
|
15
|
+
|
16
|
+
# user.first_name = "Joey"
|
17
|
+
# user = harvest.users.update(user)
|
18
|
+
# user.first_name.should == "Joey"
|
19
|
+
|
20
|
+
# id = harvest.users.delete(user)
|
21
|
+
# harvest.users.all.map(&:id).should_not include(id)
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
|
25
|
+
# it "allows activating and deactivating users" do
|
26
|
+
# cassette("users2") do
|
27
|
+
# user = harvest.users.create(
|
28
|
+
# "first_name" => "John",
|
29
|
+
# "last_name" => "Ruth",
|
30
|
+
# "email" => "john@ruth.com",
|
31
|
+
# "timezone" => "cst",
|
32
|
+
# "is_admin" => "false",
|
33
|
+
# "telephone" => "444-4444"
|
34
|
+
# )
|
35
|
+
# user.should be_active
|
36
|
+
|
37
|
+
# user = harvest.users.deactivate(user)
|
38
|
+
# user.should_not be_active
|
39
|
+
|
40
|
+
# user = harvest.users.activate(user)
|
41
|
+
# user.should be_active
|
42
|
+
|
43
|
+
# harvest.users.delete(user)
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
|
47
|
+
# context "assignments" do
|
48
|
+
# it "allows adding, updating, and removing users from projects" do
|
49
|
+
# cassette('users4') do
|
50
|
+
# client = harvest.clients.create(
|
51
|
+
# "name" => "Joe's Steam Cleaning w/Users",
|
52
|
+
# "details" => "Building API Widgets across the country"
|
53
|
+
# )
|
54
|
+
|
55
|
+
# project = harvest.projects.create(
|
56
|
+
# "name" => "Test Project w/User",
|
57
|
+
# "active" => true,
|
58
|
+
# "notes" => "project to test the api",
|
59
|
+
# "client_id" => client.id
|
60
|
+
# )
|
61
|
+
|
62
|
+
# user = harvest.users.create(
|
63
|
+
# "first_name" => "Sally",
|
64
|
+
# "last_name" => "Ruth",
|
65
|
+
# "email" => "sally@ruth.com",
|
66
|
+
# "password" => "mypassword",
|
67
|
+
# "timezone" => "cst",
|
68
|
+
# "is_admin" => "false",
|
69
|
+
# "telephone" => "444-4444"
|
70
|
+
# )
|
71
|
+
|
72
|
+
|
73
|
+
# assignment = harvest.user_assignments.create("project" => project, "user" => user)
|
74
|
+
|
75
|
+
# assignment.hourly_rate = 100
|
76
|
+
# assignment = harvest.user_assignments.update(assignment)
|
77
|
+
# assignment.hourly_rate.should == 100.0
|
78
|
+
|
79
|
+
# harvest.user_assignments.delete(assignment)
|
80
|
+
# all_assignments = harvest.user_assignments.all(project)
|
81
|
+
# all_assignments.size.should == 1
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'forecast projects' do
|
4
|
+
|
5
|
+
describe 'all' do
|
6
|
+
it 'works' do
|
7
|
+
cassette('projects-all') do
|
8
|
+
projects = forecast.projects.all
|
9
|
+
|
10
|
+
expect(projects.class).to be(Array)
|
11
|
+
expect(projects.size > 1).to eq(true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'find' do
|
17
|
+
it 'works' do
|
18
|
+
cassette('projects-find') do
|
19
|
+
projects = forecast.projects.all
|
20
|
+
project_id = projects.first.id
|
21
|
+
project = forecast.projects.find(project_id)
|
22
|
+
|
23
|
+
expect(project.class).to be(Forecast::Project)
|
24
|
+
expect(project.id > 1).to eq(true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'select_by_harvest_id()' do
|
30
|
+
it 'works' do
|
31
|
+
cassette('project-find_by_harvest_id') do
|
32
|
+
project = forecast.projects.find_by_harvest_id(mm_harvest_project_id)
|
33
|
+
|
34
|
+
expect(project.class).to be(Forecast::Project)
|
35
|
+
expect(project.id > 1).to eq(true)
|
36
|
+
expect(project.harvest_id).to eq(mm_harvest_project_id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forecasted'
|
2
|
+
require 'webmock/rspec'
|
3
|
+
require 'vcr'
|
4
|
+
require 'factory_girl'
|
5
|
+
|
6
|
+
require 'byebug' if ENV['TRAVIS'].nil?
|
7
|
+
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require File.expand_path(f) }
|
9
|
+
|
10
|
+
VCR.configure do |c|
|
11
|
+
c.cassette_library_dir = '.cassettes'
|
12
|
+
c.hook_into :webmock
|
13
|
+
|
14
|
+
c.default_cassette_options = {
|
15
|
+
# force cassettes to re_record when we pass VCR_REFRESH=true
|
16
|
+
re_record_interval: ENV['VCR_REFRESH'] == 'true' ? 0 : nil
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
FactoryGirl.find_definitions
|
21
|
+
|
22
|
+
RSpec.configure do |config|
|
23
|
+
config.include ForecastedHelpers
|
24
|
+
|
25
|
+
config.before(:suite) do
|
26
|
+
WebMock.allow_net_connect!
|
27
|
+
cassette("clean") do
|
28
|
+
ForecastedHelpers.clean_remote
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
config.before(:each) do
|
33
|
+
WebMock.allow_net_connect!
|
34
|
+
end
|
35
|
+
|
36
|
+
def cassette(*args)
|
37
|
+
VCR.use_cassette(*args) do
|
38
|
+
yield
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ForecastedHelpers
|
2
|
+
|
3
|
+
def mm_harvest_project_id
|
4
|
+
11877152
|
5
|
+
end
|
6
|
+
|
7
|
+
def mm_forecast_project_id
|
8
|
+
767184
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def self.credentials
|
13
|
+
unless File.exist?("#{File.dirname(__FILE__)}/forecast_credentials.yml")
|
14
|
+
raise "You need a credentials file in support/forecast_credentials.yml!!"
|
15
|
+
end
|
16
|
+
@credentials ||= YAML.load_file("#{File.dirname(__FILE__)}/forecast_credentials.yml")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.simple_forecast
|
20
|
+
Forecast.client({
|
21
|
+
forecast_account_id: credentials["forecast_account_id"],
|
22
|
+
access_token: credentials["access_token"]
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def credentials
|
27
|
+
ForecastedHelpers.credentials
|
28
|
+
end
|
29
|
+
|
30
|
+
def forecast
|
31
|
+
@forecast ||= ForecastedHelpers.simple_forecast
|
32
|
+
end
|
33
|
+
|
34
|
+
def hardy_forecast
|
35
|
+
Forecast.hardy_client(
|
36
|
+
forecast_account_id: credentials[:forecast_account_id],
|
37
|
+
access_token: credentials[:access_token]
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.clean_remote
|
42
|
+
return unless ENV['TRAVIS'].nil?
|
43
|
+
|
44
|
+
forecast = simple_forecast
|
45
|
+
|
46
|
+
# harvest = simple_harvest
|
47
|
+
# forecast.users.all.each do |u|
|
48
|
+
# harvest.reports.expenses_by_user(u, Time.utc(2000, 1, 1), Time.utc(2014, 6, 21)).each do |expense|
|
49
|
+
# harvest.expenses.delete(expense, u)
|
50
|
+
# end
|
51
|
+
|
52
|
+
# harvest.reports.time_by_user(u, Time.utc(2000, 1, 1), Time.utc(2014, 6, 21)).each do |time|
|
53
|
+
# harvest.time.delete(time, u)
|
54
|
+
# end
|
55
|
+
|
56
|
+
# harvest.users.delete(u) if u.email != credentials["username"]
|
57
|
+
# end
|
58
|
+
|
59
|
+
# we store expenses on this date in the tests
|
60
|
+
# harvest.expenses.all(Time.utc(2009, 12, 28)).each {|e| harvest.expenses.delete(e) }
|
61
|
+
|
62
|
+
# %w(expense_categories time projects invoices contacts clients tasks).each do |collection|
|
63
|
+
# harvest.send(collection).all.each {|m| harvest.send(collection).delete(m) }
|
64
|
+
# end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
shared_examples_for 'a json sanitizer' do |keys|
|
2
|
+
keys.each do |key|
|
3
|
+
it "doesn't include '#{key}' when serializing to json" do
|
4
|
+
instance = described_class.new
|
5
|
+
instance[key] = 10
|
6
|
+
instance.as_json[instance.class.json_root].keys.should_not include(key)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|