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.
@@ -0,0 +1,425 @@
1
+ require 'date'
2
+
3
+ describe 'Time Entries' do
4
+ before :all do
5
+ @toggl = TogglV8::API.new(Testing::API_TOKEN)
6
+ @workspaces = @toggl.workspaces
7
+ @workspace_id = @workspaces.first['id']
8
+ end
9
+
10
+ context 'CRUD time entry' do
11
+ before :each do
12
+ time_entry_info = {
13
+ 'wid' => @workspace_id,
14
+ 'start' => @toggl.iso8601(DateTime.now),
15
+ 'duration' => 77
16
+ }
17
+
18
+ @expected = time_entry_info.clone
19
+
20
+ @time_entry = @toggl.create_time_entry(time_entry_info)
21
+ end
22
+
23
+ after :each do
24
+ @toggl.delete_time_entry(@time_entry['id'])
25
+ end
26
+
27
+ it 'creates a time entry' do
28
+ expect(@time_entry).to include(@expected)
29
+ end
30
+
31
+ it 'requires a workspace, project, or task to create' do
32
+ time_entry_info = {
33
+ 'start' => @toggl.iso8601(DateTime.now),
34
+ 'duration' => 77
35
+ }
36
+
37
+ expect {
38
+ @toggl.create_time_entry(time_entry_info)
39
+ }.to raise_error(ArgumentError)
40
+ end
41
+
42
+ it 'gets a time entry' do
43
+ retrieved_time_entry = @toggl.get_time_entry(@time_entry['id'])
44
+
45
+ ['start', 'stop'].each do |key|
46
+ expect(retrieved_time_entry[key]).to eq_ts @time_entry[key]
47
+ retrieved_time_entry.delete(key)
48
+ @time_entry.delete(key)
49
+ end
50
+
51
+ expect(retrieved_time_entry).to eq @time_entry
52
+ end
53
+
54
+ it 'updates a time entry' do
55
+ time_entry_info = {
56
+ 'start' => '2010-02-13T23:31:30+00:00',
57
+ 'duration' => 42
58
+ }
59
+
60
+ expected = time_entry_info.clone
61
+
62
+ time_entry_updated = @toggl.update_time_entry(@time_entry['id'], time_entry_info)
63
+ expect(time_entry_updated).to include(expected)
64
+ end
65
+
66
+ it 'deletes a time entry' do
67
+ existing_time_entry = @toggl.get_time_entry(@time_entry['id'])
68
+ expect(existing_time_entry.has_key?('server_deleted_at')).to eq false
69
+
70
+ deleted_time_entry = @toggl.delete_time_entry(@time_entry['id'])
71
+ expect(deleted_time_entry).to eq "[#{ @time_entry['id'] }]"
72
+
73
+ zombie_time_entry = @toggl.get_time_entry(@time_entry['id'])
74
+ expect(zombie_time_entry.has_key?('server_deleted_at')).to eq true
75
+ end
76
+ end
77
+
78
+ context '+ UTC offset' do
79
+ # ISO8601 times with positive '+' UTC offsets must be properly encoded
80
+
81
+ before :each do
82
+ time_entry_info = {
83
+ 'wid' => @workspace_id,
84
+ 'start' => '2016-01-22T12:08:14+02:00',
85
+ 'duration' => 77
86
+ }
87
+
88
+ @expected = time_entry_info.clone
89
+
90
+ @time_entry = @toggl.create_time_entry(time_entry_info)
91
+ end
92
+
93
+ after :each do
94
+ @toggl.delete_time_entry(@time_entry['id'])
95
+ end
96
+
97
+ it 'creates a time entry' do
98
+ expect(@time_entry).to include(@expected)
99
+ end
100
+
101
+ it 'requires a workspace, project, or task to create' do
102
+ time_entry_info = {
103
+ 'start' => '2016-01-22T12:08:14+02:00',
104
+ 'duration' => 77
105
+ }
106
+
107
+ expect {
108
+ @toggl.create_time_entry(time_entry_info)
109
+ }.to raise_error(ArgumentError)
110
+ end
111
+
112
+ it 'gets a time entry' do
113
+ retrieved_time_entry = @toggl.get_time_entry(@time_entry['id'])
114
+
115
+ ['start', 'stop'].each do |key|
116
+ expect(retrieved_time_entry[key]).to eq_ts @time_entry[key]
117
+ retrieved_time_entry.delete(key)
118
+ @time_entry.delete(key)
119
+ end
120
+
121
+ expect(retrieved_time_entry).to eq @time_entry
122
+ end
123
+
124
+ it 'updates a time entry' do
125
+ time_entry_info = {
126
+ 'start' => '2010-02-13T23:31:30+07:00',
127
+ 'duration' => 42
128
+ }
129
+
130
+ expected = time_entry_info.clone
131
+
132
+ time_entry_updated = @toggl.update_time_entry(@time_entry['id'], time_entry_info)
133
+ expect(time_entry_updated).to include(expected)
134
+ end
135
+
136
+ it 'deletes a time entry' do
137
+ existing_time_entry = @toggl.get_time_entry(@time_entry['id'])
138
+ expect(existing_time_entry.has_key?('server_deleted_at')).to eq false
139
+
140
+ deleted_time_entry = @toggl.delete_time_entry(@time_entry['id'])
141
+ expect(deleted_time_entry).to eq "[#{ @time_entry['id'] }]"
142
+
143
+ zombie_time_entry = @toggl.get_time_entry(@time_entry['id'])
144
+ expect(zombie_time_entry.has_key?('server_deleted_at')).to eq true
145
+ end
146
+ end
147
+
148
+ context 'multiple time entries' do
149
+ before :all do
150
+ time_entry_info = {
151
+ 'wid' => @workspace_id,
152
+ 'duration' => 77
153
+ }
154
+ @now = DateTime.now
155
+
156
+ start = { 'start' => @toggl.iso8601(@now - 9) }
157
+ @time_entry_nine_days_ago = @toggl.create_time_entry(time_entry_info.merge(start))
158
+ @nine_days_ago_id = @time_entry_nine_days_ago['id']
159
+
160
+ start = { 'start' => @toggl.iso8601(@now - 7) }
161
+ @time_entry_last_week = @toggl.create_time_entry(time_entry_info.merge(start))
162
+ @last_week_id = @time_entry_last_week['id']
163
+
164
+ start = { 'start' => @toggl.iso8601(@now) }
165
+ @time_entry_now = @toggl.create_time_entry(time_entry_info.merge(start))
166
+ @now_id = @time_entry_now['id']
167
+
168
+ start = { 'start' => @toggl.iso8601(@now + 7) }
169
+ @time_entry_next_week = @toggl.create_time_entry(time_entry_info.merge(start))
170
+ @next_week_id = @time_entry_next_week['id']
171
+ end
172
+
173
+ after :all do
174
+ TogglV8SpecHelper.delete_all_time_entries(@toggl)
175
+ end
176
+
177
+ it 'gets time entries (reaching back 9 days up till now)' do
178
+ ids = @toggl.get_time_entries.map { |t| t['id']}
179
+ expect(ids).to eq [ @last_week_id, @now_id ]
180
+ end
181
+
182
+ it 'gets time entries after start_date (up till now)' do
183
+ ids = @toggl.get_time_entries({:start_date => @now - 1}).map { |t| t['id']}
184
+ expect(ids).to eq [ @now_id ]
185
+ end
186
+
187
+ it 'gets time entries between start_date and end_date' do
188
+ ids = @toggl.get_time_entries({:start_date => @now - 1, :end_date => @now + 1}).map { |t| t['id']}
189
+ expect(ids).to eq [ @now_id ]
190
+ end
191
+
192
+ it 'gets time entries in the future' do
193
+ ids = @toggl.get_time_entries({:start_date => @now - 1, :end_date => @now + 8}).map { |t| t['id']}
194
+ expect(ids).to eq [ @now_id, @next_week_id ]
195
+ end
196
+ end
197
+
198
+ context 'start and stop time entry' do
199
+ it 'starts and stops a time entry' do
200
+ time_entry_info = {
201
+ 'wid' => @workspace_id,
202
+ 'description' => 'time entry description'
203
+ }
204
+
205
+ # start time entry
206
+ running_time_entry = @toggl.start_time_entry(time_entry_info)
207
+
208
+ # get current time entry by '/current'
209
+ time_entry_current = @toggl.get_current_time_entry
210
+ # get current time entry by id
211
+ time_entry_by_id = @toggl.get_time_entry(running_time_entry['id'])
212
+
213
+ # compare two methods of getting current time entry
214
+ expect(time_entry_current).to eq time_entry_by_id
215
+
216
+ # compare current time entry with running time entry
217
+ expect(time_entry_by_id['start']).to eq_ts running_time_entry['start']
218
+ time_entry_by_id.delete('start')
219
+ running_time_entry.delete('start')
220
+
221
+ expect(time_entry_by_id).to eq running_time_entry
222
+ expect(time_entry_by_id.has_key?('stop')).to eq false
223
+
224
+ # stop time entry
225
+ stopped_time_entry = @toggl.stop_time_entry(running_time_entry['id'])
226
+ expect(stopped_time_entry.has_key?('stop')).to eq true
227
+
228
+ @toggl.delete_time_entry(stopped_time_entry['id'])
229
+ end
230
+
231
+ it 'returns nil if there is no current time entry' do
232
+ time_entry = @toggl.get_current_time_entry
233
+ expect(time_entry).to be nil
234
+ end
235
+
236
+ it 'requires a workspace, project, or task to start' do
237
+ time_entry_info = {
238
+ 'description' => 'time entry description'
239
+ }
240
+
241
+ expect {
242
+ @toggl.start_time_entry(time_entry_info)
243
+ }.to raise_error(ArgumentError)
244
+ end
245
+ end
246
+
247
+ context 'time entry tags' do
248
+ before :each do
249
+ time_entry_info = {
250
+ 'wid' => @workspace_id,
251
+ 'duration' => 7777
252
+ }
253
+ @now = DateTime.now
254
+
255
+ start = { 'start' => @toggl.iso8601(@now - 7) }
256
+ @time7 = @toggl.create_time_entry(time_entry_info.merge(start))
257
+
258
+ start = { 'start' => @toggl.iso8601(@now - 6) }
259
+ @time6 = @toggl.create_time_entry(time_entry_info.merge(start))
260
+
261
+ start = { 'start' => @toggl.iso8601(@now - 5) }
262
+ @time5 = @toggl.create_time_entry(time_entry_info.merge(start))
263
+
264
+ start = { 'start' => @toggl.iso8601(@now - 4) }
265
+ @time4 = @toggl.create_time_entry(time_entry_info.merge(start))
266
+
267
+ @time_entry_ids = [ @time7['id'], @time6['id'], @time5['id'], @time4['id']]
268
+ end
269
+
270
+ after :each do
271
+ TogglV8SpecHelper.delete_all_time_entries(@toggl)
272
+ TogglV8SpecHelper.delete_all_tags(@toggl)
273
+ end
274
+
275
+ it 'adds and removes one tag' do
276
+ # Add one tag
277
+ @toggl.update_time_entries_tags_fixed(@time_entry_ids,
278
+ {'tags' =>['money'], 'tag_action' => 'add'})
279
+
280
+ time_entries = @toggl.get_time_entries
281
+ tags = time_entries.map { |t| t['tags'] }
282
+ expect(tags).to eq [
283
+ ['money'],
284
+ ['money'],
285
+ ['money'],
286
+ ['money']
287
+ ]
288
+
289
+ # Remove one tag
290
+ @toggl.update_time_entries_tags_fixed(@time_entry_ids,
291
+ {'tags' =>['money'], 'tag_action' => 'remove'})
292
+
293
+ time_entries = @toggl.get_time_entries
294
+ tags = time_entries.map { |t| t['tags'] }.compact
295
+ expect(tags).to eq []
296
+ end
297
+
298
+ it '"removes" a non-existent tag' do
299
+ # Not tags to start
300
+ time_entries = @toggl.get_time_entries
301
+ tags = time_entries.map { |t| t['tags'] }.compact
302
+ expect(tags).to eq []
303
+
304
+ # "Remove" a tag
305
+ @toggl.update_time_entries_tags_fixed(@time_entry_ids,
306
+ {'tags' =>['void'], 'tag_action' => 'remove'})
307
+
308
+ # No tags to finish
309
+ time_entries = @toggl.get_time_entries
310
+ tags = time_entries.map { |t| t['tags'] }.compact
311
+ expect(tags).to eq []
312
+ end
313
+
314
+ it 'adds and removes multiple tags' do
315
+ # Add multiple tags
316
+ @toggl.update_time_entries_tags_fixed(@time_entry_ids,
317
+ {'tags' =>['billed', 'productive'], 'tag_action' => 'add'})
318
+
319
+ time_entries = @toggl.get_time_entries
320
+ tags = time_entries.map { |t| t['tags'] }
321
+ expect(tags).to eq [
322
+ ['billed', 'productive'],
323
+ ['billed', 'productive'],
324
+ ['billed', 'productive'],
325
+ ['billed', 'productive']
326
+ ]
327
+
328
+ # Remove multiple tags
329
+ @toggl.update_time_entries_tags_fixed(@time_entry_ids,
330
+ {'tags' =>['billed','productive'], 'tag_action' => 'remove'})
331
+
332
+ time_entries = @toggl.get_time_entries
333
+ tags = time_entries.map { |t| t['tags'] }.compact
334
+ expect(tags).to eq []
335
+ end
336
+
337
+ it 'manages multiple tags' do
338
+ # Add some tags
339
+ @toggl.update_time_entries_tags_fixed(@time_entry_ids,
340
+ {'tags' =>['billed', 'productive'], 'tag_action' => 'add'})
341
+
342
+ # Remove some tags
343
+ @toggl.update_time_entries_tags_fixed([ @time6['id'], @time4['id'] ],
344
+ {'tags' =>['billed'], 'tag_action' => 'remove'})
345
+
346
+ # Add some tags
347
+ @toggl.update_time_entries_tags_fixed([ @time7['id'] ],
348
+ {'tags' =>['best'], 'tag_action' => 'add'})
349
+
350
+ time7 = @toggl.get_time_entry(@time7['id'])
351
+ time6 = @toggl.get_time_entry(@time6['id'])
352
+ time5 = @toggl.get_time_entry(@time5['id'])
353
+ time4 = @toggl.get_time_entry(@time4['id'])
354
+
355
+ tags = [ time7['tags'], time6['tags'], time5['tags'], time4['tags'] ]
356
+ expect(tags).to eq [
357
+ ['best', 'billed', 'productive'],
358
+ [ 'productive'],
359
+ [ 'billed', 'productive'],
360
+ [ 'productive']
361
+ ]
362
+ end
363
+ end
364
+
365
+ context 'iso8601' do
366
+ before :all do
367
+ @ts = DateTime.new(2008,6,21, 13,30,2, "+09:00")
368
+ @expected = '2008-06-21T13:30:02+09:00'
369
+ end
370
+
371
+ it 'formats a DateTime' do
372
+ expect(@toggl.iso8601(@ts)).to eq @expected
373
+ end
374
+
375
+ it 'formats a Date' do
376
+ ts = @ts.to_date
377
+ expect(@toggl.iso8601(@ts)).to eq @expected
378
+ end
379
+
380
+ it 'formats a Time' do
381
+ ts = @ts.to_time
382
+ expect(@toggl.iso8601(@ts)).to eq @expected
383
+ end
384
+
385
+ it 'cannot format a FixNum' do
386
+ expect{ @toggl.iso8601(1234567890) }.to raise_error(ArgumentError)
387
+ end
388
+
389
+ it 'cannot format a malformed timestamp' do
390
+ expect{ @toggl.iso8601('X') }.to raise_error(ArgumentError)
391
+ end
392
+
393
+ context 'String' do
394
+ it 'converts +00:00 to Zulu' do
395
+ ts = '2015-08-21T09:21:02+00:00'
396
+ expected = '2015-08-21T09:21:02Z'
397
+
398
+ expect(@toggl.iso8601(ts)).to eq expected
399
+ end
400
+
401
+ it 'converts -00:00 to Z' do
402
+ ts = '2015-08-21T09:21:02-00:00'
403
+ expected = '2015-08-21T09:21:02Z'
404
+
405
+ expect(@toggl.iso8601(ts)).to eq expected
406
+ end
407
+
408
+ it 'maintains an offset' do
409
+ expect(@toggl.iso8601('2015-08-21T04:21:02-05:00')).to eq '2015-08-21T04:21:02-05:00'
410
+ end
411
+ end
412
+ end
413
+
414
+ RSpec::Matchers.define :eq_ts do |expected|
415
+ # Matching actual time is necessary due to differing formats.
416
+ # Example:
417
+ # 1) POST time_entries/start returns 2015-08-21T07:28:20Z
418
+ # when GET time_entries/{time_entry_id} returns 2015-08-21T07:28:20+00:00
419
+ # 2) 2015-08-21T03:20:30-05:00 and 2015-08-21T08:20:30+00:00 refer to
420
+ # the same moment in time, but one is in local time and the other in UTC
421
+ match do |actual|
422
+ DateTime.parse(actual) == DateTime.parse(expected)
423
+ end
424
+ end
425
+ end
@@ -0,0 +1,82 @@
1
+ describe 'Users' do
2
+ before :all do
3
+ @toggl = TogglV8::API.new(Testing::API_TOKEN)
4
+ @user = @toggl.me(all=true)
5
+ @workspaces = @toggl.workspaces
6
+ @workspace_id = @workspaces.first['id']
7
+ end
8
+
9
+ it 'returns /me' do
10
+ expect(@user).to_not be_nil
11
+ expect(@user['id']).to eq Testing::USER_ID
12
+ expect(@user['fullname']).to eq Testing::USERNAME
13
+ # expect(@user['image_url']).to eq 'https://assets.toggl.com/avatars/a5d106126b6bed8df283e708af0828ee.png'
14
+ # expect(@user['timezone']).to eq 'Etc/UTC'
15
+ # expect(@user['workspaces'].length).to eq 1
16
+ # expect(@user['workspaces'].first['name']).to eq "togglv8's workspace"
17
+ end
18
+
19
+ it 'returns my_clients' do
20
+ my_clients = @toggl.my_clients(@user)
21
+ expect(my_clients).to be_empty
22
+ end
23
+
24
+ it 'returns my_projects' do
25
+ my_projects = @toggl.my_projects(@user)
26
+ expect(my_projects).to be_empty
27
+ end
28
+
29
+ it 'returns my_projects and my_deleted_projects' do
30
+ # Create project
31
+ project = @toggl.create_project({ 'name' => 'my project', 'wid' => @workspace_id })
32
+
33
+ my_project_ids = @toggl.my_projects.map { |p| p['id'] }
34
+ my_deleted_project_ids = @toggl.my_deleted_projects.map { |p| p['id'] }
35
+
36
+ expect(my_project_ids).to eq [ project['id'] ]
37
+ expect(my_deleted_project_ids).not_to include(project['id'])
38
+
39
+ # Delete project
40
+ @toggl.delete_project(project['id'])
41
+
42
+ my_project_ids = @toggl.my_projects.map { |p| p['id'] }
43
+ my_deleted_project_ids = @toggl.my_deleted_projects.map { |p| p['id'] }
44
+
45
+ expect(my_project_ids).to eq []
46
+ expect(my_deleted_project_ids).to include(project['id'])
47
+ end
48
+
49
+ it 'returns my_tags' do
50
+ my_tags = @toggl.my_tags(@user)
51
+ expect(my_tags).to be_empty
52
+ end
53
+
54
+ it 'returns my_tasks' do
55
+ my_tasks = @toggl.my_tasks(@user)
56
+ expect(my_tasks).to be_empty
57
+ end
58
+
59
+ it 'returns my_time_entries' do
60
+ my_time_entries = @toggl.my_time_entries(@user)
61
+ expect(my_time_entries).to be_empty
62
+ end
63
+
64
+ it 'returns my_workspaces' do
65
+ my_workspaces = @toggl.my_workspaces(@user)
66
+ expect(my_workspaces.length).to eq 1
67
+ end
68
+
69
+ context 'new user' do
70
+ it 'creates a new user' do
71
+ now = Time.now.to_i
72
+ user_info = {
73
+ 'email' => "test-#{now}+1@mailinator.com",
74
+ 'timezone' => 'Etc/UTC'
75
+ }
76
+ user_password = { 'password' => "password-#{now}+1" }
77
+
78
+ new_user = @toggl.create_user(user_info.merge(user_password))
79
+ expect(new_user).to include(user_info)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,45 @@
1
+ describe 'Workspaces' do
2
+ before :all do
3
+ @toggl = TogglV8::API.new(Testing::API_TOKEN)
4
+ @user = @toggl.me(all=true)
5
+ @workspaces = @toggl.workspaces
6
+ @workspace_id = @workspaces.first['id']
7
+ @project = @toggl.create_project({ 'name' => 'project with a task', 'wid' => @workspace_id })
8
+ end
9
+
10
+ after :all do
11
+ @toggl.delete_project(@project['id'])
12
+ end
13
+
14
+ it 'shows users' do
15
+ users = @toggl.users(@workspace_id)
16
+ expect(users.length).to eq 2
17
+
18
+ expect(users.first['id']).to eq Testing::OTHER_USER_ID
19
+ expect(users.first['email']).to eq Testing::OTHER_EMAIL
20
+ expect(users.first['fullname']).to eq Testing::OTHER_USERNAME
21
+
22
+ expect(users.last['id']).to eq Testing::USER_ID
23
+ expect(users.last['email']).to eq Testing::EMAIL
24
+ expect(users.last['fullname']).to eq Testing::USERNAME
25
+ expect(users.last['default_wid']).to eq @workspace_id
26
+ end
27
+
28
+ context 'tasks', :pro_account do
29
+ before :each do
30
+ @task = @toggl.create_task('name' => 'workspace task', 'pid' => @project['id'])
31
+ end
32
+
33
+ after :each do
34
+ @toggl.delete_task(@task['id'])
35
+ end
36
+
37
+ it 'shows tasks' do
38
+ tasks = @toggl.tasks(@workspace_id)
39
+ expect(tasks.length).to eq 1
40
+ expect(tasks.first['name']).to eq 'workspace task'
41
+ expect(tasks.first['pid']).to eq @project['id']
42
+ expect(tasks.first['wid']).to eq @workspace_id
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,88 @@
1
+ require 'fileutils'
2
+
3
+ describe 'TogglV8' do
4
+ it 'initializes with api_token' do
5
+ toggl = TogglV8::API.new(Testing::API_TOKEN)
6
+ me = toggl.me
7
+ expect(me).to_not be nil
8
+ expect(me['api_token']).to eq Testing::API_TOKEN
9
+ expect(me['email']).to eq Testing::EMAIL
10
+ end
11
+
12
+ it 'initializes with username and password' do
13
+ toggl = TogglV8::API.new(Testing::EMAIL, Testing::PASSWORD)
14
+ me = toggl.me
15
+ expect(me).to_not be nil
16
+ expect(me['api_token']).to eq Testing::API_TOKEN
17
+ expect(me['email']).to eq Testing::EMAIL
18
+ end
19
+
20
+ it 'does not initialize with bogus api_token' do
21
+ toggl = TogglV8::API.new('4880nqor1orr9n241sn08070q33oq49s')
22
+ expect { toggl.me }.to raise_error(RuntimeError, "HTTP Status: 403")
23
+ end
24
+
25
+ context '.toggl file' do
26
+ before :each do
27
+ @tmp_home = mktemp_dir
28
+ @original_home = Dir.home
29
+ ENV['HOME'] = @tmp_home
30
+ end
31
+
32
+ after :each do
33
+ FileUtils.rm_rf(@tmp_home)
34
+ ENV['HOME'] = @original_home
35
+ end
36
+
37
+ it 'initializes with .toggl file' do
38
+ toggl_file = File.join(@tmp_home, '.toggl')
39
+ File.open(toggl_file, 'w') { |file| file.write(Testing::API_TOKEN) }
40
+
41
+ toggl = TogglV8::API.new
42
+ me = toggl.me
43
+ expect(me).to_not be nil
44
+ expect(me['api_token']).to eq Testing::API_TOKEN
45
+ expect(me['email']).to eq Testing::EMAIL
46
+ end
47
+
48
+ it 'initializes with .toggl file ending with a newline' do
49
+ toggl_file = File.join(@tmp_home, '.toggl')
50
+ File.open(toggl_file, 'w') { |file| file.write(Testing::API_TOKEN + "\n") }
51
+
52
+ toggl = TogglV8::API.new
53
+ me = toggl.me
54
+ expect(me).to_not be nil
55
+ expect(me['api_token']).to eq Testing::API_TOKEN
56
+ expect(me['email']).to eq Testing::EMAIL
57
+ end
58
+
59
+ it 'raises error if .toggl file is missing' do
60
+ expect{ toggl = TogglV8::API.new }.to raise_error(RuntimeError)
61
+ end
62
+ end
63
+
64
+ context 'handles errors' do
65
+ before :all do
66
+ @toggl = TogglV8::API.new(Testing::API_TOKEN)
67
+ end
68
+
69
+ it 'surfaces an HTTP Status Code in case of error' do
70
+ expect(@toggl.conn).to receive(:get).once.and_return(
71
+ MockResponse.new(400, {}, 'body'))
72
+ expect { @toggl.me }.to raise_error(RuntimeError, "HTTP Status: 400")
73
+ end
74
+
75
+ it 'retries a request up to 3 times if a 429 is received' do
76
+ expect(@toggl.conn).to receive(:get).exactly(3).times.and_return(
77
+ MockResponse.new(429, {}, 'body'))
78
+ expect { @toggl.me }.to raise_error(RuntimeError, "HTTP Status: 429")
79
+ end
80
+
81
+ it 'retries a request after 429' do
82
+ expect(@toggl.conn).to receive(:get).twice.and_return(
83
+ MockResponse.new(429, {}, 'body'),
84
+ MockResponse.new(200, {}, nil))
85
+ expect(@toggl.me).to eq({}) # response is {} in this case because body is nil
86
+ end
87
+ end
88
+ end