ruby-trello-czuger 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +182 -0
  3. data/lib/trello.rb +163 -0
  4. data/lib/trello/action.rb +68 -0
  5. data/lib/trello/association.rb +14 -0
  6. data/lib/trello/association_proxy.rb +42 -0
  7. data/lib/trello/attachment.rb +40 -0
  8. data/lib/trello/authorization.rb +187 -0
  9. data/lib/trello/basic_data.rb +132 -0
  10. data/lib/trello/board.rb +211 -0
  11. data/lib/trello/card.rb +467 -0
  12. data/lib/trello/checklist.rb +143 -0
  13. data/lib/trello/client.rb +120 -0
  14. data/lib/trello/comment.rb +62 -0
  15. data/lib/trello/configuration.rb +68 -0
  16. data/lib/trello/core_ext/array.rb +6 -0
  17. data/lib/trello/core_ext/hash.rb +6 -0
  18. data/lib/trello/core_ext/string.rb +6 -0
  19. data/lib/trello/cover_image.rb +8 -0
  20. data/lib/trello/has_actions.rb +9 -0
  21. data/lib/trello/item.rb +37 -0
  22. data/lib/trello/item_state.rb +30 -0
  23. data/lib/trello/json_utils.rb +64 -0
  24. data/lib/trello/label.rb +108 -0
  25. data/lib/trello/label_name.rb +31 -0
  26. data/lib/trello/list.rb +114 -0
  27. data/lib/trello/member.rb +112 -0
  28. data/lib/trello/multi_association.rb +12 -0
  29. data/lib/trello/net.rb +39 -0
  30. data/lib/trello/notification.rb +61 -0
  31. data/lib/trello/organization.rb +68 -0
  32. data/lib/trello/plugin_datum.rb +34 -0
  33. data/lib/trello/token.rb +37 -0
  34. data/lib/trello/webhook.rb +103 -0
  35. data/spec/action_spec.rb +149 -0
  36. data/spec/array_spec.rb +13 -0
  37. data/spec/association_spec.rb +26 -0
  38. data/spec/basic_auth_policy_spec.rb +51 -0
  39. data/spec/board_spec.rb +442 -0
  40. data/spec/card_spec.rb +822 -0
  41. data/spec/checklist_spec.rb +296 -0
  42. data/spec/client_spec.rb +257 -0
  43. data/spec/configuration_spec.rb +95 -0
  44. data/spec/hash_spec.rb +15 -0
  45. data/spec/integration/how_to_authorize_spec.rb +53 -0
  46. data/spec/integration/how_to_use_boards_spec.rb +48 -0
  47. data/spec/integration/integration_test.rb +40 -0
  48. data/spec/item_spec.rb +75 -0
  49. data/spec/json_utils_spec.rb +73 -0
  50. data/spec/label_spec.rb +205 -0
  51. data/spec/list_spec.rb +253 -0
  52. data/spec/member_spec.rb +159 -0
  53. data/spec/notification_spec.rb +143 -0
  54. data/spec/oauth_policy_spec.rb +160 -0
  55. data/spec/organization_spec.rb +71 -0
  56. data/spec/spec_helper.rb +435 -0
  57. data/spec/string_spec.rb +55 -0
  58. data/spec/token_spec.rb +89 -0
  59. data/spec/trello_spec.rb +134 -0
  60. data/spec/webhook_spec.rb +130 -0
  61. metadata +200 -0
