togglv8-ng 1.4.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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +16 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +4 -0
- data/.rdoc_options +23 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +101 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +160 -0
- data/Rakefile +6 -0
- data/lib/logging.rb +38 -0
- data/lib/reportsv2.rb +177 -0
- data/lib/togglv8/clients.rb +37 -0
- data/lib/togglv8/connection.rb +99 -0
- data/lib/togglv8/dashboard.rb +14 -0
- data/lib/togglv8/project_users.rb +32 -0
- data/lib/togglv8/projects.rb +112 -0
- data/lib/togglv8/tags.rb +25 -0
- data/lib/togglv8/tasks.rb +55 -0
- data/lib/togglv8/time_entries.rb +114 -0
- data/lib/togglv8/togglv8.rb +55 -0
- data/lib/togglv8/users.rb +74 -0
- data/lib/togglv8/version.rb +4 -0
- data/lib/togglv8/workspaces.rb +47 -0
- data/lib/togglv8.rb +13 -0
- data/spec/lib/reportsv2_spec.rb +254 -0
- data/spec/lib/togglv8/clients_spec.rb +145 -0
- data/spec/lib/togglv8/dashboard_spec.rb +31 -0
- data/spec/lib/togglv8/projects_spec.rb +111 -0
- data/spec/lib/togglv8/tags_spec.rb +54 -0
- data/spec/lib/togglv8/tasks_spec.rb +100 -0
- data/spec/lib/togglv8/time_entries_spec.rb +425 -0
- data/spec/lib/togglv8/users_spec.rb +82 -0
- data/spec/lib/togglv8/workspaces_spec.rb +45 -0
- data/spec/lib/togglv8_spec.rb +88 -0
- data/spec/spec_helper.rb +87 -0
- data/spec/togglv8_spec_helper.rb +75 -0
- data/togglv8.gemspec +33 -0
- metadata +223 -0
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
describe 'ReportsV2' do
|
4
|
+
it 'initializes with api_token' do
|
5
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
6
|
+
env = reports.env
|
7
|
+
expect(env).to_not be nil
|
8
|
+
expect(env['user']['api_token']).to eq Testing::API_TOKEN
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'does not initialize with bogus api_token' do
|
12
|
+
reports = TogglV8::ReportsV2.new(api_token: '4880nqor1orr9n241sn08070q33oq49s')
|
13
|
+
expect { reports.env }.to raise_error(RuntimeError, "HTTP Status: 401")
|
14
|
+
end
|
15
|
+
|
16
|
+
context '.toggl file' do
|
17
|
+
before :each do
|
18
|
+
@tmp_home = mktemp_dir
|
19
|
+
@original_home = Dir.home
|
20
|
+
ENV['HOME'] = @tmp_home
|
21
|
+
end
|
22
|
+
|
23
|
+
after :each do
|
24
|
+
FileUtils.rm_rf(@tmp_home)
|
25
|
+
ENV['HOME'] = @original_home
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'initializes with .toggl file' do
|
29
|
+
toggl_file = File.join(@tmp_home, '.toggl')
|
30
|
+
File.open(toggl_file, 'w') { |file| file.write(Testing::API_TOKEN) }
|
31
|
+
|
32
|
+
reports = TogglV8::ReportsV2.new
|
33
|
+
env = reports.env
|
34
|
+
expect(env).to_not be nil
|
35
|
+
expect(env['user']['api_token']).to eq Testing::API_TOKEN
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'initializes with custom toggl file' do
|
39
|
+
toggl_file = File.join(@tmp_home, 'my_toggl')
|
40
|
+
File.open(toggl_file, 'w') { |file| file.write(Testing::API_TOKEN) }
|
41
|
+
|
42
|
+
reports = TogglV8::ReportsV2.new(toggl_api_file: toggl_file)
|
43
|
+
env = reports.env
|
44
|
+
expect(env).to_not be nil
|
45
|
+
expect(env['user']['api_token']).to eq Testing::API_TOKEN
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises error if .toggl file is missing' do
|
49
|
+
expect{ reports = TogglV8::ReportsV2.new }.to raise_error(RuntimeError)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'handles errors' do
|
54
|
+
before :all do
|
55
|
+
@reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
56
|
+
@reports.workspace_id = @workspace_id
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'surfaces a Warning HTTP header in case of 400 error' do
|
60
|
+
# https://github.com/toggl/toggl_api_docs/blob/master/reports.md#failed-requests
|
61
|
+
expect { @reports.error400 }.to raise_error(RuntimeError,
|
62
|
+
"This URL is intended only for testing")
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'retries a request up to 3 times if a 429 is received' do
|
66
|
+
expect(@reports.conn).to receive(:get).exactly(3).times.and_return(
|
67
|
+
MockResponse.new(429, {}, 'body'))
|
68
|
+
expect { @reports.env }.to raise_error(RuntimeError, "HTTP Status: 429")
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'retries a request after 429' do
|
72
|
+
expect(@reports.conn).to receive(:get).twice.and_return(
|
73
|
+
MockResponse.new(429, {}, 'body'),
|
74
|
+
MockResponse.new(200, {}, 'rev1.2.3'))
|
75
|
+
expect(@reports.revision).to eq('rev1.2.3')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'miscellaneous' do
|
80
|
+
it 'env returns environment' do
|
81
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
82
|
+
reports.workspace_id = @workspace_id
|
83
|
+
env = reports.env
|
84
|
+
expect(env['workspace']).to_not be nil
|
85
|
+
expect(env['user']).to_not be nil
|
86
|
+
expect(env['user']['id']).to eq Testing::USER_ID
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'index returns endpoints' do
|
90
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
91
|
+
reports.workspace_id = @workspace_id
|
92
|
+
index = reports.index
|
93
|
+
expect(index['Welcome to reports api V2. VALID requests are:']).to_not be nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'revision has not changed' do
|
97
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
98
|
+
reports.workspace_id = @workspace_id
|
99
|
+
expect(reports.revision).to start_with "0.0.38\n"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'project', :pro_account do
|
104
|
+
before :all do
|
105
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
106
|
+
@project_name = "Project #{Time.now.iso8601}"
|
107
|
+
@project = @toggl.create_project({
|
108
|
+
'name' => @project_name,
|
109
|
+
'wid' => @workspace_id
|
110
|
+
})
|
111
|
+
end
|
112
|
+
|
113
|
+
after :all do
|
114
|
+
@toggl.delete_project(@project['id'])
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'dashboard' do
|
118
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
119
|
+
reports.workspace_id = @toggl.workspaces.first['id']
|
120
|
+
project_dashboard = reports.project(@project['id'])
|
121
|
+
|
122
|
+
expect(project_dashboard['name']).to eq @project_name
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'blank reports' do
|
127
|
+
before :all do
|
128
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
129
|
+
@workspaces = @toggl.workspaces
|
130
|
+
@workspace_id = @workspaces.first['id']
|
131
|
+
@reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
132
|
+
@reports.workspace_id = @workspace_id
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'summary' do
|
136
|
+
expect(@reports.summary).to eq []
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'weekly' do
|
140
|
+
expect(@reports.weekly).to eq []
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'details' do
|
144
|
+
expect(@reports.details).to eq []
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'reports' do
|
149
|
+
before :all do
|
150
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
151
|
+
@workspaces = @toggl.workspaces
|
152
|
+
@workspace_id = @workspaces.first['id']
|
153
|
+
time_entry_info = {
|
154
|
+
'wid' => @workspace_id,
|
155
|
+
'start' => @toggl.iso8601(DateTime.now),
|
156
|
+
'duration' => 77
|
157
|
+
}
|
158
|
+
|
159
|
+
@time_entry = @toggl.create_time_entry(time_entry_info)
|
160
|
+
|
161
|
+
@reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
162
|
+
@reports.workspace_id = @workspace_id
|
163
|
+
|
164
|
+
@tmp_home = mktemp_dir
|
165
|
+
@original_home = Dir.home
|
166
|
+
ENV['HOME'] = @tmp_home
|
167
|
+
end
|
168
|
+
|
169
|
+
after :all do
|
170
|
+
@toggl.delete_time_entry(@time_entry['id'])
|
171
|
+
|
172
|
+
FileUtils.rm_rf(@tmp_home)
|
173
|
+
ENV['HOME'] = @original_home
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'JSON reports' do
|
177
|
+
it 'summary' do
|
178
|
+
summary = @reports.summary
|
179
|
+
expect(summary.length).to eq 1
|
180
|
+
expect(summary.first['time']).to eq 77000
|
181
|
+
expect(summary.first['items'].length).to eq 1
|
182
|
+
expect(summary.first['items'].first['time']).to eq 77000
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'weekly' do
|
186
|
+
weekly = @reports.weekly
|
187
|
+
expect(weekly.length).to eq 1
|
188
|
+
expect(weekly.first['details'].first['title']['user']).to eq Testing::USERNAME
|
189
|
+
expect(weekly.first['totals'][7]).to eq 77000
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'details' do
|
193
|
+
details = @reports.details
|
194
|
+
expect(details.length).to eq 1
|
195
|
+
expect(details.first['user']).to eq Testing::USERNAME
|
196
|
+
expect(details.first['dur']).to eq 77000
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'CSV reports' do
|
201
|
+
it 'summary' do
|
202
|
+
filename = File.join(@tmp_home, 'summary.csv')
|
203
|
+
summary = @reports.write_summary(filename)
|
204
|
+
expect(file_contains(filename, /00:01:17/))
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'weekly' do
|
208
|
+
filename = File.join(@tmp_home, 'weekly.csv')
|
209
|
+
weekly = @reports.write_weekly(filename)
|
210
|
+
expect(file_contains(filename, /00:01:17/))
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'details' do
|
214
|
+
filename = File.join(@tmp_home, 'details.csv')
|
215
|
+
details = @reports.write_details(filename)
|
216
|
+
expect(file_contains(filename, /00:01:17/))
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'PDF reports' do
|
221
|
+
it 'summary' do
|
222
|
+
filename = File.join(@tmp_home, 'summary.pdf')
|
223
|
+
summary = @reports.write_summary(filename)
|
224
|
+
expect(file_is_pdf(filename))
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'weekly' do
|
228
|
+
filename = File.join(@tmp_home, 'weekly.pdf')
|
229
|
+
weekly = @reports.write_weekly(filename)
|
230
|
+
expect(file_is_pdf(filename))
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'details' do
|
234
|
+
filename = File.join(@tmp_home, 'details.pdf')
|
235
|
+
details = @reports.write_details(filename)
|
236
|
+
expect(file_is_pdf(filename))
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'XLS reports', :pro_account do
|
241
|
+
it 'summary' do
|
242
|
+
filename = File.join(@tmp_home, 'summary.xls')
|
243
|
+
summary = @reports.write_summary(filename)
|
244
|
+
expect(file_is_xls(filename))
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'details' do
|
248
|
+
filename = File.join(@tmp_home, 'details.xls')
|
249
|
+
details = @reports.write_details(filename)
|
250
|
+
expect(file_is_xls(filename))
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
describe 'Clients' do
|
2
|
+
before :all do
|
3
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
4
|
+
@workspaces = @toggl.workspaces
|
5
|
+
@workspace_id = @workspaces.first['id']
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'gets {} if there are no clients' do
|
9
|
+
client = @toggl.clients
|
10
|
+
expect(client).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'gets {} if there are no workspace clients' do
|
14
|
+
client = @toggl.clients(@workspace_id)
|
15
|
+
expect(client).to be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'new client' do
|
19
|
+
before :all do
|
20
|
+
@client = @toggl.create_client({ 'name' => 'new client +1', 'wid' => @workspace_id })
|
21
|
+
client_ids = @toggl.my_clients.map { |c| c['id'] }
|
22
|
+
expect(client_ids).to eq [ @client['id'] ]
|
23
|
+
end
|
24
|
+
|
25
|
+
after :all do
|
26
|
+
TogglV8SpecHelper.delete_all_clients(@toggl)
|
27
|
+
clients = @toggl.my_clients
|
28
|
+
expect(clients).to be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'gets a client' do
|
32
|
+
client_ids = @toggl.clients.map { |c| c['id'] }
|
33
|
+
expect(client_ids).to eq [ @client['id'] ]
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'gets a workspace client' do
|
37
|
+
client_ids = @toggl.clients(@workspace_id).map { |c| c['id'] }
|
38
|
+
expect(client_ids).to eq [ @client['id'] ]
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'multiple clients' do
|
42
|
+
before :all do
|
43
|
+
@client2 = @toggl.create_client({ 'name' => 'new client 2', 'wid' => @workspace_id })
|
44
|
+
end
|
45
|
+
|
46
|
+
after :all do
|
47
|
+
@toggl.delete_client(@client2['id'])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'gets clients' do
|
51
|
+
client_ids = @toggl.clients.map { |c| c['id'] }
|
52
|
+
expect(client_ids).to match_array [ @client['id'], @client2['id'] ]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'gets workspace clients' do
|
56
|
+
client_ids = @toggl.clients(@workspace_id).map { |c| c['id'] }
|
57
|
+
expect(client_ids).to match_array [ @client['id'], @client2['id'] ]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'creates a client' do
|
62
|
+
expect(@client).to_not be nil
|
63
|
+
expect(@client['name']).to eq 'new client +1'
|
64
|
+
expect(@client['notes']).to eq nil
|
65
|
+
expect(@client['wid']).to eq @workspace_id
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'gets client data' do
|
69
|
+
client = @toggl.get_client(@client['id'])
|
70
|
+
expect(client).to_not be nil
|
71
|
+
expect(client['name']).to eq @client['name']
|
72
|
+
expect(client['wid']).to eq @client['wid']
|
73
|
+
expect(client['notes']).to eq @client['notes']
|
74
|
+
expect(client['at']).to_not be nil
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'client projects' do
|
78
|
+
it 'gets {} if there are no client projects' do
|
79
|
+
projects = @toggl.get_client_projects(@client['id'])
|
80
|
+
expect(projects).to be_empty
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'new client projects' do
|
84
|
+
before :all do
|
85
|
+
@project = @toggl.create_project({ 'name' => 'project', 'wid' => @workspace_id, 'cid' => @client['id'] })
|
86
|
+
end
|
87
|
+
|
88
|
+
after :all do
|
89
|
+
TogglV8SpecHelper.delete_all_projects(@toggl)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'gets a client project' do
|
93
|
+
projects = @toggl.get_client_projects(@client['id'])
|
94
|
+
project_ids = projects.map { |p| p['id'] }
|
95
|
+
expect(project_ids).to eq [ @project['id'] ]
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'gets multiple client projects' do
|
99
|
+
project2 = @toggl.create_project({ 'name' => 'project2', 'wid' => @workspace_id, 'cid' => @client['id'] })
|
100
|
+
|
101
|
+
projects = @toggl.get_client_projects(@client['id'])
|
102
|
+
project_ids = projects.map { |p| p['id'] }
|
103
|
+
expect(project_ids).to match_array [ @project['id'], project2['id'] ]
|
104
|
+
|
105
|
+
@toggl.delete_project(project2['id'])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'updated client' do
|
112
|
+
before :each do
|
113
|
+
@client = @toggl.create_client({ 'name' => 'client to update', 'wid' => @workspace_id })
|
114
|
+
end
|
115
|
+
|
116
|
+
after :each do
|
117
|
+
@toggl.delete_client(@client['id'])
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'updates client data' do
|
121
|
+
new_values = {
|
122
|
+
'name' => 'CLIENT-NEW',
|
123
|
+
'notes' => 'NOTES-NEW',
|
124
|
+
}
|
125
|
+
|
126
|
+
client = @toggl.update_client(@client['id'], new_values)
|
127
|
+
expect(client).to include(new_values)
|
128
|
+
end
|
129
|
+
|
130
|
+
# :nocov:
|
131
|
+
# It appears hourly rate is no longer tied to a client despite the docs:
|
132
|
+
# https://github.com/toggl/toggl_api_docs/blob/master/chapters/clients.md#clients
|
133
|
+
xit 'updates Pro client data', :pro_account do
|
134
|
+
new_values = {
|
135
|
+
'hrate' => '7.77',
|
136
|
+
'cur' => 'USD',
|
137
|
+
}
|
138
|
+
client = @toggl.update_client(@client['id'], new_values)
|
139
|
+
|
140
|
+
client = @toggl.get_client(@client['id'])
|
141
|
+
expect(client).to include(new_values)
|
142
|
+
end
|
143
|
+
# :nocov:
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe 'Dashboard' do
|
2
|
+
before :all do
|
3
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
4
|
+
@workspaces = @toggl.workspaces
|
5
|
+
@workspace_id = @workspaces.first['id']
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'gets nil dashboard data' do
|
9
|
+
dashboard = @toggl.dashboard(@workspace_id)
|
10
|
+
expect(dashboard).to eq Hash['most_active_user' => nil, 'activity' => nil]
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'gets dashboard time entries' do
|
14
|
+
before :all do
|
15
|
+
@new_time_entry = @toggl.start_time_entry({ 'wid' => @workspace_id, 'description' => 'new time entry +1' })
|
16
|
+
end
|
17
|
+
|
18
|
+
after :all do
|
19
|
+
@toggl.delete_time_entry(@new_time_entry['id'])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'gets dashboard data' do
|
23
|
+
dashboard = @toggl.dashboard(@workspace_id)
|
24
|
+
expect(dashboard['most_active_user']).to be nil
|
25
|
+
expect(dashboard['activity']).to_not be nil
|
26
|
+
expect(dashboard['activity'].first['user_id']).to eq @toggl.me['id']
|
27
|
+
expect(dashboard['activity'].first['project_id']).to be nil
|
28
|
+
expect(dashboard['activity'].first['description']).to eq 'new time entry +1'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
describe 'Projects' do
|
2
|
+
before :all do
|
3
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
4
|
+
@workspaces = @toggl.workspaces
|
5
|
+
@workspace_id = @workspaces.first['id']
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'gets {} if there are no workspace projects' do
|
9
|
+
projects = @toggl.projects(@workspace_id)
|
10
|
+
expect(projects).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'new project' do
|
14
|
+
before :all do
|
15
|
+
@project = @toggl.create_project({ 'name' => 'new project +1', 'wid' => @workspace_id })
|
16
|
+
project_ids = @toggl.my_projects.map { |p| p['id'] }
|
17
|
+
expect(project_ids).to eq [ @project['id'] ]
|
18
|
+
end
|
19
|
+
|
20
|
+
after :all do
|
21
|
+
TogglV8SpecHelper.delete_all_projects(@toggl)
|
22
|
+
projects = @toggl.my_projects
|
23
|
+
expect(projects).to be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'creates a project' do
|
27
|
+
expect(@project).to_not be nil
|
28
|
+
expect(@project['name']).to eq 'new project +1'
|
29
|
+
expect(@project['billable']).to eq false
|
30
|
+
expect(@project['is_private']).to eq true
|
31
|
+
expect(@project['active']).to eq true
|
32
|
+
expect(@project['template']).to eq false
|
33
|
+
expect(@project['auto_estimates']).to eq false
|
34
|
+
expect(@project['wid']).to eq @workspace_id
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'gets project data' do
|
38
|
+
project = @toggl.get_project(@project['id'])
|
39
|
+
expect(project).to_not be nil
|
40
|
+
expect(project['wid']).to eq @project['wid']
|
41
|
+
expect(project['name']).to eq @project['name']
|
42
|
+
expect(project['billable']).to eq @project['billable']
|
43
|
+
expect(project['is_private']).to eq @project['is_private']
|
44
|
+
expect(project['active']).to eq @project['active']
|
45
|
+
expect(project['template']).to eq @project['template']
|
46
|
+
expect(project['auto_estimates']).to eq @project['auto_estimates']
|
47
|
+
expect(project['at']).to_not be nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'gets project users' do
|
51
|
+
users = @toggl.get_project_users(@project['id'])
|
52
|
+
expect(users.length).to eq 1
|
53
|
+
expect(users.first['uid']).to eq Testing::USER_ID
|
54
|
+
expect(users.first['manager']).to eq true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'updated project' do
|
59
|
+
before :each do
|
60
|
+
@project = @toggl.create_project({ 'name' => 'project to update', 'wid' => @workspace_id })
|
61
|
+
end
|
62
|
+
|
63
|
+
after :each do
|
64
|
+
@toggl.delete_project(@project['id'])
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'updates project data' do
|
68
|
+
new_values = {
|
69
|
+
'name' => 'PROJECT-NEW',
|
70
|
+
'is_private' => false,
|
71
|
+
'active' => false,
|
72
|
+
'auto_estimates' => true,
|
73
|
+
}
|
74
|
+
project = @toggl.update_project(@project['id'], new_values)
|
75
|
+
expect(project).to include(new_values)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'updates Pro project data', :pro_account do
|
79
|
+
new_values = {
|
80
|
+
'template' => true,
|
81
|
+
'billable' => true,
|
82
|
+
}
|
83
|
+
project = @toggl.update_project(@project['id'], new_values)
|
84
|
+
expect(project).to include(new_values)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'multiple projects' do
|
89
|
+
after :all do
|
90
|
+
TogglV8SpecHelper.delete_all_projects(@toggl)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'deletes multiple projects' do
|
94
|
+
# start with no projects
|
95
|
+
expect(@toggl.projects(@workspace_id)).to be_empty
|
96
|
+
|
97
|
+
p1 = @toggl.create_project({ 'name' => 'p1', 'wid' => @workspace_id })
|
98
|
+
p2 = @toggl.create_project({ 'name' => 'p2', 'wid' => @workspace_id })
|
99
|
+
p3 = @toggl.create_project({ 'name' => 'p3', 'wid' => @workspace_id })
|
100
|
+
|
101
|
+
# see 3 new projects
|
102
|
+
expect(@toggl.projects(@workspace_id).length).to eq 3
|
103
|
+
|
104
|
+
p_ids = [p1, p2, p3].map { |p| p['id'] }
|
105
|
+
@toggl.delete_projects(p_ids)
|
106
|
+
|
107
|
+
# end with no projects
|
108
|
+
expect(@toggl.projects(@workspace_id)).to be_empty
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
describe 'Tags' do
|
2
|
+
before :all do
|
3
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
4
|
+
@workspaces = @toggl.workspaces
|
5
|
+
@workspace_id = @workspaces.first['id']
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'new tag' do
|
9
|
+
before :all do
|
10
|
+
@tag = @toggl.create_tag({ 'name' => 'new tag +1', 'wid' => @workspace_id })
|
11
|
+
tag_ids = @toggl.my_tags.map { |t| t['id'] }
|
12
|
+
expect(tag_ids).to eq [ @tag['id'] ]
|
13
|
+
end
|
14
|
+
|
15
|
+
after :all do
|
16
|
+
TogglV8SpecHelper.delete_all_tags(@toggl)
|
17
|
+
tags = @toggl.my_tags
|
18
|
+
expect(tags).to be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'creates a tag' do
|
22
|
+
expect(@tag).to_not be nil
|
23
|
+
expect(@tag['name']).to eq 'new tag +1'
|
24
|
+
expect(@tag['notes']).to eq nil
|
25
|
+
expect(@tag['wid']).to eq @workspace_id
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns tag associated with workspace_id' do
|
29
|
+
tags = @toggl.tags(@workspace_id)
|
30
|
+
expect(tags).not_to be_empty
|
31
|
+
expect(tags.first['name']).to eq 'new tag +1'
|
32
|
+
expect(tags.first['wid']).to eq @workspace_id
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'updated tag' do
|
37
|
+
before :each do
|
38
|
+
@tag = @toggl.create_tag({ 'name' => 'tag to update', 'wid' => @workspace_id })
|
39
|
+
end
|
40
|
+
|
41
|
+
after :each do
|
42
|
+
@toggl.delete_tag(@tag['id'])
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'updates tag data' do
|
46
|
+
new_values = {
|
47
|
+
'name' => 'TAG-NEW',
|
48
|
+
}
|
49
|
+
|
50
|
+
tag = @toggl.update_tag(@tag['id'], new_values)
|
51
|
+
expect(tag).to include(new_values)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
describe 'Tasks', :pro_account do
|
2
|
+
before :all do
|
3
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
4
|
+
@workspaces = @toggl.workspaces
|
5
|
+
@workspace_id = @workspaces.first['id']
|
6
|
+
@project = @toggl.create_project({ 'name' => 'project with a task', 'wid' => @workspace_id })
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
@toggl.delete_project(@project['id'])
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'new task' do
|
14
|
+
before :all do
|
15
|
+
@task = @toggl.create_task({ 'name' => 'new task +1', 'pid' => @project['id'] })
|
16
|
+
@task_ids = @toggl.get_project_tasks(@project['id']).map { |t| t['id'] }
|
17
|
+
expect(@task_ids).to eq [ @task['id'] ]
|
18
|
+
end
|
19
|
+
|
20
|
+
after :all do
|
21
|
+
@toggl.delete_tasks(@task_ids)
|
22
|
+
tasks = @toggl.get_project_tasks(@project['id'])
|
23
|
+
expect(tasks).to be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'creates a task' do
|
27
|
+
expect(@task).to_not be nil
|
28
|
+
expect(@task['name']).to eq 'new task +1'
|
29
|
+
expect(@task['pid']).to eq @project['id']
|
30
|
+
expect(@task['wid']).to eq @workspace_id
|
31
|
+
expect(@task['active']).to eq true
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'gets a task' do
|
35
|
+
task = @toggl.get_task(@task['id'])
|
36
|
+
expect(task).to include('at') # 'at' is last updated timestamp
|
37
|
+
task.delete('at') # 'at' is not included in POST response
|
38
|
+
expect(task).to eq @task # compare POST and GET responses
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'updated task' do
|
43
|
+
before :each do
|
44
|
+
@task = @toggl.create_task({ 'name' => 'task to update', 'pid' => @project['id'] })
|
45
|
+
end
|
46
|
+
|
47
|
+
after :each do
|
48
|
+
@toggl.delete_task(@task['id'])
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'updates task data' do
|
52
|
+
new_values = {
|
53
|
+
'name' => 'task-NEW',
|
54
|
+
}
|
55
|
+
|
56
|
+
task = @toggl.update_task(@task['id'], new_values)
|
57
|
+
expect(task).to include(new_values)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'multiple tasks' do
|
62
|
+
before :each do
|
63
|
+
timestamp = Time.now.strftime("%H%M%S.%9N")
|
64
|
+
@task1 = @toggl.create_task({ 'name' => "task1-#{timestamp}", 'pid' => @project['id'] })
|
65
|
+
@task2 = @toggl.create_task({ 'name' => "task2-#{timestamp}", 'pid' => @project['id'] })
|
66
|
+
@task3 = @toggl.create_task({ 'name' => "task3-#{timestamp}", 'pid' => @project['id'] })
|
67
|
+
@task_ids = [ @task1['id'], @task2['id'], @task3['id'] ]
|
68
|
+
end
|
69
|
+
|
70
|
+
after :all do
|
71
|
+
@toggl.delete_tasks(@task_ids)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'updates multiple tasks' do
|
75
|
+
# start with 3 active tasks
|
76
|
+
tasks = @toggl.get_project_tasks(@project['id'])
|
77
|
+
active_flags = tasks.map { |t| t['active'] }
|
78
|
+
expect(active_flags).to match_array([true, true, true])
|
79
|
+
|
80
|
+
t_ids = [@task1, @task2, @task3].map { |t| t['id'] }
|
81
|
+
params = { 'active' => false }
|
82
|
+
@toggl.update_tasks(t_ids, params)
|
83
|
+
|
84
|
+
# end with no active tasks
|
85
|
+
tasks = @toggl.get_project_tasks(@project['id'])
|
86
|
+
expect(tasks).to be_empty
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'deletes multiple tasks' do
|
90
|
+
# start with 3 new tasks
|
91
|
+
expect(@toggl.get_project_tasks(@project['id']).length).to eq 3
|
92
|
+
|
93
|
+
t_ids = [@task1, @task2, @task3].map { |t| t['id'] }
|
94
|
+
@toggl.delete_tasks(t_ids)
|
95
|
+
|
96
|
+
# end with no active tasks
|
97
|
+
expect(@toggl.get_project_tasks(@project['id'])).to be_empty
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|