harvested 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/Gemfile +15 -0
  2. data/HISTORY +11 -0
  3. data/README.md +14 -6
  4. data/Rakefile +13 -31
  5. data/TODO +2 -0
  6. data/VERSION +1 -1
  7. data/examples/user_assignments.rb +1 -1
  8. data/harvested.gemspec +114 -126
  9. data/lib/ext/array.rb +52 -0
  10. data/lib/ext/date.rb +9 -0
  11. data/lib/ext/hash.rb +17 -0
  12. data/lib/ext/time.rb +5 -0
  13. data/lib/harvest/api/account.rb +8 -1
  14. data/lib/harvest/api/base.rb +32 -10
  15. data/lib/harvest/api/contacts.rb +1 -1
  16. data/lib/harvest/api/expenses.rb +3 -4
  17. data/lib/harvest/api/invoice_categories.rb +26 -0
  18. data/lib/harvest/api/invoices.rb +16 -0
  19. data/lib/harvest/api/projects.rb +2 -10
  20. data/lib/harvest/api/reports.rb +13 -16
  21. data/lib/harvest/api/task_assignments.rb +8 -6
  22. data/lib/harvest/api/tasks.rb +1 -1
  23. data/lib/harvest/api/time.rb +13 -13
  24. data/lib/harvest/api/user_assignments.rb +7 -5
  25. data/lib/harvest/base.rb +9 -1
  26. data/lib/harvest/behavior/activatable.rb +2 -2
  27. data/lib/harvest/behavior/crud.rb +15 -13
  28. data/lib/harvest/client.rb +18 -13
  29. data/lib/harvest/contact.rb +13 -11
  30. data/lib/harvest/errors.rb +6 -4
  31. data/lib/harvest/expense.rb +40 -14
  32. data/lib/harvest/expense_category.rb +10 -9
  33. data/lib/harvest/hardy_client.rb +1 -1
  34. data/lib/harvest/invoice.rb +103 -0
  35. data/lib/harvest/invoice_category.rb +18 -0
  36. data/lib/harvest/line_item.rb +12 -0
  37. data/lib/harvest/model.rb +120 -0
  38. data/lib/harvest/project.rb +55 -26
  39. data/lib/harvest/rate_limit_status.rb +9 -8
  40. data/lib/harvest/task.rb +17 -14
  41. data/lib/harvest/task_assignment.rb +27 -22
  42. data/lib/harvest/time_entry.rb +32 -30
  43. data/lib/harvest/user.rb +46 -22
  44. data/lib/harvest/user_assignment.rb +24 -17
  45. data/lib/harvested.rb +12 -5
  46. data/spec/functional/account_spec.rb +17 -0
  47. data/spec/functional/clients_spec.rb +58 -0
  48. data/spec/functional/errors_spec.rb +22 -0
  49. data/spec/functional/expenses_spec.rb +84 -0
  50. data/spec/functional/hardy_client_spec.rb +33 -0
  51. data/spec/functional/invoice_spec.rb +67 -0
  52. data/spec/functional/project_spec.rb +50 -0
  53. data/spec/functional/reporting_spec.rb +80 -0
  54. data/spec/functional/tasks_spec.rb +88 -0
  55. data/spec/functional/time_tracking_spec.rb +53 -0
  56. data/spec/functional/users_spec.rb +102 -0
  57. data/spec/harvest/base_spec.rb +1 -1
  58. data/spec/harvest/credentials_spec.rb +1 -1
  59. data/spec/harvest/expense_category_spec.rb +5 -0
  60. data/spec/harvest/expense_spec.rb +8 -5
  61. data/spec/harvest/invoice_spec.rb +47 -0
  62. data/spec/harvest/project_spec.rb +11 -0
  63. data/spec/harvest/task_assignment_spec.rb +4 -4
  64. data/spec/harvest/task_spec.rb +7 -0
  65. data/spec/harvest/time_entry_spec.rb +11 -10
  66. data/spec/harvest/user_assignment_spec.rb +3 -3
  67. data/spec/harvest/user_spec.rb +3 -1
  68. data/spec/spec_helper.rb +37 -6
  69. data/{features → spec}/support/harvest_credentials.example.yml +0 -1
  70. data/spec/support/harvested_helpers.rb +44 -0
  71. data/spec/support/json_examples.rb +11 -0
  72. data/spec/test_rubies +5 -0
  73. metadata +109 -85
  74. data/.gitignore +0 -28
  75. data/features/account.feature +0 -7
  76. data/features/client_contacts.feature +0 -23
  77. data/features/clients.feature +0 -29
  78. data/features/errors.feature +0 -25
  79. data/features/expense_categories.feature +0 -21
  80. data/features/expenses.feature +0 -55
  81. data/features/hardy_client.feature +0 -40
  82. data/features/projects.feature +0 -39
  83. data/features/reporting.feature +0 -72
  84. data/features/step_definitions/account_steps.rb +0 -7
  85. data/features/step_definitions/assignment_steps.rb +0 -100
  86. data/features/step_definitions/contact_steps.rb +0 -11
  87. data/features/step_definitions/debug_steps.rb +0 -3
  88. data/features/step_definitions/error_steps.rb +0 -113
  89. data/features/step_definitions/expenses_steps.rb +0 -46
  90. data/features/step_definitions/harvest_steps.rb +0 -8
  91. data/features/step_definitions/model_steps.rb +0 -90
  92. data/features/step_definitions/people_steps.rb +0 -4
  93. data/features/step_definitions/report_steps.rb +0 -91
  94. data/features/step_definitions/time_entry_steps.rb +0 -40
  95. data/features/support/env.rb +0 -37
  96. data/features/support/error_helpers.rb +0 -18
  97. data/features/support/fixtures/empty_clients.xml +0 -2
  98. data/features/support/fixtures/over_limit.xml +0 -8
  99. data/features/support/fixtures/receipt.png +0 -0
  100. data/features/support/fixtures/under_limit.xml +0 -8
  101. data/features/support/harvest_helpers.rb +0 -11
  102. data/features/support/inflections.rb +0 -9
  103. data/features/task_assignment.feature +0 -69
  104. data/features/tasks.feature +0 -25
  105. data/features/time_tracking.feature +0 -29
  106. data/features/user_assignments.feature +0 -33
  107. data/features/users.feature +0 -55
  108. data/lib/harvest/base_model.rb +0 -73
  109. data/spec/spec.default.opts +0 -1