data/spec/card_spec.rb ADDED
@@ -0,0 +1,822 @@
1
+ require 'spec_helper'
2
+
3
+ module Trello
4
+ describe Card do
5
+ include Helpers
6
+
7
+ let(:card) { client.find(:card, 'abcdef123456789123456789') }
8
+ let(:client) { Client.new }
9
+
10
+ before do
11
+ allow(client)
12
+ .to receive(:get)
13
+ .with("/cards/abcdef123456789123456789", {})
14
+ .and_return JSON.generate(cards_details.first)
15
+ end
16
+
17
+ context "finding" do
18
+ let(:client) { Trello.client }
19
+
20
+ before do
21
+ allow(client)
22
+ .to receive(:find)
23
+ end
24
+
25
+ it "delegates to Trello.client#find" do
26
+ expect(client)
27
+ .to receive(:find)
28
+ .with(:card, 'abcdef123456789123456789', {})
29
+
30
+ Card.find('abcdef123456789123456789')
31
+ end
32
+
33
+ it "is equivalent to client#find" do
34
+ expect(Card.find('abcdef123456789123456789')).to eq(card)
35
+ end
36
+ end
37
+
38
+ context "creating" do
39
+ let(:client) { Trello.client }
40
+
41
+ it "creates a new record" do
42
+ cards_details.each do |card_details|
43
+ card = Card.new(card_details)
44
+ expect(card).to be_valid
45
+ end
46
+ end
47
+
48
+ it 'properly initializes all fields from response-like formatted hash' do
49
+ card_details = cards_details.first
50
+ card = Card.new(card_details)
51
+ expect(card.id).to eq(card_details['id'])
52
+ expect(card.short_id).to eq(card_details['idShort'])
53
+ expect(card.name).to eq(card_details['name'])
54
+ expect(card.desc).to eq(card_details['desc'])
55
+ expect(card.closed).to eq(card_details['closed'])
56
+ expect(card.list_id).to eq(card_details['idList'])
57
+ expect(card.board_id).to eq(card_details['idBoard'])
58
+ expect(card.cover_image_id).to eq(card_details['idAttachmentCover'])
59
+ expect(card.member_ids).to eq(card_details['idMembers'])
60
+ expect(card.labels).to eq(card_details['labels'].map { |lbl| Trello::Label.new(lbl) })
61
+ expect(card.card_labels).to eq(card_details['idLabels'])
62
+ expect(card.url).to eq(card_details['url'])
63
+ expect(card.short_url).to eq(card_details['shortUrl'])
64
+ expect(card.pos).to eq(card_details['pos'])
65
+ expect(card.last_activity_date).to eq(card_details['dateLastActivity'])
66
+ end
67
+
68
+ it 'properly initializes all fields from options-like formatted hash' do
69
+ card_details = cards_details[1]
70
+ card = Card.new(card_details)
71
+ expect(card.name).to eq(card_details[:name])
72
+ expect(card.list_id).to eq(card_details[:list_id])
73
+ expect(card.desc).to eq(card_details[:desc])
74
+ expect(card.member_ids).to eq(card_details[:member_ids])
75
+ expect(card.card_labels).to eq(card_details[:card_labels])
76
+ expect(card.due).to eq(card_details[:due])
77
+ expect(card.pos).to eq(card_details[:pos])
78
+ expect(card.source_card_id).to eq(card_details[:source_card_id])
79
+ expect(card.source_card_properties).to eq(card_details[:source_card_properties])
80
+ end
81
+
82
+ it 'must not be valid if not given a name' do
83
+ card = Card.new('idList' => lists_details.first['id'])
84
+ expect(card).to_not be_valid
85
+ end
86
+
87
+ it 'must not be valid if not given a list id' do
88
+ card = Card.new('name' => lists_details.first['name'])
89
+ expect(card).to_not be_valid
90
+ end
91
+
92
+ it 'creates a new record and saves it on Trello', refactor: true do
93
+ payload = {
94
+ name: 'Test Card',
95
+ desc: nil,
96
+ card_labels: "abcdef123456789123456789"
97
+ }
98
+
99
+ result = JSON.generate(cards_details.first.merge(payload.merge(idList: lists_details.first['id'])))
100
+
101
+ expected_payload = {name: "Test Card", desc: nil, idList: "abcdef123456789123456789",
102
+ idMembers: nil, idLabels: "abcdef123456789123456789", pos: nil, due: nil, dueComplete: false, idCardSource: nil, keepFromSource: 'all'}
103
+
104
+ expect(client)
105
+ .to receive(:post)
106
+ .with("/cards", expected_payload)
107
+ .and_return result
108
+
109
+ card = Card.create(cards_details.first.merge(payload.merge(list_id: lists_details.first['id'])))
110
+
111
+ expect(card).to be_a Card
112
+ end
113
+
114
+ it 'creates a duplicate card with all source properties and saves it on Trello', refactor: true do
115
+ payload = {
116
+ source_card_id: cards_details.first['id']
117
+ }
118
+
119
+ result = JSON.generate(cards_details.first.merge(payload.merge(idList: lists_details.first['id'])))
120
+
121
+ expected_payload = {name: nil, desc: nil, idList: "abcdef123456789123456789",
122
+ idMembers: nil, idLabels: nil, pos: nil, due: nil, dueComplete: false, idCardSource: cards_details.first['id'], keepFromSource: 'all'}
123
+
124
+ expect(client)
125
+ .to receive(:post)
126
+ .with("/cards", expected_payload)
127
+ .and_return result
128
+
129
+ card = Card.create(cards_details.first.merge(payload.merge(list_id: lists_details.first['id'])))
130
+
131
+ expect(card).to be_a Card
132
+ end
133
+
134
+ it 'creates a duplicate card with source due date and checklists and saves it on Trello', refactor: true do
135
+ payload = {
136
+ source_card_id: cards_details.first['id'],
137
+ source_card_properties: ['due', 'checklists']
138
+ }
139
+
140
+ result = JSON.generate(cards_details.first.merge(payload.merge(idList: lists_details.first['id'])))
141
+
142
+ expected_payload = {name: nil, desc: nil, idList: "abcdef123456789123456789",
143
+ idMembers: nil, idLabels: nil, pos: nil, due: nil, dueComplete: false, idCardSource: cards_details.first['id'], keepFromSource: ['due', 'checklists']}
144
+
145
+ expect(client)
146
+ .to receive(:post)
147
+ .with("/cards", expected_payload)
148
+ .and_return result
149
+
150
+ card = Card.create(cards_details.first.merge(payload.merge(list_id: lists_details.first['id'])))
151
+
152
+ expect(card).to be_a Card
153
+ end
154
+
155
+ it 'creates a duplicate card with no source properties and saves it on Trello', refactor: true do
156
+ payload = {
157
+ source_card_id: cards_details.first['id'],
158
+ source_card_properties: nil
159
+ }
160
+
161
+ result = JSON.generate(cards_details.first.merge(payload.merge(idList: lists_details.first['id'])))
162
+
163
+ expected_payload = {name: nil, desc: nil, idList: "abcdef123456789123456789",
164
+ idMembers: nil, idLabels: nil, pos: nil, due: nil, dueComplete: false, idCardSource: cards_details.first['id'], keepFromSource: nil}
165
+
166
+ expect(client)
167
+ .to receive(:post)
168
+ .with("/cards", expected_payload)
169
+ .and_return result
170
+
171
+ card = Card.create(cards_details.first.merge(payload.merge(list_id: lists_details.first['id'])))
172
+
173
+ expect(card).to be_a Card
174
+ end
175
+
176
+ end
177
+
178
+ context "updating" do
179
+ it "updating name does a put on the correct resource with the correct value" do
180
+ expected_new_name = "xxx"
181
+
182
+ payload = {
183
+ name: expected_new_name,
184
+ }
185
+
186
+ expect(client)
187
+ .to receive(:put)
188
+ .once
189
+ .with("/cards/abcdef123456789123456789", payload)
190
+
191
+ card.name = expected_new_name
192
+ card.save
193
+ end
194
+
195
+ it "updating desc does a put on the correct resource with the correct value" do
196
+ expected_new_desc = "xxx"
197
+
198
+ payload = {
199
+ desc: expected_new_desc,
200
+ }
201
+
202
+ expect(client).to receive(:put).once.with("/cards/abcdef123456789123456789", payload)
203
+
204
+ card.desc = expected_new_desc
205
+ card.save
206
+ end
207
+ end
208
+
209
+ context "deleting" do
210
+ it "deletes the card" do
211
+ expect(client)
212
+ .to receive(:delete)
213
+ .with("/cards/#{card.id}")
214
+
215
+ card.delete
216
+ end
217
+ end
218
+
219
+ context "fields" do
220
+ it "gets its id" do
221
+ expect(card.id).to_not be_nil
222
+ end
223
+
224
+ it "gets its short id" do
225
+ expect(card.short_id).to_not be_nil
226
+ end
227
+
228
+ it "gets its name" do
229
+ expect(card.name).to_not be_nil
230
+ end
231
+
232
+ it "gets its description" do
233
+ expect(card.desc).to_not be_nil
234
+ end
235
+
236
+ it "knows if it is open or closed" do
237
+ expect(card.closed).to_not be_nil
238
+ end
239
+
240
+ it "gets its url" do
241
+ expect(card.url).to_not be_nil
242
+ end
243
+
244
+ it "gets its short url" do
245
+ expect(card.short_url).to_not be_nil
246
+ end
247
+
248
+ it "gets its last active date" do
249
+ expect(card.last_activity_date).to_not be_nil
250
+ end
251
+
252
+ it "gets its cover image id" do
253
+ expect(card.cover_image_id).to_not be_nil
254
+ end
255
+
256
+ it "gets its pos" do
257
+ expect(card.pos).to_not be_nil
258
+ end
259
+
260
+
261
+ it 'gets its creation time' do
262
+ expect(card.created_at).to be_kind_of Time
263
+ end
264
+
265
+ it 'get its correct creation time' do
266
+ expect(card.created_at).to eq(Time.parse('2061-05-04 04:40:18 +0200'))
267
+ end
268
+
269
+ end
270
+
271
+ context "actions" do
272
+ let(:filter) { :all }
273
+
274
+ before do
275
+ allow(client)
276
+ .to receive(:get)
277
+ .with("/cards/abcdef123456789123456789/actions", { filter: filter })
278
+ .and_return actions_payload
279
+ end
280
+
281
+ it "asks for all actions by default" do
282
+ expect(card.actions.count).to be > 0
283
+ end
284
+
285
+ context 'when overriding a filter' do
286
+ let(:filter) { :updateCard }
287
+
288
+ it "allows the filter" do
289
+ expect(card.actions(filter: filter).count).to be > 0
290
+ end
291
+ end
292
+ end
293
+
294
+ context "boards" do
295
+ before do
296
+ allow(client)
297
+ .to receive(:get)
298
+ .with("/boards/abcdef123456789123456789", {})
299
+ .and_return JSON.generate(boards_details.first)
300
+ end
301
+
302
+ it "has a board" do
303
+ expect(card.board).to_not be_nil
304
+ end
305
+ end
306
+
307
+ context "cover image" do
308
+ before do
309
+ allow(client)
310
+ .to receive(:get)
311
+ .with("/attachments/abcdef123456789123456789", {})
312
+ .and_return JSON.generate(attachments_details.first)
313
+ end
314
+
315
+ it "has a cover image" do
316
+ expect(card.cover_image).to_not be_nil
317
+ end
318
+ end
319
+
320
+ context "checklists" do
321
+ before do
322
+ allow(client)
323
+ .to receive(:get)
324
+ .with("/cards/abcdef123456789123456789/checklists", { filter: :all})
325
+ .and_return checklists_payload
326
+ end
327
+
328
+ it "has a list of checklists" do
329
+ expect(card.checklists.count).to be > 0
330
+ end
331
+
332
+ it "creates a new checklist for the card" do
333
+ expect(client)
334
+ .to receive(:post)
335
+ .with("/cards/abcdef123456789123456789/checklists", name: "new checklist")
336
+
337
+ card.create_new_checklist("new checklist")
338
+ end
339
+ end
340
+
341
+ context "list" do
342
+ before do
343
+ allow(client)
344
+ .to receive(:get)
345
+ .with("/lists/abcdef123456789123456789", {})
346
+ .and_return JSON.generate(lists_details.first)
347
+ end
348
+ it 'has a list' do
349
+ expect(card.list).to_not be_nil
350
+ end
351
+
352
+ it 'can be moved to another list' do
353
+ other_list = double(id: '987654321987654321fedcba')
354
+ payload = {value: other_list.id}
355
+
356
+ expect(client)
357
+ .to receive(:put)
358
+ .with("/cards/abcdef123456789123456789/idList", payload)
359
+
360
+ card.move_to_list(other_list)
361
+ end
362
+
363
+ it 'should not be moved if new list is identical to old list' do
364
+ other_list = double(id: 'abcdef123456789123456789')
365
+ expect(client).to_not receive(:put)
366
+ card.move_to_list(other_list)
367
+ end
368
+
369
+ it "should accept a string for moving a card to list" do
370
+ payload = { value: "12345678"}
371
+
372
+ expect(client)
373
+ .to receive(:put)
374
+ .with("/cards/abcdef123456789123456789/idList", payload)
375
+
376
+ card.move_to_list("12345678")
377
+ end
378
+
379
+ it 'can be moved to another board' do
380
+ other_board = double(id: '987654321987654321fedcba')
381
+ payload = {value: other_board.id}
382
+
383
+ expect(client)
384
+ .to receive(:put)
385
+ .with("/cards/abcdef123456789123456789/idBoard", payload)
386
+
387
+ card.move_to_board(other_board)
388
+ end
389
+
390
+ it 'can be moved to a list on another board' do
391
+ other_board = double(id: '987654321987654321fedcba')
392
+ other_list = double(id: '987654321987654321aalist')
393
+ payload = {value: other_board.id, idList: other_list.id}
394
+
395
+ expect(client)
396
+ .to receive(:put)
397
+ .with("/cards/abcdef123456789123456789/idBoard", payload)
398
+
399
+ card.move_to_board(other_board, other_list)
400
+ end
401
+
402
+ it 'can be moved to a list on the same board' do
403
+ current_board = double(id: 'abcdef123456789123456789')
404
+ other_list = double(
405
+ id: '987654321987654321fedcba',
406
+ board_id: 'abcdef123456789123456789'
407
+ )
408
+ allow(List).to receive(:find).with('987654321987654321fedcba').
409
+ and_return(other_list)
410
+ allow(card).to receive(:board).and_return(current_board)
411
+ payload = {value: other_list.id}
412
+
413
+ expect(client)
414
+ .to receive(:put)
415
+ .with('/cards/abcdef123456789123456789/idList', payload)
416
+
417
+ card.move_to_list_on_any_board(other_list.id)
418
+ end
419
+
420
+ it 'can be moved to a list on another board' do
421
+ current_board = double(id: 'abcdef123456789123456789')
422
+ other_board = double(id: '987654321987654321fedcba')
423
+ other_list = double(
424
+ id: '987654321987654321aalist',
425
+ board_id: '987654321987654321fedcba'
426
+ )
427
+ allow(List).to receive(:find).with('987654321987654321aalist').
428
+ and_return(other_list)
429
+ allow(card).to receive(:board).and_return(current_board)
430
+ allow(Board).to receive(:find).with('987654321987654321fedcba').
431
+ and_return(other_board)
432
+ payload = { value: other_board.id, idList: other_list.id }
433
+
434
+ expect(client)
435
+ .to receive(:put)
436
+ .with('/cards/abcdef123456789123456789/idBoard', payload)
437
+
438
+ card.move_to_list_on_any_board(other_list.id)
439
+ end
440
+
441
+ it 'should not be moved if new board is identical with old board', focus: true do
442
+ other_board = double(id: 'abcdef123456789123456789')
443
+ expect(client).to_not receive(:put)
444
+ card.move_to_board(other_board)
445
+ end
446
+ end
447
+
448
+ context "members" do
449
+ before do
450
+ allow(client)
451
+ .to receive(:get)
452
+ .with("/boards/abcdef123456789123456789", {})
453
+ .and_return JSON.generate(boards_details.first)
454
+
455
+ allow(client)
456
+ .to receive(:get)
457
+ .with("/members/abcdef123456789123456789")
458
+ .and_return user_payload
459
+ end
460
+
461
+ it "has a list of members" do
462
+ expect(card.board).to_not be_nil
463
+ expect(card.members).to_not be_nil
464
+ end
465
+
466
+ it "allows a member to be added to a card" do
467
+ new_member = double(id: '4ee7df3ce582acdec80000b2')
468
+ payload = {
469
+ value: new_member.id
470
+ }
471
+
472
+ expect(client)
473
+ .to receive(:post)
474
+ .with("/cards/abcdef123456789123456789/members", payload)
475
+
476
+ card.add_member(new_member)
477
+ end
478
+
479
+ it "allows a member to be removed from a card" do
480
+ existing_member = double(id: '4ee7df3ce582acdec80000b2')
481
+
482
+ expect(client)
483
+ .to receive(:delete)
484
+ .with("/cards/abcdef123456789123456789/members/#{existing_member.id}")
485
+
486
+ card.remove_member(existing_member)
487
+ end
488
+ end
489
+
490
+ context "add/remove votes" do
491
+ let(:authenticated_member) { double(id: '4ee7df3ce582acdec80000b2') }
492
+
493
+ before do
494
+ allow(card)
495
+ .to receive(:me)
496
+ .and_return(authenticated_member)
497
+ end
498
+
499
+ it 'upvotes a card with the currently authenticated member' do
500
+ expect(client)
501
+ .to receive(:post)
502
+ .with("/cards/abcdef123456789123456789/membersVoted", {
503
+ value: authenticated_member.id
504
+ })
505
+
506
+ card.upvote
507
+ end
508
+
509
+ it 'returns the card even if the user has already upvoted' do
510
+ expect(client)
511
+ .to receive(:post)
512
+ .with("/cards/abcdef123456789123456789/membersVoted", {
513
+ value: authenticated_member.id
514
+ })
515
+ .and_raise(Trello::Error, 'member has already voted')
516
+ expect(card.upvote).to be_kind_of Trello::Card
517
+ end
518
+
519
+ it 'removes an upvote from a card' do
520
+ expect(client)
521
+ .to receive(:delete)
522
+ .with("/cards/abcdef123456789123456789/membersVoted/#{authenticated_member.id}")
523
+
524
+ card.remove_upvote
525
+ end
526
+
527
+ it 'returns card after remove_upvote even if the user has not previously upvoted it' do
528
+ expect(client)
529
+ .to receive(:delete)
530
+ .with("/cards/abcdef123456789123456789/membersVoted/#{authenticated_member.id}")
531
+ .and_raise(Trello::Error, 'member has not voted on the card')
532
+
533
+ card.remove_upvote
534
+ end
535
+
536
+ end
537
+
538
+ context "return all voters" do
539
+ it 'returns members that have voted for the card' do
540
+ no_voters = JSON.generate([])
541
+ expect(client)
542
+ .to receive(:get)
543
+ .with("/cards/#{card.id}/membersVoted")
544
+ .and_return(no_voters)
545
+
546
+ card.voters
547
+
548
+
549
+ voters = JSON.generate([user_details])
550
+ expect(client)
551
+ .to receive(:get)
552
+ .with("/cards/#{card.id}/membersVoted")
553
+ .and_return(voters)
554
+
555
+ expect(card.voters.first).to be_kind_of Trello::Member
556
+ end
557
+ end
558
+
559
+
560
+ context "comments" do
561
+ it "posts a comment" do
562
+ expect(client)
563
+ .to receive(:post)
564
+ .with("/cards/abcdef123456789123456789/actions/comments", { text: 'testing' })
565
+ .and_return JSON.generate(boards_details.first)
566
+
567
+ card.add_comment "testing"
568
+ end
569
+ end
570
+
571
+ context "labels" do
572
+ before do
573
+ allow(client)
574
+ .to receive(:post)
575
+ .with("/cards/ebcdef123456789123456789/labels", { value: 'green' })
576
+ .and_return "not important"
577
+
578
+ allow(client)
579
+ .to receive(:delete)
580
+ .with("/cards/ebcdef123456789123456789/labels/green")
581
+ .and_return "not important"
582
+ end
583
+
584
+ it "includes card label objects list" do
585
+ labels = card.labels
586
+ expect(labels.size).to eq(4)
587
+ expect(labels[0].color).to eq('yellow')
588
+ expect(labels[0].id).to eq('abcdef123456789123456789')
589
+ expect(labels[0].board_id).to eq('abcdef123456789123456789')
590
+ expect(labels[0].name).to eq('iOS')
591
+ expect(labels[0].uses).to eq(3)
592
+ expect(labels[1].color).to eq('purple')
593
+ expect(labels[1].id).to eq('bbcdef123456789123456789')
594
+ expect(labels[1].board_id).to eq('abcdef123456789123456789')
595
+ expect(labels[1].name).to eq('Issue or bug')
596
+ expect(labels[1].uses).to eq(1)
597
+ end
598
+
599
+ it "includes label ids list" do
600
+ label_ids = card.card_labels
601
+ expect(label_ids.size).to eq(4)
602
+ expect(label_ids[0]).to eq('abcdef123456789123456789')
603
+ expect(label_ids[1]).to eq('bbcdef123456789123456789')
604
+ expect(label_ids[2]).to eq('cbcdef123456789123456789')
605
+ expect(label_ids[3]).to eq('dbcdef123456789123456789')
606
+ end
607
+
608
+ it "can remove a label" do
609
+ expect(client).to receive(:delete).once.with("/cards/abcdef123456789123456789/idLabels/abcdef123456789123456789")
610
+ label = Label.new(label_details.first)
611
+ card.remove_label(label)
612
+ end
613
+
614
+ it "can add a label" do
615
+ expect(client).to receive(:post).once.with("/cards/abcdef123456789123456789/idLabels", {:value => "abcdef123456789123456789"})
616
+ label = Label.new(label_details.first)
617
+ card.add_label label
618
+ end
619
+
620
+ it "throws an error when trying to add a invalid label" do
621
+ allow(client).to receive(:post).with("/cards/abcdef123456789123456789/idLabels", { value: 'abcdef123456789123456789' }).
622
+ and_return "not important"
623
+ label = Label.new(label_details.first)
624
+ label.name = nil
625
+ card.add_label(label)
626
+ expect(card.errors.full_messages.to_sentence).to eq("Label is not valid.")
627
+ end
628
+
629
+ it "throws an error when trying to remove a invalid label" do
630
+ allow(client).to receive(:delete).with("/cards/abcdef123456789123456789/idLabels/abcdef123456789123456789").
631
+ and_return "not important"
632
+ label = Label.new(label_details.first)
633
+ label.name = nil
634
+ card.remove_label(label)
635
+ expect(card.errors.full_messages.to_sentence).to eq("Label is not valid.")
636
+ end
637
+ end
638
+
639
+ context "plugins" do
640
+ it "can list the existing plugins with correct fields" do
641
+ allow(client)
642
+ .to receive(:get)
643
+ .with("/boards/abcdef123456789123456789", {})
644
+ .and_return JSON.generate(boards_details.first)
645
+
646
+ allow(client)
647
+ .to receive(:get)
648
+ .with("/cards/abcdef123456789123456789/pluginData", {})
649
+ .and_return plugin_data_payload
650
+
651
+ expect(card.board).to_not be_nil
652
+ expect(card.plugin_data).to_not be_nil
653
+
654
+ first_plugin = card.plugin_data.first
655
+ expect(first_plugin.id).to eq plugin_data_details[0]["id"]
656
+ expect(first_plugin.idPlugin).to eq plugin_data_details[0]["idPlugin"]
657
+ expect(first_plugin.scope).to eq plugin_data_details[0]["scope"]
658
+ expect(first_plugin.idModel).to eq plugin_data_details[0]["idModel"]
659
+ expect(first_plugin.value).to eq JSON.parse plugin_data_details[0]["value"]
660
+ expect(first_plugin.access).to eq plugin_data_details[0]["access"]
661
+
662
+ second_plugin = card.plugin_data[1]
663
+ expect(second_plugin.id).to eq plugin_data_details[1]["id"]
664
+ expect(second_plugin.idPlugin).to eq plugin_data_details[1]["idPlugin"]
665
+ expect(second_plugin.scope).to eq plugin_data_details[1]["scope"]
666
+ expect(second_plugin.idModel).to eq plugin_data_details[1]["idModel"]
667
+ expect(second_plugin.value).to eq JSON.parse plugin_data_details[1]["value"]
668
+ expect(second_plugin.access).to eq plugin_data_details[1]["access"]
669
+
670
+ end
671
+ end
672
+
673
+ context "attachments" do
674
+ it "can add an attachment" do
675
+ f = File.new('spec/list_spec.rb', 'r')
676
+ allow(client)
677
+ .to receive(:get)
678
+ .with("/cards/abcdef123456789123456789/attachments")
679
+ .and_return attachments_payload
680
+
681
+ allow(client)
682
+ .to receive(:post)
683
+ .with("/cards/abcdef123456789123456789/attachments", { file: f, name: '' })
684
+ .and_return "not important"
685
+
686
+ card.add_attachment(f)
687
+
688
+ expect(card.errors).to be_empty
689
+ end
690
+
691
+ it "can list the existing attachments with correct fields" do
692
+ allow(client)
693
+ .to receive(:get)
694
+ .with("/boards/abcdef123456789123456789", {})
695
+ .and_return JSON.generate(boards_details.first)
696
+
697
+ allow(client)
698
+ .to receive(:get)
699
+ .with("/cards/abcdef123456789123456789/attachments")
700
+ .and_return attachments_payload
701
+
702
+ expect(card.board).to_not be_nil
703
+ expect(card.attachments).to_not be_nil
704
+
705
+ first_attachment = card.attachments.first
706
+ expect(first_attachment.id).to eq attachments_details[0]["id"]
707
+ expect(first_attachment.name).to eq attachments_details[0]["name"]
708
+ expect(first_attachment.url).to eq attachments_details[0]["url"]
709
+ expect(first_attachment.bytes).to eq attachments_details[0]["bytes"]
710
+ expect(first_attachment.member_id).to eq attachments_details[0]["idMember"]
711
+ expect(first_attachment.date).to eq Time.parse(attachments_details[0]["date"])
712
+ expect(first_attachment.is_upload).to eq attachments_details[0]["isUpload"]
713
+ expect(first_attachment.mime_type).to eq attachments_details[0]["mimeType"]
714
+ expect(first_attachment.previews).to eq attachments_details[0]["previews"]
715
+
716
+ second_attachment = card.attachments[1]
717
+ expect(second_attachment.previews).to eq nil
718
+ end
719
+
720
+ it "can remove an attachment" do
721
+ allow(client)
722
+ .to receive(:delete)
723
+ .with("/cards/abcdef123456789123456789/attachments/abcdef123456789123456789")
724
+ .and_return "not important"
725
+
726
+ allow(client)
727
+ .to receive(:get)
728
+ .with("/cards/abcdef123456789123456789/attachments")
729
+ .and_return attachments_payload
730
+
731
+ card.remove_attachment(card.attachments.first)
732
+ expect(card.errors).to be_empty
733
+ end
734
+ end
735
+
736
+ describe "#closed?" do
737
+ it "returns the closed attribute" do
738
+ expect(card).to_not be_closed
739
+ end
740
+ end
741
+
742
+ describe "#close" do
743
+ it "updates the close attribute to true" do
744
+ card.close
745
+ expect(card).to be_closed
746
+ end
747
+ end
748
+
749
+ describe "#close!" do
750
+ it "updates the close attribute to true and saves the list" do
751
+ payload = { closed: true }
752
+
753
+ expect(client)
754
+ .to receive(:put)
755
+ .once
756
+ .with("/cards/abcdef123456789123456789", payload)
757
+
758
+ card.close!
759
+ end
760
+ end
761
+
762
+ describe "can mark due_complete" do
763
+ it "updates the due completed attribute to true" do
764
+ due_date = Time.now
765
+
766
+ payload = {
767
+ due: due_date,
768
+ }
769
+
770
+ expect(client)
771
+ .to receive(:put)
772
+ .once
773
+ .with("/cards/abcdef123456789123456789", payload)
774
+
775
+ card.due = due_date
776
+ card.save
777
+
778
+ expect(card.due).to_not be_nil
779
+
780
+ payload = {
781
+ dueComplete: true
782
+ }
783
+
784
+ expect(client)
785
+ .to receive(:put)
786
+ .once
787
+ .with("/cards/abcdef123456789123456789", payload)
788
+
789
+ card.due_complete = true
790
+ card.save
791
+
792
+ expect(card.due_complete).to be true
793
+ end
794
+ end
795
+
796
+ describe "#update_fields" do
797
+ it "does not set any fields when the fields argument is empty" do
798
+ expected = cards_details.first
799
+
800
+ card = Card.new(expected)
801
+ card.client = client
802
+
803
+ card.update_fields({})
804
+
805
+ expected.each do |key, value|
806
+ if card.respond_to?(key) && key != 'labels'
807
+ expect(card.send(key)).to eq value
808
+ end
809
+
810
+ expect(card.labels).to eq expected['labels'].map { |lbl| Trello::Label.new(lbl) }
811
+ expect(card.short_id).to eq expected['idShort']
812
+ expect(card.short_url).to eq expected['shortUrl']
813
+ expect(card.board_id).to eq expected['idBoard']
814
+ expect(card.member_ids).to eq expected['idMembers']
815
+ expect(card.cover_image_id).to eq expected['idAttachmentCover']
816
+ expect(card.list_id).to eq expected['idList']
817
+ expect(card.card_labels).to eq expected['idLabels']
818
+ end
819
+ end
820
+ end
821
+ end
822
+ end