ruby-trello-czuger 2.0.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.
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