@@ -1,46 +0,0 @@
1
- When 'I create an expense for the project "$1" with the category "$2" with the following:' do |project_name, category_name, table|
2
- project = Then %Q{there should be a project "#{project_name}"}
3
- category = Then %Q{there should be an expense category "#{category_name}"}
4
-
5
- expense = Harvest::Expense.new(table.rows_hash.merge("expense_category_id" => category.id, "project_id" => project.id))
6
- harvest_api.expenses.create(expense)
7
- end
8
-
9
- Then 'there should be an expense "$1" on "$2"' do |notes, date|
10
- expenses = harvest_api.expenses.all(date)
11
- expense = expenses.detect {|e| e.notes == notes}
12
- expense.should_not be_nil
13
- expense
14
- end
15
-
16
- Then 'there should not be an expense "$1" on "$2"' do |notes, date|
17
- expenses = harvest_api.expenses.all(date)
18
- expense = expenses.detect {|e| e.notes == notes}
19
- expense.should be_nil
20
- end
21
-
22
- When 'I delete the expense "$1" on "$2"' do |notes, date|
23
- expense = Then %Q{there should be an expense "#{notes}" on "#{date}"}
24
- id = harvest_api.expenses.delete(expense)
25
- expense.id.should == id
26
- end
27
-
28
- Then 'the expense "$1" on "$2" should have the following attributes:' do |notes, date, table|
29
- expense = Then %Q{there should be an expense "#{notes}" on "#{date}"}
30
- table.rows_hash.each do |key, value|
31
- expense.send(key).to_s.should == value
32
- end
33
- end
34
-
35
- When 'I update the expense "$1" on "$2" with the following:' do |notes, date, table|
36
- expense = Then %Q{there should be an expense "#{notes}" on "#{date}"}
37
- expense.attributes = table.rows_hash
38
- harvest_api.expenses.update(expense)
39
- end
40
-
41
- When 'I attach the receipt "$1" to the expense "$2" on "$3"' do |path, notes, date|
42
- path = "#{File.dirname(__FILE__)}/../#{path}"
43
- receipt = StringIO.new(File.read(path))
44
- expense = Then %Q{there should be an expense "#{notes}" on "#{date}"}
45
- harvest_api.expenses.attach(expense, "receipt.png", receipt)
46
- end
@@ -1,8 +0,0 @@
1
- Given 'I am using the credentials from "$1"' do |path|
2
- raise "You need a credentials file in support/harvest_credentials.yml!!" unless File.exist?("#{File.dirname(__FILE__)}/../#{path}")
3
- credentials = YAML.load_file("#{File.dirname(__FILE__)}/../#{path}")
4
- @username = credentials["username"]
5
- @password = credentials["password"]
6
- @subdomain = credentials["subdomain"]
7
- @ssl = credentials["ssl"]
8
- end
@@ -1,90 +0,0 @@
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
@@ -1,4 +0,0 @@
1
- Then 'I reset the password of "$1"' do |email|
2
- user = Then %Q{there should be a user "#{email}"}
3
- harvest_api.users.reset_password(user)
4
- end
@@ -1,91 +0,0 @@
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
@@ -1,40 +0,0 @@
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
@@ -1,37 +0,0 @@
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
@@ -1,18 +0,0 @@
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)
@@ -1,2 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <nil-classes type="array"/>
@@ -1,8 +0,0 @@
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>
@@ -1,8 +0,0 @@
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>
@@ -1,11 +0,0 @@
1
- module HarvestHelpers
2
- def standard_api
3
- Harvest.client(@subdomain, @username, @password, :ssl => @ssl)
4
- end
5
-
6
- def harvest_api
7
- Harvest.hardy_client(@subdomain, @username, @password, :ssl => @ssl)
8
- end
9
- end
10
-
11
- World(HarvestHelpers)
@@ -1,9 +0,0 @@
1
- module Inflections
2
- def pluralize(string)
3
- case string
4
- when 'expense category' then 'expense_categories'
5
- else "#{string}s" end
6
- end
7
- end
8
-
9
- World(Inflections)
@@ -1,69 +0,0 @@
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"