harvested 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/.gitignore +23 -0
- data/HISTORY +16 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/examples/basics.rb +35 -0
- data/examples/clear_account.rb +28 -0
- data/examples/task_assignments.rb +27 -0
- data/examples/user_assignments.rb +24 -0
- data/features/account.feature +7 -0
- data/features/client_contacts.feature +23 -0
- data/features/clients.feature +29 -0
- data/features/errors.feature +25 -0
- data/features/expense_categories.feature +21 -0
- data/features/expenses.feature +55 -0
- data/features/hardy_client.feature +40 -0
- data/features/projects.feature +39 -0
- data/features/reporting.feature +72 -0
- data/features/step_definitions/account_steps.rb +7 -0
- data/features/step_definitions/assignment_steps.rb +100 -0
- data/features/step_definitions/contact_steps.rb +11 -0
- data/features/step_definitions/debug_steps.rb +3 -0
- data/features/step_definitions/error_steps.rb +113 -0
- data/features/step_definitions/expenses_steps.rb +46 -0
- data/features/step_definitions/harvest_steps.rb +8 -0
- data/features/step_definitions/model_steps.rb +90 -0
- data/features/step_definitions/people_steps.rb +4 -0
- data/features/step_definitions/report_steps.rb +91 -0
- data/features/step_definitions/time_entry_steps.rb +40 -0
- data/features/support/env.rb +37 -0
- data/features/support/error_helpers.rb +18 -0
- data/features/support/fixtures/empty_clients.xml +2 -0
- data/features/support/fixtures/over_limit.xml +8 -0
- data/features/support/fixtures/receipt.png +0 -0
- data/features/support/fixtures/under_limit.xml +8 -0
- data/features/support/harvest_credentials.example.yml +4 -0
- data/features/support/harvest_helpers.rb +11 -0
- data/features/support/inflections.rb +9 -0
- data/features/task_assignment.feature +69 -0
- data/features/tasks.feature +25 -0
- data/features/time_tracking.feature +29 -0
- data/features/user_assignments.feature +33 -0
- data/features/users.feature +55 -0
- data/lib/harvest/api/account.rb +10 -0
- data/lib/harvest/api/base.rb +42 -0
- data/lib/harvest/api/clients.rb +10 -0
- data/lib/harvest/api/contacts.rb +19 -0
- data/lib/harvest/api/expense_categories.rb +9 -0
- data/lib/harvest/api/expenses.rb +28 -0
- data/lib/harvest/api/projects.rb +39 -0
- data/lib/harvest/api/reports.rb +39 -0
- data/lib/harvest/api/task_assignments.rb +32 -0
- data/lib/harvest/api/tasks.rb +9 -0
- data/lib/harvest/api/time.rb +32 -0
- data/lib/harvest/api/user_assignments.rb +32 -0
- data/lib/harvest/api/users.rb +15 -0
- data/lib/harvest/base.rb +59 -0
- data/lib/harvest/base_model.rb +34 -0
- data/lib/harvest/behavior/activatable.rb +21 -0
- data/lib/harvest/behavior/crud.rb +31 -0
- data/lib/harvest/client.rb +18 -0
- data/lib/harvest/contact.rb +16 -0
- data/lib/harvest/credentials.rb +21 -0
- data/lib/harvest/errors.rb +23 -0
- data/lib/harvest/expense.rb +19 -0
- data/lib/harvest/expense_category.rb +18 -0
- data/lib/harvest/hardy_client.rb +80 -0
- data/lib/harvest/project.rb +22 -0
- data/lib/harvest/rate_limit_status.rb +16 -0
- data/lib/harvest/task.rb +20 -0
- data/lib/harvest/task_assignment.rb +34 -0
- data/lib/harvest/time_entry.rb +41 -0
- data/lib/harvest/timezones.rb +150 -0
- data/lib/harvest/user.rb +40 -0
- data/lib/harvest/user_assignment.rb +34 -0
- data/lib/harvested.rb +31 -0
- data/spec/harvest/base_spec.rb +9 -0
- data/spec/harvest/credentials_spec.rb +22 -0
- data/spec/harvest/expense_spec.rb +15 -0
- data/spec/harvest/task_assignment_spec.rb +10 -0
- data/spec/harvest/time_entry_spec.rb +22 -0
- data/spec/harvest/user_assignment_spec.rb +10 -0
- data/spec/harvest/user_spec.rb +32 -0
- data/spec/spec.default.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +243 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
When /^I create an? (client|task|user|expense category) with the following:$/ do |type, table|
|
2
|
+
case type
|
3
|
+
when "client"
|
4
|
+
client = Harvest::Client.new(table.rows_hash)
|
5
|
+
harvest_api.clients.create(client)
|
6
|
+
when "task"
|
7
|
+
task = Harvest::Task.new(table.rows_hash)
|
8
|
+
harvest_api.tasks.create(task)
|
9
|
+
when "user"
|
10
|
+
user = Harvest::User.new(table.rows_hash)
|
11
|
+
harvest_api.users.create(user)
|
12
|
+
when "expense category"
|
13
|
+
expense_cat = Harvest::ExpenseCategory.new(table.rows_hash)
|
14
|
+
harvest_api.expense_categories.create(expense_cat)
|
15
|
+
else pending end
|
16
|
+
end
|
17
|
+
|
18
|
+
When /^I create a (contact|project) for the client "([^\"]*)" with the following:$/ do |type, client_name, table|
|
19
|
+
client = Then %Q{there should be a client "#{client_name}"}
|
20
|
+
attributes = table.rows_hash.merge("client_id" => client.id)
|
21
|
+
|
22
|
+
case type
|
23
|
+
when "contact"
|
24
|
+
contact = Harvest::Contact.new(attributes)
|
25
|
+
harvest_api.contacts.create(contact)
|
26
|
+
when "project"
|
27
|
+
project = Harvest::Project.new(attributes)
|
28
|
+
harvest_api.projects.create(project)
|
29
|
+
else pending end
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^there should be an? (contact|project|client|task|user|expense category) "([^\"]*)"$/ do |type, identifier|
|
33
|
+
collection = harvest_api.send(pluralize(type)).all
|
34
|
+
attribute = case type
|
35
|
+
when 'contact', 'user' then 'email'
|
36
|
+
when 'project', 'client', 'task', 'expense category' then 'name'
|
37
|
+
else pending end
|
38
|
+
item = collection.detect {|c| c.send(attribute) == identifier}
|
39
|
+
item.should_not be_nil
|
40
|
+
item
|
41
|
+
end
|
42
|
+
|
43
|
+
Then /^there should not be an? (contact|project|client|task|user|expense category) "([^\"]*)"$/ do |type, identifier|
|
44
|
+
collection = harvest_api.send(pluralize(type)).all
|
45
|
+
attribute = case type
|
46
|
+
when 'contact', 'user' then 'email'
|
47
|
+
when 'project', 'client', 'task', 'expense category' then 'name'
|
48
|
+
else pending end
|
49
|
+
item = collection.detect {|c| c.send(attribute) == identifier}
|
50
|
+
item.should be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
When /^I update the (contact|project|client|task|user|expense category) "([^\"]*)" with the following:$/ do |type, name, table|
|
54
|
+
item = Then %Q{there should be a #{type} "#{name}"}
|
55
|
+
item.attributes = table.rows_hash
|
56
|
+
harvest_api.send(pluralize(type)).update(item)
|
57
|
+
end
|
58
|
+
|
59
|
+
Then /^the (contact|project|client|task|user|expense category) "([^\"]*)" should have the following attributes:$/ do |type, name, table|
|
60
|
+
item = Then %Q{there should be a #{type} "#{name}"}
|
61
|
+
table.rows_hash.each do |key, value|
|
62
|
+
item.send(key).to_s.should == value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
When /^I delete the (contact|project|client|task|user|expense category) "([^\"]*)"$/ do |type, name|
|
67
|
+
item = Then %Q{there should be a #{type} "#{name}"}
|
68
|
+
id = harvest_api.send(pluralize(type)).delete(item)
|
69
|
+
id.should == item.id
|
70
|
+
end
|
71
|
+
|
72
|
+
Then /^the (client|project|user) "([^\"]*)" should be activated$/ do |type, identifier|
|
73
|
+
item = Then %Q{there should be a #{type} "#{identifier}"}
|
74
|
+
item.should be_active
|
75
|
+
end
|
76
|
+
|
77
|
+
Then /^the (client|project|user) "([^\"]*)" should be deactivated$/ do |type, identifier|
|
78
|
+
item = Then %Q{there should be a #{type} "#{identifier}"}
|
79
|
+
item.should_not be_active
|
80
|
+
end
|
81
|
+
|
82
|
+
When /^I deactivate the (client|project|user) "([^\"]*)"$/ do |type, identifier|
|
83
|
+
item = Then %Q{there should be a #{type} "#{identifier}"}
|
84
|
+
harvest_api.send(pluralize(type)).deactivate(item)
|
85
|
+
end
|
86
|
+
|
87
|
+
When /^I activate the (client|project|user) "([^\"]*)"$/ do |type, identifier|
|
88
|
+
item = Then %Q{there should be a #{type} "#{identifier}"}
|
89
|
+
harvest_api.send(pluralize(type)).activate(item)
|
90
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
When /^I run a project report for "([^\"]*)" for "([^\"]*)" and "([^\"]*)" the following entries should be returned:$/ do |project_name, start_date, end_date, table|
|
2
|
+
start_date = Time.parse(start_date)
|
3
|
+
end_date = Time.parse(end_date)
|
4
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
5
|
+
entries = harvest_api.reports.time_by_project(project, start_date, end_date)
|
6
|
+
table.raw.each do |row|
|
7
|
+
entry = entries.detect {|e| e.notes == row.first }
|
8
|
+
entry.should_not be_nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^I run a project report for "([^\"]*)" for "([^\"]*)" and "([^\"]*)" the following entries should not be returned:$/ do |project_name, start_date, end_date, table|
|
13
|
+
start_date = Time.parse(start_date)
|
14
|
+
end_date = Time.parse(end_date)
|
15
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
16
|
+
entries = harvest_api.reports.time_by_project(project, start_date, end_date)
|
17
|
+
table.raw.each do |row|
|
18
|
+
entry = entries.detect {|e| e.notes == row.first }
|
19
|
+
entry.should be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
When /^I run a a project report for "([^\"]*)" for "([^\"]*)" and "([^\"]*)" filtered by my user the following entries should be returned:$/ do |project_name, start_date, end_date, table|
|
24
|
+
start_date = Time.parse(start_date)
|
25
|
+
end_date = Time.parse(end_date)
|
26
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
27
|
+
user = Then %Q{there should be a user "#{@username}"}
|
28
|
+
entries = harvest_api.reports.time_by_project(project, start_date, end_date, user)
|
29
|
+
table.raw.each do |row|
|
30
|
+
entry = entries.detect {|e| e.notes == row.first }
|
31
|
+
entry.should_not be_nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
When /^I run a a project report for "([^\"]*)" for "([^\"]*)" and "([^\"]*)" filtered by my user the following entries should not be returned:$/ do |project_name, start_date, end_date, table|
|
36
|
+
start_date = Time.parse(start_date)
|
37
|
+
end_date = Time.parse(end_date)
|
38
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
39
|
+
user = Then %Q{there should be a user "#{@username}"}
|
40
|
+
entries = harvest_api.reports.time_by_project(project, start_date, end_date, user)
|
41
|
+
table.raw.each do |row|
|
42
|
+
entry = entries.detect {|e| e.notes == row.first }
|
43
|
+
entry.should be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
When /^I run a people report for my user for "([^\"]*)" and "([^\"]*)" the following entries should be returned:$/ do |start_date, end_date, table|
|
48
|
+
start_date = Time.parse(start_date)
|
49
|
+
end_date = Time.parse(end_date)
|
50
|
+
user = Then %Q{there should be a user "#{@username}"}
|
51
|
+
entries = harvest_api.reports.time_by_user(user, start_date, end_date)
|
52
|
+
table.raw.each do |row|
|
53
|
+
entry = entries.detect {|e| e.notes == row.first }
|
54
|
+
entry.should_not be_nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
When /^I run a people report for my user for "([^\"]*)" and "([^\"]*)" filtered by the project "([^\"]*)" the following entries should be returned:$/ do |start_date, end_date, project_name, table|
|
59
|
+
start_date = Time.parse(start_date)
|
60
|
+
end_date = Time.parse(end_date)
|
61
|
+
user = Then %Q{there should be a user "#{@username}"}
|
62
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
63
|
+
entries = harvest_api.reports.time_by_user(user, start_date, end_date, project)
|
64
|
+
table.raw.each do |row|
|
65
|
+
entry = entries.detect {|e| e.notes == row.first }
|
66
|
+
entry.should_not be_nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
When /^I run a people report for my user for "([^\"]*)" and "([^\"]*)" filtered by the project "([^\"]*)" the following entries should not be returned:$/ do |start_date, end_date, project_name, table|
|
71
|
+
start_date = Time.parse(start_date)
|
72
|
+
end_date = Time.parse(end_date)
|
73
|
+
user = Then %Q{there should be a user "#{@username}"}
|
74
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
75
|
+
entries = harvest_api.reports.time_by_user(user, start_date, end_date, project)
|
76
|
+
table.raw.each do |row|
|
77
|
+
entry = entries.detect {|e| e.notes == row.first }
|
78
|
+
entry.should be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
When /^I run an expense report for my user for "([^\"]*)" and "([^\"]*)" the following entries should be returned:$/ do |start_date, end_date, table|
|
83
|
+
start_date = Time.parse(start_date)
|
84
|
+
end_date = Time.parse(end_date)
|
85
|
+
user = Then %Q{there should be a user "#{@username}"}
|
86
|
+
expenses = harvest_api.reports.expenses_by_user(user, start_date, end_date)
|
87
|
+
table.raw.each do |row|
|
88
|
+
expense = expenses.detect {|e| e.notes == row.first }
|
89
|
+
expense.should_not be_nil
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
When 'I create a time entry for the project "$1" and the task "$2" with the following:' do |project_name, task_name, table|
|
2
|
+
task = Then %Q{there should be a task "#{task_name}"}
|
3
|
+
project = Then %Q{there should be a project "#{project_name}"}
|
4
|
+
entry = Harvest::TimeEntry.new(table.rows_hash.merge('project_id' => project.id, 'task_id' => task.id))
|
5
|
+
created_entry = harvest_api.time.create(entry)
|
6
|
+
created_entry.project.should == project.name
|
7
|
+
created_entry.task.should == task.name
|
8
|
+
end
|
9
|
+
|
10
|
+
Then 'there should be a time entry "$1" on "$2"' do |notes, date|
|
11
|
+
entries = harvest_api.time.all(date)
|
12
|
+
entry = entries.detect {|e| e.notes == notes}
|
13
|
+
entry.should_not be_nil
|
14
|
+
entry
|
15
|
+
end
|
16
|
+
|
17
|
+
Then 'there should not be a time entry "$1" on "$2"' do |notes, date|
|
18
|
+
entries = harvest_api.time.all(date)
|
19
|
+
entry = entries.detect {|e| e.notes == notes}
|
20
|
+
entry.should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
When 'I update the time entry "$1" on "$2" with the following:' do |note, date, table|
|
24
|
+
entry = Then %Q{there should be a time entry "#{note}" on "#{date}"}
|
25
|
+
entry.attributes = table.rows_hash
|
26
|
+
harvest_api.time.update(entry)
|
27
|
+
end
|
28
|
+
|
29
|
+
Then 'the time entry "$1" on "$2" should have the following attributes:' do |note, date, table|
|
30
|
+
entry = Then %Q{there should be a time entry "#{note}" on "#{date}"}
|
31
|
+
table.rows_hash.each do |key, value|
|
32
|
+
entry.send(key).to_s.should == value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
When 'I delete the time entry "$1" on "$2"' do |note, date|
|
37
|
+
entry = Then %Q{there should be a time entry "#{note}" on "#{date}"}
|
38
|
+
id = harvest_api.time.delete(entry)
|
39
|
+
entry.id.should == id
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
|
2
|
+
require 'harvested'
|
3
|
+
require 'ruby-debug'
|
4
|
+
require 'fakeweb'
|
5
|
+
|
6
|
+
require 'spec/expectations'
|
7
|
+
|
8
|
+
Before do
|
9
|
+
FakeWeb.clean_registry
|
10
|
+
FakeWeb.allow_net_connect = true
|
11
|
+
end
|
12
|
+
|
13
|
+
Before('@disconnected') do
|
14
|
+
FakeWeb.allow_net_connect = false
|
15
|
+
end
|
16
|
+
|
17
|
+
Before('@clean') do
|
18
|
+
credentials = YAML.load_file("#{File.dirname(__FILE__)}/harvest_credentials.yml")
|
19
|
+
api = Harvest.hardy_client(credentials["subdomain"], credentials["username"], credentials["password"], :ssl => credentials["ssl"])
|
20
|
+
|
21
|
+
api.users.all.each do |u|
|
22
|
+
api.users.delete(u) if u.email != credentials["username"]
|
23
|
+
end
|
24
|
+
my_user = api.users.all.first
|
25
|
+
|
26
|
+
api.reports.time_by_user(my_user, Time.parse('01/01/2000'), Time.now).each do |time|
|
27
|
+
api.time.delete(time)
|
28
|
+
end
|
29
|
+
|
30
|
+
api.reports.expenses_by_user(my_user, Time.parse('01/01/2000'), Time.now).each do |time|
|
31
|
+
api.expenses.delete(time)
|
32
|
+
end
|
33
|
+
|
34
|
+
%w(expenses expense_categories projects contacts clients tasks).each do |collection|
|
35
|
+
api.send(collection).all.each {|m| api.send(collection).delete(m) }
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ErrorHelpers
|
2
|
+
def set_time_and_return_and_error
|
3
|
+
@time = Time.now
|
4
|
+
@error = nil
|
5
|
+
begin
|
6
|
+
@clients = yield
|
7
|
+
rescue => e
|
8
|
+
case e
|
9
|
+
when Harvest::HTTPError, Net::HTTPError, Net::HTTPFatalError
|
10
|
+
@error = e
|
11
|
+
else
|
12
|
+
raise e
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
World(ErrorHelpers)
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<hash>
|
3
|
+
<last-access-at type="datetime">2010-04-02T01:34:59+00:00</last-access-at>
|
4
|
+
<count type="integer">41</count>
|
5
|
+
<timeframe-limit type="integer">15</timeframe-limit>
|
6
|
+
<max-calls type="integer">40</max-calls>
|
7
|
+
<lockout-seconds type="integer">5</lockout-seconds>
|
8
|
+
</hash>
|
Binary file
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<hash>
|
3
|
+
<last-access-at type="datetime">2010-04-02T01:34:59+00:00</last-access-at>
|
4
|
+
<count type="integer">2</count>
|
5
|
+
<timeframe-limit type="integer">15</timeframe-limit>
|
6
|
+
<max-calls type="integer">40</max-calls>
|
7
|
+
<lockout-seconds type="integer">5</lockout-seconds>
|
8
|
+
</hash>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
@clean
|
2
|
+
Feature: Task Assignments
|
3
|
+
|
4
|
+
Scenario: Adding and Updating a Task on a Project
|
5
|
+
Given I am using the credentials from "./support/harvest_credentials.yml"
|
6
|
+
When I create a client with the following:
|
7
|
+
| name | Client Projects |
|
8
|
+
| details | Building API Widgets across the country |
|
9
|
+
When I create a project for the client "Client Projects" with the following:
|
10
|
+
| name | Test Project |
|
11
|
+
| active | true |
|
12
|
+
| notes | project to test the api |
|
13
|
+
Then there should be a project "Test Project"
|
14
|
+
When I create a task with the following:
|
15
|
+
| name | Test Task |
|
16
|
+
| billable | true |
|
17
|
+
| deactivated | false |
|
18
|
+
| hourly_rate | 120 |
|
19
|
+
Then there should be a task "Test Task"
|
20
|
+
When I assign the task "Test Task" to the project "Test Project"
|
21
|
+
Then the task "Test Task" should be assigned to the project "Test Project"
|
22
|
+
When I update the task "Test Task" for the project "Test Project" with the following:
|
23
|
+
| hourly_rate | 75 |
|
24
|
+
| billable | false |
|
25
|
+
Then the task "Test Task" for the project "Test Project" should have the following attributes:
|
26
|
+
| hourly_rate | 75.0 |
|
27
|
+
| billable? | false |
|
28
|
+
| active? | true |
|
29
|
+
|
30
|
+
Scenario: Removing Tasks on a project
|
31
|
+
Given I am using the credentials from "./support/harvest_credentials.yml"
|
32
|
+
When I create a client with the following:
|
33
|
+
| name | Client Projects |
|
34
|
+
| details | Building API Widgets across the country |
|
35
|
+
When I create a project for the client "Client Projects" with the following:
|
36
|
+
| name | Test Project |
|
37
|
+
| active | true |
|
38
|
+
| notes | project to test the api |
|
39
|
+
Then there should be a project "Test Project"
|
40
|
+
When I create a task with the following:
|
41
|
+
| name | Test Task1 |
|
42
|
+
When I create a task with the following:
|
43
|
+
| name | Test Task2 |
|
44
|
+
Then there should be a task "Test Task1"
|
45
|
+
Then there should be a task "Test Task2"
|
46
|
+
When I assign the task "Test Task1" to the project "Test Project"
|
47
|
+
When I assign the task "Test Task2" to the project "Test Project"
|
48
|
+
Then the task "Test Task1" should be assigned to the project "Test Project"
|
49
|
+
Then the task "Test Task2" should be assigned to the project "Test Project"
|
50
|
+
When I remove the task "Test Task1" from the project "Test Project"
|
51
|
+
Then the task "Test Task1" should not be assigned to the project "Test Project"
|
52
|
+
When I try to remove the task "Test Task2" from the project "Test Project"
|
53
|
+
Then a 400 error should be raised
|
54
|
+
|
55
|
+
Scenario: Removing a task that has recorded hours
|
56
|
+
|
57
|
+
Scenario: Creating a task and immediately assigning it
|
58
|
+
Given I am using the credentials from "./support/harvest_credentials.yml"
|
59
|
+
When I create a client with the following:
|
60
|
+
| name | Client Projects |
|
61
|
+
| details | Building API Widgets across the country |
|
62
|
+
When I create a project for the client "Client Projects" with the following:
|
63
|
+
| name | Test Project |
|
64
|
+
| active | true |
|
65
|
+
| notes | project to test the api |
|
66
|
+
Then there should be a project "Test Project"
|
67
|
+
When I create and assign a task "Created Task" to the project "Test Project"
|
68
|
+
Then there should be a task "Created Task"
|
69
|
+
Then the task "Created Task" should be assigned to the project "Test Project"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
@clean
|
2
|
+
Feature: Managing Tasks
|
3
|
+
|
4
|
+
Scenario: Adding, Updating, and Removing a Task
|
5
|
+
Given I am using the credentials from "./support/harvest_credentials.yml"
|
6
|
+
When I create a task with the following:
|
7
|
+
| name | Test Task |
|
8
|
+
| billable | true |
|
9
|
+
| deactivated | false |
|
10
|
+
| hourly_rate | 120 |
|
11
|
+
Then there should be a task "Test Task"
|
12
|
+
When I update the task "Test Task" with the following:
|
13
|
+
| name | Updated Task |
|
14
|
+
| hourly_rate | 100.0 |
|
15
|
+
| deactivated | true |
|
16
|
+
| billable | false |
|
17
|
+
| default | true |
|
18
|
+
Then the task "Updated Task" should have the following attributes:
|
19
|
+
| hourly_rate | 100.0 |
|
20
|
+
| deactivated | true |
|
21
|
+
| active? | false |
|
22
|
+
| billable | false |
|
23
|
+
| default? | true |
|
24
|
+
When I delete the task "Updated Task"
|
25
|
+
Then there should not be a task "Updated Task"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
@clean
|
2
|
+
Feature: Time Tracking
|
3
|
+
|
4
|
+
Scenario: Adding, Updating, and Deleting Time Entries
|
5
|
+
Given I am using the credentials from "./support/harvest_credentials.yml"
|
6
|
+
And I create a client with the following:
|
7
|
+
| name | Time Client |
|
8
|
+
| details | Client to track time against |
|
9
|
+
And I create a project for the client "Time Client" with the following:
|
10
|
+
| name | Time Project |
|
11
|
+
| active | true |
|
12
|
+
And I create a task with the following:
|
13
|
+
| name | Time Task |
|
14
|
+
| billable | true |
|
15
|
+
| hourly_rate | 120 |
|
16
|
+
And I assign the task "Time Task" to the project "Time Project"
|
17
|
+
When I create a time entry for the project "Time Project" and the task "Time Task" with the following:
|
18
|
+
| notes | Test api support |
|
19
|
+
| hours | 3.0 |
|
20
|
+
| spent_at | 12/28/2009 |
|
21
|
+
Then there should be a time entry "Test api support" on "12/28/2009"
|
22
|
+
When I update the time entry "Test api support" on "12/28/2009" with the following:
|
23
|
+
| hours | 4.0 |
|
24
|
+
Then the time entry "Test api support" on "12/28/2009" should have the following attributes:
|
25
|
+
| hours | 4.0 |
|
26
|
+
When I delete the time entry "Test api support" on "12/28/2009"
|
27
|
+
Then there should not be a time entry "Test api support" on "12/28/2009"
|
28
|
+
|
29
|
+
Scenario: Toggling Timers
|