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.
- checksums.yaml +7 -0
- data/README.md +182 -0
- data/lib/trello.rb +163 -0
- data/lib/trello/action.rb +68 -0
- data/lib/trello/association.rb +14 -0
- data/lib/trello/association_proxy.rb +42 -0
- data/lib/trello/attachment.rb +40 -0
- data/lib/trello/authorization.rb +187 -0
- data/lib/trello/basic_data.rb +132 -0
- data/lib/trello/board.rb +211 -0
- data/lib/trello/card.rb +467 -0
- data/lib/trello/checklist.rb +143 -0
- data/lib/trello/client.rb +120 -0
- data/lib/trello/comment.rb +62 -0
- data/lib/trello/configuration.rb +68 -0
- data/lib/trello/core_ext/array.rb +6 -0
- data/lib/trello/core_ext/hash.rb +6 -0
- data/lib/trello/core_ext/string.rb +6 -0
- data/lib/trello/cover_image.rb +8 -0
- data/lib/trello/has_actions.rb +9 -0
- data/lib/trello/item.rb +37 -0
- data/lib/trello/item_state.rb +30 -0
- data/lib/trello/json_utils.rb +64 -0
- data/lib/trello/label.rb +108 -0
- data/lib/trello/label_name.rb +31 -0
- data/lib/trello/list.rb +114 -0
- data/lib/trello/member.rb +112 -0
- data/lib/trello/multi_association.rb +12 -0
- data/lib/trello/net.rb +39 -0
- data/lib/trello/notification.rb +61 -0
- data/lib/trello/organization.rb +68 -0
- data/lib/trello/plugin_datum.rb +34 -0
- data/lib/trello/token.rb +37 -0
- data/lib/trello/webhook.rb +103 -0
- data/spec/action_spec.rb +149 -0
- data/spec/array_spec.rb +13 -0
- data/spec/association_spec.rb +26 -0
- data/spec/basic_auth_policy_spec.rb +51 -0
- data/spec/board_spec.rb +442 -0
- data/spec/card_spec.rb +822 -0
- data/spec/checklist_spec.rb +296 -0
- data/spec/client_spec.rb +257 -0
- data/spec/configuration_spec.rb +95 -0
- data/spec/hash_spec.rb +15 -0
- data/spec/integration/how_to_authorize_spec.rb +53 -0
- data/spec/integration/how_to_use_boards_spec.rb +48 -0
- data/spec/integration/integration_test.rb +40 -0
- data/spec/item_spec.rb +75 -0
- data/spec/json_utils_spec.rb +73 -0
- data/spec/label_spec.rb +205 -0
- data/spec/list_spec.rb +253 -0
- data/spec/member_spec.rb +159 -0
- data/spec/notification_spec.rb +143 -0
- data/spec/oauth_policy_spec.rb +160 -0
- data/spec/organization_spec.rb +71 -0
- data/spec/spec_helper.rb +435 -0
- data/spec/string_spec.rb +55 -0
- data/spec/token_spec.rb +89 -0
- data/spec/trello_spec.rb +134 -0
- data/spec/webhook_spec.rb +130 -0
- metadata +200 -0
data/lib/trello/net.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Trello
|
2
|
+
Request = Struct.new "Request", :verb, :uri, :headers, :body
|
3
|
+
Response = Struct.new "Response", :code, :headers, :body
|
4
|
+
|
5
|
+
class TInternet
|
6
|
+
class << self
|
7
|
+
require "rest_client"
|
8
|
+
|
9
|
+
def execute(request)
|
10
|
+
try_execute request
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def try_execute(request)
|
16
|
+
begin
|
17
|
+
if request
|
18
|
+
result = execute_core request
|
19
|
+
Response.new(200, {}, result)
|
20
|
+
end
|
21
|
+
rescue RestClient::Exception => e
|
22
|
+
raise if !e.respond_to?(:http_code) || e.http_code.nil?
|
23
|
+
Response.new(e.http_code, {}, e.http_body)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_core(request)
|
28
|
+
RestClient.proxy = ENV['HTTP_PROXY'] if ENV['HTTP_PROXY']
|
29
|
+
RestClient::Request.execute(
|
30
|
+
method: request.verb,
|
31
|
+
url: request.uri.to_s,
|
32
|
+
headers: request.headers,
|
33
|
+
payload: request.body,
|
34
|
+
timeout: 10
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Trello
|
2
|
+
|
3
|
+
# @!attribute [r] id
|
4
|
+
# @return [String]
|
5
|
+
# @!attribute [rw] unread
|
6
|
+
# @return [Boolean]
|
7
|
+
# @!attribute [r] type
|
8
|
+
# @return [Object]
|
9
|
+
# @!attribute [r] date
|
10
|
+
# @return [Datetime]
|
11
|
+
# @!attribute [rw] data
|
12
|
+
# @return [Object]
|
13
|
+
# @!attribute [r] member_creator_id,
|
14
|
+
# @return [String]
|
15
|
+
class Notification < BasicData
|
16
|
+
register_attributes :id, :unread, :type, :date, :data, :member_creator_id,
|
17
|
+
read_only: [ :id, :unread, :type, :date, :member_creator_id ]
|
18
|
+
validates_presence_of :id, :type, :date, :member_creator_id
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# Locate a notification by its id
|
22
|
+
def find(id, params = {})
|
23
|
+
client.find(:notification, id, params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_fields(fields)
|
28
|
+
attributes[:id] = fields['id'] || attributes[:id]
|
29
|
+
attributes[:unread] = fields['unread'] if fields.has_key?('unread')
|
30
|
+
attributes[:type] = fields['type'] || attributes[:type]
|
31
|
+
attributes[:date] = fields['date'] || attributes[:date]
|
32
|
+
attributes[:data] = fields['data'] || attributes[:data]
|
33
|
+
attributes[:member_creator_id] = fields['idMemberCreator'] || attributes[:member_creator_id]
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
alias :unread? :unread
|
38
|
+
|
39
|
+
one :member_creator, path: :members, via: Member, using: :member_creator_id
|
40
|
+
|
41
|
+
def board
|
42
|
+
Board.from_response client.get("/notifications/#{id}/board")
|
43
|
+
end
|
44
|
+
|
45
|
+
def list
|
46
|
+
List.from_response client.get("/notifications/#{id}/list")
|
47
|
+
end
|
48
|
+
|
49
|
+
def card
|
50
|
+
Card.from_response client.get("/notifications/#{id}/card")
|
51
|
+
end
|
52
|
+
|
53
|
+
def member
|
54
|
+
Member.from_response client.get("/notifications/#{id}/member")
|
55
|
+
end
|
56
|
+
|
57
|
+
def organization
|
58
|
+
Organization.from_response client.get("/notifications/#{id}/organization")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Trello
|
2
|
+
# Organizations are useful for linking members together.
|
3
|
+
#
|
4
|
+
# @!attribute [r] id
|
5
|
+
# @return [String]
|
6
|
+
# @!attribute [r] name
|
7
|
+
# @return [String]
|
8
|
+
# @!attribute [r] display_name
|
9
|
+
# @return [String]
|
10
|
+
# @!attribute [r] description
|
11
|
+
# @return [String]
|
12
|
+
# @!attribute [r] url
|
13
|
+
# @return [String]
|
14
|
+
class Organization < BasicData
|
15
|
+
register_attributes :id, :name, :display_name, :description, :url, :invited,
|
16
|
+
:website, :logo_hash, :billable_member_count, :active_billable_member_count,
|
17
|
+
:memberships,
|
18
|
+
readonly: [ :id, :name, :display_name, :description, :url, :invited,
|
19
|
+
:website, :logo_hash, :billable_member_count, :active_billable_member_count,
|
20
|
+
:memberships ]
|
21
|
+
validates_presence_of :id, :name
|
22
|
+
|
23
|
+
include HasActions
|
24
|
+
|
25
|
+
class << self
|
26
|
+
# Find an organization by its id.
|
27
|
+
def find(id, params = {})
|
28
|
+
client.find(:organization, id, params)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Update the fields of an organization.
|
33
|
+
#
|
34
|
+
# Supply a hash of string keyed data retrieved from the Trello API representing
|
35
|
+
# an Organization.
|
36
|
+
def update_fields(fields)
|
37
|
+
attributes[:id] = fields['id'] || attributes[:id]
|
38
|
+
attributes[:name] = fields['name'] || attributes[:name]
|
39
|
+
attributes[:display_name] = fields['displayName'] || attributes[:display_name]
|
40
|
+
attributes[:description] = fields['desc'] || attributes[:description]
|
41
|
+
attributes[:url] = fields['url'] || attributes[:url]
|
42
|
+
attributes[:invited] = fields['invited'] if fields.has_key?('invited')
|
43
|
+
attributes[:website] = fields['website'] || attributes[:website]
|
44
|
+
attributes[:logo_hash] = fields['logoHash'] || attributes[:logo_hash]
|
45
|
+
attributes[:billable_member_count] = fields['billableMemberCount'] || attributes[:billable_member_count]
|
46
|
+
attributes[:active_billable_member_count] = fields['activeBillableMemberCount'] || attributes[:active_billable_member_count]
|
47
|
+
attributes[:memberships] = fields['memberships'] || attributes[:memberships]
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns a list of boards under this organization.
|
52
|
+
def boards
|
53
|
+
boards = Board.from_response client.get("/organizations/#{id}/boards/all")
|
54
|
+
MultiAssociation.new(self, boards).proxy
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns an array of members associated with the organization.
|
58
|
+
def members(params = {})
|
59
|
+
members = Member.from_response client.get("/organizations/#{id}/members/all", params)
|
60
|
+
MultiAssociation.new(self, members).proxy
|
61
|
+
end
|
62
|
+
|
63
|
+
# :nodoc:
|
64
|
+
def request_prefix
|
65
|
+
"/organizations/#{id}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Trello
|
2
|
+
# A file or url that is linked to a Trello card
|
3
|
+
#
|
4
|
+
# @!attribute id
|
5
|
+
# @return [String]
|
6
|
+
# @!attribute idPlugin
|
7
|
+
# @return [String]
|
8
|
+
# @!attribute scope
|
9
|
+
# @return [String]
|
10
|
+
# @!attribute idModel
|
11
|
+
# @return [String]
|
12
|
+
# @!attribute value
|
13
|
+
# @return [String]
|
14
|
+
# @!attribute access
|
15
|
+
# @return [String]
|
16
|
+
class PluginDatum < BasicData
|
17
|
+
# Update the fields of a plugin.
|
18
|
+
register_attributes :id, :idPlugin, :scope, :idModel, :value, :access
|
19
|
+
|
20
|
+
|
21
|
+
# Supply a hash of stringkeyed data retrieved from the Trello API representing
|
22
|
+
# an attachment.
|
23
|
+
def update_fields(fields)
|
24
|
+
attributes[:id] = fields['id'] || attributes[:id]
|
25
|
+
attributes[:idPlugin] = fields['idPlugin'] || attributes[:idPlugin]
|
26
|
+
attributes[:scope] = fields['scope'] || attributes[:scope]
|
27
|
+
attributes[:value] = JSON.parse(fields['value']).presence if fields.has_key?('value')
|
28
|
+
attributes[:idModel] = fields['idModel'] || attributes[:idModel]
|
29
|
+
attributes[:access] = fields['access'] || attributes[:access]
|
30
|
+
self
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/trello/token.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Trello
|
2
|
+
|
3
|
+
# @!attribute [r] id
|
4
|
+
# @return [String]
|
5
|
+
# @!attribute [r] member_id
|
6
|
+
# @return [String]
|
7
|
+
# @!attribute [r] created_at
|
8
|
+
# @return [Datetime]
|
9
|
+
# @!attribute [r] permissions
|
10
|
+
# @return [Object]
|
11
|
+
# @!attribute [r] webhooks
|
12
|
+
# @return [Object]
|
13
|
+
class Token < BasicData
|
14
|
+
register_attributes :id, :member_id, :created_at, :permissions, :webhooks,
|
15
|
+
readonly: [ :id, :member_id, :created_at, :permissions, :webhooks ]
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Finds a token
|
19
|
+
def find(token, params = {webhooks: true})
|
20
|
+
client.find(:token, token, params)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# :nodoc:
|
25
|
+
def update_fields(fields)
|
26
|
+
attributes[:id] = fields['id'] || attributes[:id]
|
27
|
+
attributes[:member_id] = fields['idMember'] || attributes[:member_id]
|
28
|
+
attributes[:created_at] = Time.iso8601(fields['dateCreated']) rescue nil if fields.has_key?('dateCreated')
|
29
|
+
attributes[:permissions] = fields['permissions'] || attributes[:permissions]
|
30
|
+
attributes[:permissions] ||= {}
|
31
|
+
attributes[:webhooks] = fields['webhooks'] || attributes[:webhooks]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns a reference to the user who authorized the token.
|
35
|
+
one :member, path: :members, using: :member_id
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Trello
|
2
|
+
# A webhook is a URL called each time a specified model is updated
|
3
|
+
#
|
4
|
+
# @!attribute [r] id
|
5
|
+
# @return [String]
|
6
|
+
# @!attribute [r] description
|
7
|
+
# @return [String]
|
8
|
+
# @!attribute [r] id_model
|
9
|
+
# @return [String] A 24-character hex string
|
10
|
+
# @!attribute [r] callback_url
|
11
|
+
# @return [String]
|
12
|
+
# @!attribute [r] active
|
13
|
+
# @return [Boolean]
|
14
|
+
class Webhook < BasicData
|
15
|
+
register_attributes :id, :description, :id_model, :callback_url, :active,
|
16
|
+
readonly: [ :id ]
|
17
|
+
validates_presence_of :id, :id_model, :callback_url
|
18
|
+
validates_length_of :description, in: 1..16384
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# Find a specific webhook by its ID.
|
22
|
+
#
|
23
|
+
# @raise [Trello::Error] if a Webhook with the given ID can't be found.
|
24
|
+
# @return [Trello::Webhook] the Webhook with the given ID.
|
25
|
+
def find(id, params = {})
|
26
|
+
client.find(:webhook, id, params)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Create a new webhook and save it to Trello.
|
30
|
+
#
|
31
|
+
# @param [Hash] options
|
32
|
+
#
|
33
|
+
# @option options [String] :description (optional) A string with a length from 0 to 16384
|
34
|
+
# @option options [String] :callback_url (required) A valid URL that is
|
35
|
+
# reachable with a HEAD request
|
36
|
+
# @option options [String] :id_model (required) id of the model that should be hooked
|
37
|
+
#
|
38
|
+
# @raise [Trello::Error] if the Webhook could not be created.
|
39
|
+
#
|
40
|
+
# @return [Trello::Webhook]
|
41
|
+
def create(options)
|
42
|
+
client.create(:webhook,
|
43
|
+
'description' => options[:description],
|
44
|
+
'idModel' => options[:id_model],
|
45
|
+
'callbackURL' => options[:callback_url])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Trello::Webhook] self
|
50
|
+
def update_fields(fields)
|
51
|
+
attributes[:id] = fields['id'] || attributes[:id]
|
52
|
+
attributes[:description] = fields['description'] || fields[:description] || attributes[:description]
|
53
|
+
attributes[:id_model] = fields['idModel'] || fields[:id_model] || attributes[:id_model]
|
54
|
+
attributes[:callback_url] = fields['callbackURL'] || fields[:callback_url] || attributes[:callback_url]
|
55
|
+
attributes[:active] = fields['active'] if fields.has_key?('active')
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Save the webhook.
|
60
|
+
#
|
61
|
+
# @raise [Trello::Error] if the Webhook could not be saved.
|
62
|
+
#
|
63
|
+
# @return [String] the JSON representation of the saved webhook.
|
64
|
+
def save
|
65
|
+
# If we have an id, just update our fields.
|
66
|
+
return update! if id
|
67
|
+
|
68
|
+
from_response client.post("/webhooks", {
|
69
|
+
description: description,
|
70
|
+
idModel: id_model,
|
71
|
+
callbackURL: callback_url
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
# Update the webhook.
|
76
|
+
#
|
77
|
+
# @raise [Trello::Error] if the Webhook could not be saved.
|
78
|
+
#
|
79
|
+
# @return [String] the JSON representation of the updated webhook.
|
80
|
+
def update!
|
81
|
+
client.put("/webhooks/#{id}", {
|
82
|
+
description: description,
|
83
|
+
idModel: id_model,
|
84
|
+
callbackURL: callback_url,
|
85
|
+
active: active
|
86
|
+
})
|
87
|
+
end
|
88
|
+
|
89
|
+
# Delete this webhook
|
90
|
+
#
|
91
|
+
# @return [String] the JSON response from the Trello API
|
92
|
+
def delete
|
93
|
+
client.delete("/webhooks/#{id}")
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check if the webhook is activated
|
97
|
+
#
|
98
|
+
# @return [Boolean]
|
99
|
+
def activated?
|
100
|
+
active
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/spec/action_spec.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Trello
|
4
|
+
describe Action do
|
5
|
+
include Helpers
|
6
|
+
|
7
|
+
let(:client) { Client.new }
|
8
|
+
let(:action) { client.find(:action, '4ee2482134a81a757a08af47') }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(client)
|
12
|
+
.to receive(:get)
|
13
|
+
.with('/actions/4ee2482134a81a757a08af47', {})
|
14
|
+
.and_return JSON.generate(actions_details.first)
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'finding' do
|
18
|
+
let(:client) { Trello.client }
|
19
|
+
|
20
|
+
it 'delegates to Trello.client#find' do
|
21
|
+
expect(client)
|
22
|
+
.to receive(:find)
|
23
|
+
.with(:action, '4ee2482134a81a757a08af47', {})
|
24
|
+
|
25
|
+
Action.find('4ee2482134a81a757a08af47')
|
26
|
+
end
|
27
|
+
|
28
|
+
it do
|
29
|
+
expect(Action.find('4ee2482134a81a757a08af47')).to eq(action)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'search' do
|
34
|
+
let(:client) { Trello.client }
|
35
|
+
let(:payload) { JSON.generate({ "cards" => cards_details }) }
|
36
|
+
|
37
|
+
it "searches and get back a card object" do
|
38
|
+
expect(client)
|
39
|
+
.to receive(:get)
|
40
|
+
.with("/search/", { query: "something"})
|
41
|
+
.and_return payload
|
42
|
+
|
43
|
+
expect(Action.search("something"))
|
44
|
+
.to eq({ "cards" => cards_details.jsoned_into(Card) })
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'fields' do
|
49
|
+
let(:detail) { actions_details.first }
|
50
|
+
|
51
|
+
it 'gets its id' do
|
52
|
+
expect(action.id).to eq detail['id']
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'gets its type' do
|
56
|
+
expect(action.type).to eq detail['type']
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'has the same data' do
|
60
|
+
expect(action.data).to eq detail['data']
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'gets the date' do
|
64
|
+
expect(action.date.utc.iso8601).to eq detail['date']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'boards' do
|
69
|
+
let(:payload) { JSON.generate(boards_details.first) }
|
70
|
+
|
71
|
+
before do
|
72
|
+
allow(client)
|
73
|
+
.to receive(:get)
|
74
|
+
.with('/actions/4ee2482134a81a757a08af47/board')
|
75
|
+
.and_return payload
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'has a board' do
|
79
|
+
expect(action.board).to_not be_nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
context 'card' do
|
85
|
+
let(:payload) { JSON.generate(cards_details.first) }
|
86
|
+
|
87
|
+
before do
|
88
|
+
allow(client)
|
89
|
+
.to receive(:get)
|
90
|
+
.with('/actions/4ee2482134a81a757a08af47/card')
|
91
|
+
.and_return payload
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'has a card' do
|
95
|
+
expect(action.card).to_not be_nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'list' do
|
100
|
+
let(:payload) { JSON.generate(lists_details.first) }
|
101
|
+
|
102
|
+
before do
|
103
|
+
allow(client)
|
104
|
+
.to receive(:get)
|
105
|
+
.with('/actions/4ee2482134a81a757a08af47/list')
|
106
|
+
.and_return payload
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'has a list of lists' do
|
110
|
+
expect(action.list).to_not be_nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'member creator' do
|
115
|
+
|
116
|
+
before do
|
117
|
+
allow(client)
|
118
|
+
.to receive(:get)
|
119
|
+
.with('/members/abcdef123456789123456789', {})
|
120
|
+
.and_return user_payload
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'knows its member creator' do
|
124
|
+
expect(action.member_creator).to_not be_nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#update_fields" do
|
129
|
+
it "does not set any fields when the fields argument is empty" do
|
130
|
+
expected = {
|
131
|
+
'id' => 'id',
|
132
|
+
'type' => 'type',
|
133
|
+
'data' => 'data',
|
134
|
+
'idMemberCreator' => 'member_creator_id',
|
135
|
+
'member' => 'member_participant'
|
136
|
+
}
|
137
|
+
|
138
|
+
action = Action.new(expected)
|
139
|
+
action.client = client
|
140
|
+
|
141
|
+
action.update_fields({})
|
142
|
+
|
143
|
+
expected.each do |key, value|
|
144
|
+
expect(action.send(value)).to eq expected[key]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|