cuprum-rails 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +145 -0
- data/DEVELOPMENT.md +20 -0
- data/README.md +356 -63
- data/lib/cuprum/rails/action.rb +32 -16
- data/lib/cuprum/rails/actions/create.rb +62 -15
- data/lib/cuprum/rails/actions/destroy.rb +23 -7
- data/lib/cuprum/rails/actions/edit.rb +23 -7
- data/lib/cuprum/rails/actions/index.rb +30 -10
- data/lib/cuprum/rails/actions/middleware/associations/cache.rb +112 -0
- data/lib/cuprum/rails/actions/middleware/associations/find.rb +23 -0
- data/lib/cuprum/rails/actions/middleware/associations/parent.rb +70 -0
- data/lib/cuprum/rails/actions/middleware/associations/query.rb +140 -0
- data/lib/cuprum/rails/actions/middleware/associations.rb +12 -0
- data/lib/cuprum/rails/actions/middleware/log_request.rb +126 -0
- data/lib/cuprum/rails/actions/middleware/log_result.rb +51 -0
- data/lib/cuprum/rails/actions/middleware/resources/find.rb +44 -0
- data/lib/cuprum/rails/actions/middleware/resources/query.rb +91 -0
- data/lib/cuprum/rails/actions/middleware/resources.rb +11 -0
- data/lib/cuprum/rails/actions/middleware.rb +13 -0
- data/lib/cuprum/rails/actions/new.rb +16 -4
- data/lib/cuprum/rails/actions/parameter_validation.rb +60 -0
- data/lib/cuprum/rails/actions/resource_action.rb +119 -42
- data/lib/cuprum/rails/actions/show.rb +23 -7
- data/lib/cuprum/rails/actions/update.rb +70 -22
- data/lib/cuprum/rails/actions.rb +11 -7
- data/lib/cuprum/rails/collection.rb +27 -47
- data/lib/cuprum/rails/command.rb +3 -1
- data/lib/cuprum/rails/commands/destroy_one.rb +10 -6
- data/lib/cuprum/rails/commands/find_many.rb +8 -1
- data/lib/cuprum/rails/commands/find_matching.rb +1 -1
- data/lib/cuprum/rails/commands/find_one.rb +8 -0
- data/lib/cuprum/rails/commands/insert_one.rb +17 -6
- data/lib/cuprum/rails/commands/update_one.rb +16 -5
- data/lib/cuprum/rails/constraints/parameters_contract.rb +14 -0
- data/lib/cuprum/rails/constraints.rb +10 -0
- data/lib/cuprum/rails/controller.rb +12 -2
- data/lib/cuprum/rails/controllers/action.rb +100 -0
- data/lib/cuprum/rails/controllers/class_methods/actions.rb +33 -7
- data/lib/cuprum/rails/controllers/class_methods/configuration.rb +36 -0
- data/lib/cuprum/rails/controllers/class_methods/middleware.rb +88 -0
- data/lib/cuprum/rails/controllers/class_methods/validations.rb +2 -2
- data/lib/cuprum/rails/controllers/configuration.rb +41 -1
- data/lib/cuprum/rails/controllers/middleware.rb +59 -0
- data/lib/cuprum/rails/controllers.rb +2 -0
- data/lib/cuprum/rails/errors/invalid_parameters.rb +55 -0
- data/lib/cuprum/rails/errors/invalid_statement.rb +11 -0
- data/lib/cuprum/rails/errors/missing_parameter.rb +42 -0
- data/lib/cuprum/rails/errors/resource_error.rb +46 -0
- data/lib/cuprum/rails/errors.rb +6 -1
- data/lib/cuprum/rails/map_errors.rb +29 -1
- data/lib/cuprum/rails/query.rb +1 -1
- data/lib/cuprum/rails/repository.rb +12 -25
- data/lib/cuprum/rails/request.rb +149 -60
- data/lib/cuprum/rails/resource.rb +119 -85
- data/lib/cuprum/rails/responders/base_responder.rb +78 -0
- data/lib/cuprum/rails/responders/html/plural_resource.rb +9 -39
- data/lib/cuprum/rails/responders/html/rendering.rb +81 -0
- data/lib/cuprum/rails/responders/html/resource.rb +107 -0
- data/lib/cuprum/rails/responders/html/singular_resource.rb +9 -38
- data/lib/cuprum/rails/responders/html.rb +2 -0
- data/lib/cuprum/rails/responders/html_responder.rb +8 -52
- data/lib/cuprum/rails/responders/json/resource.rb +3 -3
- data/lib/cuprum/rails/responders/json_responder.rb +31 -16
- data/lib/cuprum/rails/responders/matching.rb +29 -27
- data/lib/cuprum/rails/responders/serialization.rb +11 -9
- data/lib/cuprum/rails/responders.rb +1 -0
- data/lib/cuprum/rails/responses/head_response.rb +24 -0
- data/lib/cuprum/rails/responses/html/redirect_back_response.rb +55 -0
- data/lib/cuprum/rails/responses/html/redirect_response.rb +19 -4
- data/lib/cuprum/rails/responses/html/render_response.rb +17 -5
- data/lib/cuprum/rails/responses/html.rb +6 -2
- data/lib/cuprum/rails/responses.rb +1 -0
- data/lib/cuprum/rails/result.rb +36 -0
- data/lib/cuprum/rails/routes.rb +36 -23
- data/lib/cuprum/rails/rspec/contract_helpers.rb +57 -0
- data/lib/cuprum/rails/rspec/contracts/action_contracts.rb +754 -0
- data/lib/cuprum/rails/rspec/contracts/actions/create_contracts.rb +289 -0
- data/lib/cuprum/rails/rspec/contracts/actions/destroy_contracts.rb +164 -0
- data/lib/cuprum/rails/rspec/contracts/actions/edit_contracts.rb +73 -0
- data/lib/cuprum/rails/rspec/contracts/actions/index_contracts.rb +108 -0
- data/lib/cuprum/rails/rspec/contracts/actions/new_contracts.rb +111 -0
- data/lib/cuprum/rails/rspec/contracts/actions/show_contracts.rb +72 -0
- data/lib/cuprum/rails/rspec/contracts/actions/update_contracts.rb +263 -0
- data/lib/cuprum/rails/rspec/contracts/actions.rb +8 -0
- data/lib/cuprum/rails/rspec/contracts/command_contracts.rb +479 -0
- data/lib/cuprum/rails/rspec/contracts/responder_contracts.rb +232 -0
- data/lib/cuprum/rails/rspec/contracts/routes_contracts.rb +363 -0
- data/lib/cuprum/rails/rspec/contracts/serializers_contracts.rb +70 -0
- data/lib/cuprum/rails/rspec/contracts.rb +8 -0
- data/lib/cuprum/rails/rspec/matchers/be_a_result_matcher.rb +64 -0
- data/lib/cuprum/rails/rspec/matchers.rb +41 -0
- data/lib/cuprum/rails/serializers/base_serializer.rb +60 -0
- data/lib/cuprum/rails/serializers/context.rb +84 -0
- data/lib/cuprum/rails/serializers/json/active_record_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/array_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/attributes_serializer.rb +95 -172
- data/lib/cuprum/rails/serializers/json/error_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/hash_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/identity_serializer.rb +3 -3
- data/lib/cuprum/rails/serializers/json/properties_serializer.rb +252 -0
- data/lib/cuprum/rails/serializers/json.rb +2 -1
- data/lib/cuprum/rails/serializers.rb +3 -1
- data/lib/cuprum/rails/version.rb +1 -1
- data/lib/cuprum/rails.rb +19 -16
- metadata +73 -131
- data/lib/cuprum/rails/controller_action.rb +0 -121
- data/lib/cuprum/rails/errors/missing_parameters.rb +0 -33
- data/lib/cuprum/rails/errors/missing_primary_key.rb +0 -46
- data/lib/cuprum/rails/errors/undefined_permitted_attributes.rb +0 -34
- data/lib/cuprum/rails/rspec/command_contract.rb +0 -460
- data/lib/cuprum/rails/rspec/define_route_contract.rb +0 -84
- data/lib/cuprum/rails/serializers/json/serializer.rb +0 -66
@@ -0,0 +1,289 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/sleeping_king_studios/contract'
|
4
|
+
|
5
|
+
require 'cuprum/rails/rspec/contract_helpers'
|
6
|
+
require 'cuprum/rails/rspec/contracts/action_contracts'
|
7
|
+
require 'cuprum/rails/rspec/contracts/actions'
|
8
|
+
|
9
|
+
module Cuprum::Rails::RSpec::Contracts::Actions
|
10
|
+
# Namespace for RSpec create contracts, which validate create implementations.
|
11
|
+
module CreateContracts
|
12
|
+
# Contract asserting the action implements the create action interface.
|
13
|
+
module ShouldBeACreateActionContract
|
14
|
+
extend RSpec::SleepingKingStudios::Contract
|
15
|
+
|
16
|
+
# @method apply(example_group, invalid_attributes:, valid_attributes:, **options)
|
17
|
+
# Adds the contract to the example group.
|
18
|
+
#
|
19
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
20
|
+
# which the contract is applied.
|
21
|
+
# @param invalid_attributes [Hash<String>] A set of attributes that will
|
22
|
+
# fail validation.
|
23
|
+
# @param valid_attributes [Hash<String>] A set of attributes that will
|
24
|
+
# pass validation.
|
25
|
+
#
|
26
|
+
# @option options [Hash<String>] duplicate_attributes A set of
|
27
|
+
# attributes for a duplicate entity.
|
28
|
+
# @option options [#to_proc] examples_on_failure Extra examples to run
|
29
|
+
# for the failing cases.
|
30
|
+
# @option options [#to_proc] examples_on_success Extra examples to run
|
31
|
+
# for the passing case.
|
32
|
+
# @option options [Hash<String>] expected_attributes The expected
|
33
|
+
# attributes for both a failed validation and a returned entity.
|
34
|
+
# @option options [Hash<String>] expected_attributes_on_failure The
|
35
|
+
# expected attributes for a failed validation. Defaults to the value
|
36
|
+
# of invalid_attributes.
|
37
|
+
# @option options [Hash<String>] expected_attributes_on_success The
|
38
|
+
# expected attributes for the returned object. Defaults to the value
|
39
|
+
# of valid_attributes.
|
40
|
+
# @option options [Hash<String>] expected_value_on_success The expected
|
41
|
+
# value for the passing result. Defaults to a Hash with the created
|
42
|
+
# entity.
|
43
|
+
# @option options [Hash<String>] params The parameters used to build the
|
44
|
+
# request. Defaults to the given attributes.
|
45
|
+
#
|
46
|
+
# @yield Additional examples to run for the passing case.
|
47
|
+
|
48
|
+
contract do |invalid_attributes:, valid_attributes:, **options, &block|
|
49
|
+
include Cuprum::Rails::RSpec::Contracts::ActionContracts
|
50
|
+
include Cuprum::Rails::RSpec::Contracts::Actions::CreateContracts
|
51
|
+
|
52
|
+
options = options.merge(valid_attributes: valid_attributes)
|
53
|
+
configured_params = lambda do
|
54
|
+
attributes =
|
55
|
+
Cuprum::Rails::RSpec::ContractHelpers.option_with_default(
|
56
|
+
valid_attributes,
|
57
|
+
context: self
|
58
|
+
)
|
59
|
+
|
60
|
+
Cuprum::Rails::RSpec::ContractHelpers.option_with_default(
|
61
|
+
options[:params],
|
62
|
+
context: self,
|
63
|
+
default: {
|
64
|
+
configured_resource.singular_name => attributes
|
65
|
+
}
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
# :nocov:
|
70
|
+
if options[:examples_on_success] && block
|
71
|
+
raise ArgumentError, 'provide either :examples_on_success or a block'
|
72
|
+
elsif block
|
73
|
+
options[:examples_on_success] = block
|
74
|
+
end
|
75
|
+
# :nocov:
|
76
|
+
|
77
|
+
should_not_create_an_entity = lambda do
|
78
|
+
it 'should not create an entity' do
|
79
|
+
expect { call_action }
|
80
|
+
.not_to change(configured_resource.entity_class, :count)
|
81
|
+
end
|
82
|
+
|
83
|
+
# :nocov:
|
84
|
+
if options[:examples_on_failure]
|
85
|
+
instance_exec(&options[:examples_on_failure])
|
86
|
+
end
|
87
|
+
# :nocov:
|
88
|
+
end
|
89
|
+
|
90
|
+
include_contract 'should be a resource action',
|
91
|
+
require_permitted_attributes: true
|
92
|
+
|
93
|
+
include_contract(
|
94
|
+
'should require parameters',
|
95
|
+
params: configured_params,
|
96
|
+
&should_not_create_an_entity
|
97
|
+
)
|
98
|
+
|
99
|
+
include_contract(
|
100
|
+
'should validate attributes',
|
101
|
+
expected_attributes: options.fetch(
|
102
|
+
:expected_attributes,
|
103
|
+
options[:expected_attributes_on_failure]
|
104
|
+
),
|
105
|
+
invalid_attributes: invalid_attributes,
|
106
|
+
params: configured_params,
|
107
|
+
&should_not_create_an_entity
|
108
|
+
)
|
109
|
+
|
110
|
+
if options[:duplicate_attributes]
|
111
|
+
include_contract(
|
112
|
+
'should not create a duplicate entity',
|
113
|
+
params: configured_params,
|
114
|
+
valid_attributes: options[:duplicate_attributes],
|
115
|
+
&should_not_create_an_entity
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
include_contract 'should create the entity',
|
120
|
+
expected_attributes: options.fetch(
|
121
|
+
:expected_attributes,
|
122
|
+
options[:expected_attributes_on_success]
|
123
|
+
),
|
124
|
+
expected_value: options[:expected_value_on_success],
|
125
|
+
params: configured_params,
|
126
|
+
valid_attributes: valid_attributes,
|
127
|
+
&options[:examples_on_success]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Contract asserting the action creates a new entity.
|
132
|
+
module ShouldCreateTheEntityContract
|
133
|
+
extend RSpec::SleepingKingStudios::Contract
|
134
|
+
|
135
|
+
# @!method apply(example_group, valid_attributes:, **options)
|
136
|
+
# Adds the contract to the example group.
|
137
|
+
#
|
138
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
139
|
+
# which the contract is applied.
|
140
|
+
#
|
141
|
+
# @option options [Hash<String>] expected_attributes The expected
|
142
|
+
# attributes for the returned object. Defaults to the value of
|
143
|
+
# valid_attributes.
|
144
|
+
# @option options [Hash<String>] expected_value The expected value for
|
145
|
+
# the passing result. Defaults to a Hash with the created entity.
|
146
|
+
# @option options [Hash<String>] params The parameters used to build the
|
147
|
+
# request. Defaults to the given attributes.
|
148
|
+
# @option options [Hash<String>] valid_attributes A set of attributes
|
149
|
+
# that will pass validation.
|
150
|
+
#
|
151
|
+
# @yield Additional examples.
|
152
|
+
|
153
|
+
contract do |valid_attributes:, **options, &block|
|
154
|
+
describe '#call' do
|
155
|
+
include Cuprum::Rails::RSpec::ContractHelpers
|
156
|
+
|
157
|
+
context 'with valid parameters' do
|
158
|
+
let(:request) do
|
159
|
+
Cuprum::Rails::Request.new(params: configured_params)
|
160
|
+
end
|
161
|
+
let(:configured_valid_attributes) do
|
162
|
+
option_with_default(valid_attributes)
|
163
|
+
end
|
164
|
+
let(:configured_params) do
|
165
|
+
resource_name = resource.singular_name
|
166
|
+
|
167
|
+
option_with_default(
|
168
|
+
options[:params],
|
169
|
+
default: {}
|
170
|
+
)
|
171
|
+
.merge({ resource_name => configured_valid_attributes })
|
172
|
+
end
|
173
|
+
let(:configured_expected_attributes) do
|
174
|
+
option_with_default(
|
175
|
+
options[:expected_attributes],
|
176
|
+
default: configured_valid_attributes
|
177
|
+
)
|
178
|
+
end
|
179
|
+
let(:configured_expected_entity) do
|
180
|
+
action
|
181
|
+
.resource
|
182
|
+
.entity_class
|
183
|
+
.where(configured_expected_attributes)
|
184
|
+
.first
|
185
|
+
end
|
186
|
+
let(:configured_expected_value) do
|
187
|
+
resource_name = resource.singular_name
|
188
|
+
|
189
|
+
option_with_default(
|
190
|
+
options[:expected_value],
|
191
|
+
default: {
|
192
|
+
resource_name => configured_expected_entity
|
193
|
+
}
|
194
|
+
)
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should return a passing result' do
|
198
|
+
expect(call_action)
|
199
|
+
.to be_a_passing_result
|
200
|
+
.with_value(configured_expected_value)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'should create the entity', :aggregate_failures do
|
204
|
+
expect { call_action }
|
205
|
+
.to change(configured_resource.entity_class, :count)
|
206
|
+
.by(1)
|
207
|
+
|
208
|
+
expect(
|
209
|
+
action
|
210
|
+
.resource
|
211
|
+
.entity_class
|
212
|
+
.where(configured_expected_attributes)
|
213
|
+
.exists?
|
214
|
+
).to be true
|
215
|
+
end
|
216
|
+
|
217
|
+
instance_exec(&block) if block.is_a?(Proc)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Contract asserting the action does not create a duplicate entity.
|
224
|
+
module ShouldNotCreateADuplicateEntityContract
|
225
|
+
extend RSpec::SleepingKingStudios::Contract
|
226
|
+
|
227
|
+
# @!method apply(example_group, valid_attributes:, primary_key: "id")
|
228
|
+
# Adds the contract to the example group.
|
229
|
+
#
|
230
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
231
|
+
# which the contract is applied.
|
232
|
+
# @param valid_attributes [Hash<String>] A set of attributes that will
|
233
|
+
# pass validation.
|
234
|
+
#
|
235
|
+
# @option options [Hash<String>] params The parameters used to build the
|
236
|
+
# request. Defaults to the given attributes.
|
237
|
+
#
|
238
|
+
# @yield Additional examples.
|
239
|
+
|
240
|
+
contract do |valid_attributes:, **options, &block|
|
241
|
+
describe '#call' do
|
242
|
+
include Cuprum::Rails::RSpec::ContractHelpers
|
243
|
+
|
244
|
+
context 'with duplicate parameters' do
|
245
|
+
let(:request) do
|
246
|
+
Cuprum::Rails::Request.new(params: configured_params)
|
247
|
+
end
|
248
|
+
let(:configured_valid_attributes) do
|
249
|
+
option_with_default(valid_attributes)
|
250
|
+
end
|
251
|
+
let(:configured_duplicate_entity) do
|
252
|
+
configured_resource.entity_class.new(valid_attributes)
|
253
|
+
end
|
254
|
+
let(:configured_params) do
|
255
|
+
resource_name = configured_resource.singular_name
|
256
|
+
|
257
|
+
option_with_default(
|
258
|
+
options[:params],
|
259
|
+
default: {}
|
260
|
+
)
|
261
|
+
.merge({ resource_name => configured_valid_attributes })
|
262
|
+
end
|
263
|
+
let(:configured_expected_error) do
|
264
|
+
primary_key_name = configured_resource.primary_key.to_s
|
265
|
+
primary_key_value = configured_duplicate_entity[primary_key_name]
|
266
|
+
|
267
|
+
Cuprum::Collections::Errors::AlreadyExists.new(
|
268
|
+
attribute_name: primary_key_name,
|
269
|
+
attribute_value: primary_key_value,
|
270
|
+
collection_name: configured_resource.name,
|
271
|
+
primary_key: true
|
272
|
+
)
|
273
|
+
end
|
274
|
+
|
275
|
+
before(:example) { configured_duplicate_entity.save! }
|
276
|
+
|
277
|
+
it 'should return a failing result' do
|
278
|
+
expect(call_action)
|
279
|
+
.to be_a_failing_result
|
280
|
+
.with_error(configured_expected_error)
|
281
|
+
end
|
282
|
+
|
283
|
+
instance_exec(&block) if block.is_a?(Proc)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/sleeping_king_studios/contract'
|
4
|
+
|
5
|
+
require 'cuprum/rails/rspec/contract_helpers'
|
6
|
+
require 'cuprum/rails/rspec/contracts/action_contracts'
|
7
|
+
require 'cuprum/rails/rspec/contracts/actions'
|
8
|
+
|
9
|
+
module Cuprum::Rails::RSpec::Contracts::Actions
|
10
|
+
# Namespace for RSpec destroy contracts, which validate destroy
|
11
|
+
# implementations.
|
12
|
+
module DestroyContracts
|
13
|
+
# Contract asserting the action implements the destroy action interface.
|
14
|
+
module ShouldBeADestroyActionContract
|
15
|
+
extend RSpec::SleepingKingStudios::Contract
|
16
|
+
|
17
|
+
# @method apply(example_group, existing_entity:, **options)
|
18
|
+
# Adds the contract to the example group.
|
19
|
+
#
|
20
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
21
|
+
# which the contract is applied.
|
22
|
+
# @param existing_entity [Object] The existing entity to destroy.
|
23
|
+
#
|
24
|
+
# @option options [#to_proc] examples_on_failure Extra examples to run
|
25
|
+
# for the failing cases.
|
26
|
+
# @option options [#to_proc] examples_on_success Extra examples to run
|
27
|
+
# for the passing case.
|
28
|
+
# @option options [Hash<String>] expected_value_on_success The expected
|
29
|
+
# value for the passing result. Defaults to a Hash with the destroyed
|
30
|
+
# entity.
|
31
|
+
# @option options [Hash<String>] params The parameters used to build the
|
32
|
+
# request. Defaults to the id of the entity.
|
33
|
+
# @option options [Object] primary_key_value The value of the primary
|
34
|
+
# key for the missing entity.
|
35
|
+
#
|
36
|
+
# @yield Additional examples to run for the passing case.
|
37
|
+
|
38
|
+
contract do |existing_entity:, **options, &block|
|
39
|
+
include Cuprum::Rails::RSpec::Contracts::ActionContracts
|
40
|
+
include Cuprum::Rails::RSpec::Contracts::Actions::DestroyContracts
|
41
|
+
|
42
|
+
# :nocov:
|
43
|
+
if options[:examples_on_success] && block
|
44
|
+
raise ArgumentError, 'provide either :examples_on_success or a block'
|
45
|
+
elsif block
|
46
|
+
options[:examples_on_success] = block
|
47
|
+
end
|
48
|
+
# :nocov:
|
49
|
+
|
50
|
+
should_not_destroy_the_entity = lambda do
|
51
|
+
it 'should not destroy the entity' do
|
52
|
+
expect { call_action }
|
53
|
+
.not_to change(configured_resource.entity_class, :count)
|
54
|
+
end
|
55
|
+
|
56
|
+
# :nocov:
|
57
|
+
if options[:examples_on_failure]
|
58
|
+
instance_exec(&options[:examples_on_failure])
|
59
|
+
end
|
60
|
+
# :nocov:
|
61
|
+
end
|
62
|
+
|
63
|
+
include_contract 'should be a resource action'
|
64
|
+
|
65
|
+
include_contract(
|
66
|
+
'should require primary key',
|
67
|
+
params: options[:params],
|
68
|
+
&should_not_destroy_the_entity
|
69
|
+
)
|
70
|
+
|
71
|
+
include_contract(
|
72
|
+
'should require existing entity',
|
73
|
+
params: options[:params],
|
74
|
+
primary_key_value: options[:primary_key_value],
|
75
|
+
&should_not_destroy_the_entity
|
76
|
+
)
|
77
|
+
|
78
|
+
include_contract(
|
79
|
+
'should destroy the entity',
|
80
|
+
existing_entity: existing_entity,
|
81
|
+
expected_value: options[:expected_value_on_success],
|
82
|
+
params: options[:params],
|
83
|
+
&options[:examples_on_success]
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Contract asserting the action destroys the specified entity.
|
89
|
+
module ShouldDestroyTheEntityContract
|
90
|
+
extend RSpec::SleepingKingStudios::Contract
|
91
|
+
|
92
|
+
# @method apply(example_group, existing_entity:, **options, &block)
|
93
|
+
# Adds the contract to the example group.
|
94
|
+
#
|
95
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
96
|
+
# which the contract is applied.
|
97
|
+
# @param existing_entity [Object] The existing entity to destroy.
|
98
|
+
#
|
99
|
+
# @option options [Hash<String>] expected_value The expected value for
|
100
|
+
# the passing result. Defaults to a Hash with the destroyed entity.
|
101
|
+
# @option options [Hash<String>] params The parameters used to build the
|
102
|
+
# request. Defaults to the id of the entity.
|
103
|
+
#
|
104
|
+
# @yield Additional configuration or examples.
|
105
|
+
|
106
|
+
contract do |existing_entity:, **options, &block|
|
107
|
+
describe '#call' do
|
108
|
+
include Cuprum::Rails::RSpec::ContractHelpers
|
109
|
+
|
110
|
+
context 'when the entity exists' do
|
111
|
+
let(:request) do
|
112
|
+
Cuprum::Rails::Request.new(params: configured_params)
|
113
|
+
end
|
114
|
+
let(:configured_existing_entity) do
|
115
|
+
option_with_default(existing_entity)
|
116
|
+
end
|
117
|
+
let(:configured_params) do
|
118
|
+
resource_id =
|
119
|
+
configured_existing_entity[configured_resource.primary_key]
|
120
|
+
|
121
|
+
option_with_default(
|
122
|
+
options[:params],
|
123
|
+
default: { 'id' => resource_id }
|
124
|
+
)
|
125
|
+
end
|
126
|
+
let(:configured_expected_value) do
|
127
|
+
resource_name = configured_resource.singular_name
|
128
|
+
|
129
|
+
option_with_default(
|
130
|
+
options[:expected_value],
|
131
|
+
default: {
|
132
|
+
resource_name => configured_existing_entity
|
133
|
+
}
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should return a passing result' do
|
138
|
+
expect(call_action)
|
139
|
+
.to be_a_passing_result
|
140
|
+
.with_value(configured_expected_value)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should destroy the entity', :aggregate_failures do
|
144
|
+
expect { call_action }
|
145
|
+
.to change(configured_resource.entity_class, :count)
|
146
|
+
.by(-1)
|
147
|
+
|
148
|
+
primary_key_name = configured_resource.primary_key
|
149
|
+
primary_key_value = configured_existing_entity[primary_key_name]
|
150
|
+
expect(
|
151
|
+
action
|
152
|
+
.resource
|
153
|
+
.entity_class
|
154
|
+
.exists?(primary_key_name => primary_key_value)
|
155
|
+
).to be false
|
156
|
+
end
|
157
|
+
|
158
|
+
instance_exec(&block) if block
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/sleeping_king_studios/contract'
|
4
|
+
|
5
|
+
require 'cuprum/rails/rspec/contract_helpers'
|
6
|
+
require 'cuprum/rails/rspec/contracts/action_contracts'
|
7
|
+
require 'cuprum/rails/rspec/contracts/actions'
|
8
|
+
|
9
|
+
module Cuprum::Rails::RSpec::Contracts::Actions
|
10
|
+
# Namespace for RSpec edit contracts, which validate edit implementations.
|
11
|
+
module EditContracts
|
12
|
+
# Contract asserting the action implements the edit action interface.
|
13
|
+
module ShouldBeAnEditActionContract
|
14
|
+
extend RSpec::SleepingKingStudios::Contract
|
15
|
+
|
16
|
+
# @method apply(example_group, existing_entity:, **options)
|
17
|
+
# Adds the contract to the example group.
|
18
|
+
#
|
19
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
20
|
+
# which the contract is applied.
|
21
|
+
# @param existing_entity [Object] The existing entity to find.
|
22
|
+
#
|
23
|
+
# @option options [#to_proc] examples_on_failure Extra examples to run
|
24
|
+
# for the failing cases.
|
25
|
+
# @option options [#to_proc] examples_on_success Extra examples to run
|
26
|
+
# for the passing case.
|
27
|
+
# @option options [Hash<String>] expected_value_on_success The expected
|
28
|
+
# value for the passing result. Defaults to a Hash with the found
|
29
|
+
# entity.
|
30
|
+
# @option options [Hash<String>] params The parameters used to build the
|
31
|
+
# request. Defaults to the id of the entity.
|
32
|
+
# @option options [Object] primary_key_value The value of the primary
|
33
|
+
# key for the missing entity.
|
34
|
+
#
|
35
|
+
# @yield Additional examples to run for the passing case.
|
36
|
+
|
37
|
+
contract do |existing_entity:, **options, &block|
|
38
|
+
include Cuprum::Rails::RSpec::Contracts::ActionContracts
|
39
|
+
|
40
|
+
# :nocov:
|
41
|
+
if options[:examples_on_success] && block
|
42
|
+
raise ArgumentError, 'provide either :examples_on_success or a block'
|
43
|
+
elsif block
|
44
|
+
options[:examples_on_success] = block
|
45
|
+
end
|
46
|
+
# :nocov:
|
47
|
+
|
48
|
+
include_contract 'should be a resource action'
|
49
|
+
|
50
|
+
include_contract(
|
51
|
+
'should require primary key',
|
52
|
+
params: options[:params],
|
53
|
+
&options[:examples_on_failure]
|
54
|
+
)
|
55
|
+
|
56
|
+
include_contract(
|
57
|
+
'should require existing entity',
|
58
|
+
params: options[:params],
|
59
|
+
primary_key_value: options[:primary_key_value],
|
60
|
+
&options[:examples_on_failure]
|
61
|
+
)
|
62
|
+
|
63
|
+
include_contract(
|
64
|
+
'should find the entity',
|
65
|
+
existing_entity: existing_entity,
|
66
|
+
expected_value: options[:expected_value_on_success],
|
67
|
+
params: options[:params],
|
68
|
+
&options[:examples_on_success]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/rspec/contracts/action_contracts'
|
4
|
+
require 'cuprum/rails/rspec/contracts/actions'
|
5
|
+
|
6
|
+
module Cuprum::Rails::RSpec::Contracts::Actions
|
7
|
+
# Namespace for RSpec index contracts, which validate index implementations.
|
8
|
+
module IndexContracts
|
9
|
+
# Contract asserting the action implements the index action interface.
|
10
|
+
module ShouldBeAnIndexActionContract
|
11
|
+
extend RSpec::SleepingKingStudios::Contract
|
12
|
+
|
13
|
+
# @method apply(example_group, existing_entities:, **options)
|
14
|
+
# Adds the contract to the example group.
|
15
|
+
#
|
16
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
17
|
+
# which the contract is applied.
|
18
|
+
# @param existing_entities [Object] The existing entities to find.
|
19
|
+
#
|
20
|
+
# @option options [#to_proc] examples_on_success Extra examples to run
|
21
|
+
# for the passing case.
|
22
|
+
# @option options [Hash<String>] expected_value_on_success The expected
|
23
|
+
# value for the passing result. Defaults to a Hash with the found
|
24
|
+
# entity.
|
25
|
+
# @option options [Hash<String>] params The parameters used to build the
|
26
|
+
# request. Defaults to an empty hash.
|
27
|
+
#
|
28
|
+
# @yield Additional examples to run for the passing case.
|
29
|
+
|
30
|
+
contract do |existing_entities:, **options, &block|
|
31
|
+
include Cuprum::Rails::RSpec::Contracts::ActionContracts
|
32
|
+
include Cuprum::Rails::RSpec::Contracts::Actions::IndexContracts
|
33
|
+
|
34
|
+
# :nocov:
|
35
|
+
if options[:examples_on_success] && block
|
36
|
+
raise ArgumentError, 'provide either :examples_on_success or a block'
|
37
|
+
elsif block
|
38
|
+
options[:examples_on_success] = block
|
39
|
+
end
|
40
|
+
# :nocov:
|
41
|
+
|
42
|
+
include_contract 'should be a resource action'
|
43
|
+
|
44
|
+
include_contract 'should find the entities',
|
45
|
+
existing_entities: existing_entities,
|
46
|
+
expected_value: options[:expected_value_on_success],
|
47
|
+
params: options[:params],
|
48
|
+
&options[:examples_on_success]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Contract asserting the action queries the repository for the entities.
|
53
|
+
module ShouldFindTheEntitiesContract
|
54
|
+
extend RSpec::SleepingKingStudios::Contract
|
55
|
+
|
56
|
+
# @method apply(example_group, existing_entities:, **options)
|
57
|
+
# Adds the contract to the example group.
|
58
|
+
#
|
59
|
+
# @param example_group [RSpec::Core::ExampleGroup] The example group to
|
60
|
+
# which the contract is applied.
|
61
|
+
# @param existing_entities [Object] The existing entities to find.
|
62
|
+
#
|
63
|
+
# @option options [Hash<String>] expected_value The expected
|
64
|
+
# value for the passing result. Defaults to a Hash with the found
|
65
|
+
# entity.
|
66
|
+
# @option options [Hash<String>] params The parameters used to build the
|
67
|
+
# request. Defaults to an empty hash.
|
68
|
+
#
|
69
|
+
# @yield Additional examples.
|
70
|
+
|
71
|
+
contract do |existing_entities:, **options, &block|
|
72
|
+
include Cuprum::Rails::RSpec::Contracts::ActionContracts
|
73
|
+
|
74
|
+
describe '#call' do
|
75
|
+
include Cuprum::Rails::RSpec::ContractHelpers
|
76
|
+
|
77
|
+
let(:request) do
|
78
|
+
Cuprum::Rails::Request.new(params: configured_params)
|
79
|
+
end
|
80
|
+
let(:configured_params) do
|
81
|
+
option_with_default(options[:params], default: {})
|
82
|
+
end
|
83
|
+
let(:configured_existing_entities) do
|
84
|
+
option_with_default(existing_entities)
|
85
|
+
end
|
86
|
+
let(:configured_expected_value) do
|
87
|
+
resource_name = configured_resource.name
|
88
|
+
|
89
|
+
option_with_default(
|
90
|
+
options[:expected_value],
|
91
|
+
default: {
|
92
|
+
resource_name => configured_existing_entities
|
93
|
+
}
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should return a passing result' do
|
98
|
+
expect(call_action)
|
99
|
+
.to be_a_passing_result
|
100
|
+
.with_value(configured_expected_value)
|
101
|
+
end
|
102
|
+
|
103
|
+
instance_exec(&block) if block
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|