brainstem 2.0.0 → 2.1.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 +147 -0
- data/Gemfile.lock +68 -39
- data/lib/brainstem/api_docs.rb +9 -4
- data/lib/brainstem/api_docs/atlas.rb +3 -3
- data/lib/brainstem/api_docs/controller.rb +12 -4
- data/lib/brainstem/api_docs/controller_collection.rb +11 -2
- data/lib/brainstem/api_docs/endpoint.rb +17 -7
- data/lib/brainstem/api_docs/endpoint_collection.rb +9 -1
- data/lib/brainstem/api_docs/formatters/open_api_specification/helper.rb +19 -16
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter.rb +52 -80
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter.rb +64 -84
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint_formatter.rb +1 -1
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/endpoint_param_formatter.rb +39 -0
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/presenter_field_formatter.rb +147 -0
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/response_field_formatter.rb +146 -0
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter.rb +53 -55
- data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/tags_formatter.rb +1 -1
- data/lib/brainstem/api_docs/presenter.rb +16 -8
- data/lib/brainstem/api_docs/presenter_collection.rb +8 -5
- data/lib/brainstem/api_docs/sinks/open_api_specification_sink.rb +3 -1
- data/lib/brainstem/cli/generate_api_docs_command.rb +4 -0
- data/lib/brainstem/concerns/controller_dsl.rb +90 -20
- data/lib/brainstem/concerns/presenter_dsl.rb +16 -8
- data/lib/brainstem/dsl/association.rb +12 -0
- data/lib/brainstem/dsl/fields_block.rb +1 -1
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/api_docs/controller_spec.rb +127 -5
- data/spec/brainstem/api_docs/endpoint_spec.rb +489 -57
- data/spec/brainstem/api_docs/formatters/open_api_specification/helper_spec.rb +15 -4
- data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter_spec.rb +112 -66
- data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter_spec.rb +404 -32
- data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/endpoint_param_formatter_spec.rb +335 -0
- data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/presenter_field_formatter_spec.rb +237 -0
- data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/response_field_formatter_spec.rb +413 -0
- data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter_spec.rb +116 -4
- data/spec/brainstem/api_docs/presenter_spec.rb +406 -24
- data/spec/brainstem/cli/generate_api_docs_command_spec.rb +8 -0
- data/spec/brainstem/concerns/controller_dsl_spec.rb +606 -45
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +34 -2
- data/spec/brainstem/dsl/association_spec.rb +54 -3
- metadata +11 -2
@@ -0,0 +1,413 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/response_field_formatter'
|
3
|
+
|
4
|
+
module Brainstem
|
5
|
+
module ApiDocs
|
6
|
+
module Formatters
|
7
|
+
module OpenApiSpecification
|
8
|
+
module Version2
|
9
|
+
module FieldDefinitions
|
10
|
+
describe ResponseFieldFormatter do
|
11
|
+
describe '#format' do
|
12
|
+
let(:endpoint) { OpenStruct.new(controller_name: 'Test', action: 'create') }
|
13
|
+
let(:field_name) { 'sprocket' }
|
14
|
+
let(:configuration_tree) { field_configuration_tree.with_indifferent_access }
|
15
|
+
|
16
|
+
subject { described_class.new(endpoint, field_name, configuration_tree).format }
|
17
|
+
|
18
|
+
context 'when formatting non-nested field' do
|
19
|
+
let(:field_configuration_tree) do
|
20
|
+
{
|
21
|
+
_config: {
|
22
|
+
type: 'string',
|
23
|
+
info: 'The name of the sprocket'
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns the formatted field schema' do
|
29
|
+
expect(subject).to eq(
|
30
|
+
'type' => 'string',
|
31
|
+
'description' => 'The name of the sprocket.',
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when formatting nested field' do
|
37
|
+
context 'when formatting an array field' do
|
38
|
+
let(:field_configuration_tree) do
|
39
|
+
{
|
40
|
+
_config: {
|
41
|
+
type: 'array',
|
42
|
+
item_type: 'long',
|
43
|
+
},
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns the formatted field schema' do
|
48
|
+
expect(subject).to eq(
|
49
|
+
'type' => 'array',
|
50
|
+
'items' => {
|
51
|
+
'type' => 'integer', 'format' => 'int64'
|
52
|
+
}
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when formatting a nested array field with non nested data type' do
|
58
|
+
let(:field_configuration_tree) do
|
59
|
+
{
|
60
|
+
_config: {
|
61
|
+
type: 'array',
|
62
|
+
nested_levels: 3,
|
63
|
+
item_type: 'decimal',
|
64
|
+
},
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns the formatted field schema' do
|
69
|
+
expect(subject).to eq(
|
70
|
+
'type' => 'array',
|
71
|
+
'items' => {
|
72
|
+
'type' => 'array',
|
73
|
+
'items' => {
|
74
|
+
'type' => 'array',
|
75
|
+
'items' => {
|
76
|
+
'type' => 'number',
|
77
|
+
'format' => 'float'
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when formatting a nested array field with objects' do
|
86
|
+
let(:field_configuration_tree) do
|
87
|
+
{
|
88
|
+
_config: {
|
89
|
+
type: 'array',
|
90
|
+
nested_levels: 2,
|
91
|
+
item_type: 'hash',
|
92
|
+
},
|
93
|
+
widget_name: {
|
94
|
+
_config: {
|
95
|
+
required: true,
|
96
|
+
type: 'string',
|
97
|
+
info: 'the name of the widget',
|
98
|
+
nodoc: false
|
99
|
+
},
|
100
|
+
},
|
101
|
+
widget_permissions: {
|
102
|
+
_config: {
|
103
|
+
type: 'array',
|
104
|
+
item_type: 'hash',
|
105
|
+
info: 'the permissions of the widget',
|
106
|
+
nodoc: false
|
107
|
+
},
|
108
|
+
can_edit: {
|
109
|
+
_config: {
|
110
|
+
type: 'array',
|
111
|
+
nested_levels: 3,
|
112
|
+
item_type: 'boolean',
|
113
|
+
nodoc: false
|
114
|
+
},
|
115
|
+
}
|
116
|
+
},
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'formats a complicated tree with arrays and hashes as children' do
|
121
|
+
expect(subject).to eq(
|
122
|
+
'type' => 'array',
|
123
|
+
'items' => {
|
124
|
+
'type' => 'array',
|
125
|
+
'items' => {
|
126
|
+
'type' => 'object',
|
127
|
+
'properties' => {
|
128
|
+
'widget_name' => {
|
129
|
+
'type' => 'string',
|
130
|
+
'description' => 'The name of the widget.',
|
131
|
+
},
|
132
|
+
'widget_permissions' => {
|
133
|
+
'type' => 'array',
|
134
|
+
'description' => 'The permissions of the widget.',
|
135
|
+
'items' => {
|
136
|
+
'type' => 'object',
|
137
|
+
'properties' => {
|
138
|
+
'can_edit' => {
|
139
|
+
'type' => 'array',
|
140
|
+
'items' => {
|
141
|
+
'type' => 'array',
|
142
|
+
'items' => {
|
143
|
+
'type' => 'array',
|
144
|
+
'items' => {
|
145
|
+
'type' => 'boolean'
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'when formatting a hash field' do
|
161
|
+
let(:field_configuration_tree) do
|
162
|
+
{
|
163
|
+
_config: {
|
164
|
+
type: 'hash',
|
165
|
+
info: 'Details about the widget',
|
166
|
+
},
|
167
|
+
widget_name: {
|
168
|
+
_config: {
|
169
|
+
required: true,
|
170
|
+
type: 'string',
|
171
|
+
info: 'the name of the widget',
|
172
|
+
nodoc: false
|
173
|
+
},
|
174
|
+
},
|
175
|
+
widget_permissions: {
|
176
|
+
_config: {
|
177
|
+
type: 'array',
|
178
|
+
item_type: 'string',
|
179
|
+
info: 'the permissions of the widget',
|
180
|
+
nodoc: false
|
181
|
+
},
|
182
|
+
},
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'returns the formatted field schema' do
|
187
|
+
expect(subject).to eq(
|
188
|
+
'type' => 'object',
|
189
|
+
'description' => 'Details about the widget.',
|
190
|
+
'properties' => {
|
191
|
+
'widget_name' => {
|
192
|
+
'type' => 'string',
|
193
|
+
'description' => 'The name of the widget.',
|
194
|
+
},
|
195
|
+
'widget_permissions' => {
|
196
|
+
'type' => 'array',
|
197
|
+
'description' => 'The permissions of the widget.',
|
198
|
+
'items' => {
|
199
|
+
'type' => 'string',
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'when formatting a multi nested hash field' do
|
208
|
+
let(:field_configuration_tree) do
|
209
|
+
{
|
210
|
+
_config: {
|
211
|
+
type: 'hash',
|
212
|
+
info: 'Details about the widget',
|
213
|
+
},
|
214
|
+
widget_name: {
|
215
|
+
_config: {
|
216
|
+
required: true,
|
217
|
+
type: 'string',
|
218
|
+
info: 'the name of the widget',
|
219
|
+
nodoc: false
|
220
|
+
},
|
221
|
+
},
|
222
|
+
widget_permissions: {
|
223
|
+
_config: {
|
224
|
+
type: 'hash',
|
225
|
+
info: 'the permissions of the widget',
|
226
|
+
nodoc: false
|
227
|
+
},
|
228
|
+
can_edit: {
|
229
|
+
_config: {
|
230
|
+
type: 'boolean',
|
231
|
+
info: 'can edit the widget',
|
232
|
+
nodoc: false
|
233
|
+
}
|
234
|
+
}
|
235
|
+
},
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'returns the formatted field schema' do
|
240
|
+
expect(subject).to eq(
|
241
|
+
'type' => 'object',
|
242
|
+
'description' => 'Details about the widget.',
|
243
|
+
'properties' => {
|
244
|
+
'widget_name' => {
|
245
|
+
'type' => 'string',
|
246
|
+
'description' => 'The name of the widget.',
|
247
|
+
},
|
248
|
+
'widget_permissions' => {
|
249
|
+
'type' => 'object',
|
250
|
+
'description' => 'The permissions of the widget.',
|
251
|
+
'properties' => {
|
252
|
+
'can_edit' => {
|
253
|
+
'type' => 'boolean',
|
254
|
+
'description' => 'Can edit the widget.',
|
255
|
+
}
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'dynamic keys' do
|
265
|
+
context 'when formatting a hash field' do
|
266
|
+
let(:field_configuration_tree) do
|
267
|
+
{
|
268
|
+
_config: {
|
269
|
+
type: 'hash',
|
270
|
+
info: 'Dynamic keys hash.',
|
271
|
+
},
|
272
|
+
_dynamic_key: {
|
273
|
+
_config: {
|
274
|
+
nodoc: false,
|
275
|
+
type: 'hash',
|
276
|
+
dynamic_key: true,
|
277
|
+
info: 'a dynamic description.'
|
278
|
+
},
|
279
|
+
blah: {
|
280
|
+
_config: {
|
281
|
+
nodoc: false,
|
282
|
+
type: 'string',
|
283
|
+
},
|
284
|
+
},
|
285
|
+
},
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'returns the formatted field schema' do
|
290
|
+
expect(subject).to eq({
|
291
|
+
'type' => 'object',
|
292
|
+
'description' => 'Dynamic keys hash.',
|
293
|
+
'additionalProperties' => {
|
294
|
+
'type' => 'object',
|
295
|
+
'description' => 'A dynamic description.',
|
296
|
+
'properties' => {
|
297
|
+
'blah' => {
|
298
|
+
'type' => 'string',
|
299
|
+
},
|
300
|
+
},
|
301
|
+
},
|
302
|
+
})
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context 'when formatting a nested hash field' do
|
307
|
+
let(:field_configuration_tree) do
|
308
|
+
{
|
309
|
+
_config: {
|
310
|
+
type: 'hash',
|
311
|
+
info: 'Dynamic keys hash.',
|
312
|
+
},
|
313
|
+
non_dynamic_key: {
|
314
|
+
_config: {
|
315
|
+
nodoc: false,
|
316
|
+
type: 'hash',
|
317
|
+
info: 'A non-dynamic description.'
|
318
|
+
},
|
319
|
+
non_dynamic_property: {
|
320
|
+
_config: {
|
321
|
+
nodoc: false,
|
322
|
+
type: 'string',
|
323
|
+
},
|
324
|
+
},
|
325
|
+
},
|
326
|
+
_dynamic_key: {
|
327
|
+
_config: {
|
328
|
+
nodoc: false,
|
329
|
+
type: 'hash',
|
330
|
+
dynamic_key: true,
|
331
|
+
info: 'A dynamic description.'
|
332
|
+
},
|
333
|
+
dynamic_property1: {
|
334
|
+
_config: {
|
335
|
+
nodoc: false,
|
336
|
+
type: 'string',
|
337
|
+
},
|
338
|
+
},
|
339
|
+
_dynamic_key: {
|
340
|
+
_config: {
|
341
|
+
nodoc: false,
|
342
|
+
type: 'hash',
|
343
|
+
dynamic_key: true,
|
344
|
+
info: 'A 2nd dynamic description.'
|
345
|
+
},
|
346
|
+
_dynamic_key: {
|
347
|
+
_config: {
|
348
|
+
nodoc: false,
|
349
|
+
type: 'string',
|
350
|
+
dynamic_key: true,
|
351
|
+
info: 'A dynamic string.'
|
352
|
+
},
|
353
|
+
},
|
354
|
+
dynamic_property2: {
|
355
|
+
_config: {
|
356
|
+
nodoc: false,
|
357
|
+
type: 'string',
|
358
|
+
},
|
359
|
+
},
|
360
|
+
},
|
361
|
+
},
|
362
|
+
}
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'returns the formatted field schema' do
|
366
|
+
expect(subject).to eq({
|
367
|
+
'type' => 'object',
|
368
|
+
'description' => 'Dynamic keys hash.',
|
369
|
+
'properties' => {
|
370
|
+
'non_dynamic_key' => {
|
371
|
+
'type' => 'object',
|
372
|
+
'description' => 'A non-dynamic description.',
|
373
|
+
'properties' => {
|
374
|
+
'non_dynamic_property' => {
|
375
|
+
'type' => 'string',
|
376
|
+
}
|
377
|
+
}
|
378
|
+
},
|
379
|
+
},
|
380
|
+
'additionalProperties' => {
|
381
|
+
'type' => 'object',
|
382
|
+
'description' => 'A dynamic description.',
|
383
|
+
'properties' => {
|
384
|
+
'dynamic_property1' => {
|
385
|
+
'type' => 'string',
|
386
|
+
},
|
387
|
+
},
|
388
|
+
'additionalProperties' => {
|
389
|
+
'type' => 'object',
|
390
|
+
'description' => 'A 2nd dynamic description.',
|
391
|
+
'properties' => {
|
392
|
+
'dynamic_property2' => {
|
393
|
+
'type' => 'string',
|
394
|
+
},
|
395
|
+
},
|
396
|
+
'additionalProperties' => {
|
397
|
+
'type' => 'string',
|
398
|
+
'description' => 'A dynamic string.',
|
399
|
+
},
|
400
|
+
},
|
401
|
+
},
|
402
|
+
})
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter_spec.rb
CHANGED
@@ -30,9 +30,10 @@ module Brainstem
|
|
30
30
|
|
31
31
|
describe '#call' do
|
32
32
|
before do
|
33
|
-
stub(presenter).format_title!
|
34
|
-
stub(presenter).format_fields!
|
35
|
-
stub(presenter).valid_fields
|
33
|
+
stub(presenter).format_title! { title }
|
34
|
+
stub(presenter).format_fields! { fake_formatted_fields }
|
35
|
+
stub(presenter).valid_fields { valid_fields }
|
36
|
+
stub(presenter).valid_associations { {} }
|
36
37
|
end
|
37
38
|
|
38
39
|
context 'when nodoc' do
|
@@ -146,6 +147,83 @@ module Brainstem
|
|
146
147
|
stub(presenter).conditionals { conditionals }
|
147
148
|
end
|
148
149
|
|
150
|
+
context 'with associations present' do
|
151
|
+
context 'when association type is belongs_to or has_one' do
|
152
|
+
before do
|
153
|
+
presenter_class.associations do
|
154
|
+
association :task, Task,
|
155
|
+
type: :belongs_to
|
156
|
+
|
157
|
+
association :user, User,
|
158
|
+
response_key: :user_id,
|
159
|
+
type: :has_one
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'outputs the foreign key in single formatted id' do
|
164
|
+
subject.send(:format_fields!)
|
165
|
+
|
166
|
+
expect(subject.definition).to have_key :properties
|
167
|
+
expect(subject.definition[:properties]).to eq({
|
168
|
+
'task_id' => { 'type' => 'string', 'description' => "`task_id` will only be included in the response if `task` is in the list of included associations. See <a href='#section/Includes'>include</a> section for usage." },
|
169
|
+
'user_id' => { 'type' => 'string', 'description' => "`user_id` will only be included in the response if `user` is in the list of included associations. See <a href='#section/Includes'>include</a> section for usage." }
|
170
|
+
})
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'when association type is has_many' do
|
175
|
+
before do
|
176
|
+
presenter_class.associations do
|
177
|
+
association :task, Task,
|
178
|
+
type: :has_many
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'outputs the foreign key in plural formatted id' do
|
183
|
+
subject.send(:format_fields!)
|
184
|
+
|
185
|
+
expect(subject.definition).to have_key :properties
|
186
|
+
expect(subject.definition[:properties]).to eq({
|
187
|
+
'task_ids' => {
|
188
|
+
'type' => 'array',
|
189
|
+
'description' => "`task_ids` will only be included in the response if `task` is in the list of included associations. See <a href='#section/Includes'>include</a> section for usage.",
|
190
|
+
'items' => {
|
191
|
+
'type' => 'string'
|
192
|
+
},
|
193
|
+
},
|
194
|
+
})
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'when association is polymorphic' do
|
199
|
+
before do
|
200
|
+
presenter_class.associations do
|
201
|
+
association :task, :polymorphic, polymorphic_classes: [User, Task]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'outputs an object that contains an id and key' do
|
206
|
+
subject.send(:format_fields!)
|
207
|
+
|
208
|
+
expect(subject.definition).to have_key :properties
|
209
|
+
expect(subject.definition[:properties]).to eq({
|
210
|
+
'task_ref' => {
|
211
|
+
'type' => 'object',
|
212
|
+
'description' => "`task_ref` will only be included in the response if `task` is in the list of included associations. See <a href='#section/Includes'>include</a> section for usage.",
|
213
|
+
'properties' => {
|
214
|
+
'id' => {
|
215
|
+
'type' => 'string'
|
216
|
+
},
|
217
|
+
'key' => {
|
218
|
+
'type' => 'string'
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
})
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
149
227
|
context 'with fields present' do
|
150
228
|
describe 'branch node' do
|
151
229
|
context 'with single branch' do
|
@@ -165,7 +243,6 @@ module Brainstem
|
|
165
243
|
'sprockets' => {
|
166
244
|
'type' => 'object',
|
167
245
|
'properties' => {
|
168
|
-
|
169
246
|
'sprocket_name' => { 'type' => 'string', 'description' => 'Whatever.' }
|
170
247
|
}
|
171
248
|
}
|
@@ -225,6 +302,7 @@ module Brainstem
|
|
225
302
|
expect(subject.definition[:properties]).to eq({
|
226
303
|
'sprockets' => {
|
227
304
|
'type' => 'array',
|
305
|
+
'description' => 'Parent.',
|
228
306
|
'items' => {
|
229
307
|
'type' => 'object',
|
230
308
|
'properties' => {
|
@@ -422,6 +500,40 @@ module Brainstem
|
|
422
500
|
end
|
423
501
|
end
|
424
502
|
end
|
503
|
+
|
504
|
+
describe '#sort_properties!' do
|
505
|
+
let(:presenter_class) do
|
506
|
+
Class.new(Brainstem::Presenter) do
|
507
|
+
presents Workspace
|
508
|
+
end
|
509
|
+
end
|
510
|
+
let(:presenter) { Presenter.new(Object.new, const: presenter_class, target_class: 'Workspace') }
|
511
|
+
let(:conditionals) { {} }
|
512
|
+
|
513
|
+
before do
|
514
|
+
stub(presenter).conditionals { conditionals }
|
515
|
+
|
516
|
+
presenter_class.associations do
|
517
|
+
association :user, User,
|
518
|
+
response_key: :user_id,
|
519
|
+
type: :has_one
|
520
|
+
|
521
|
+
association :task, Task,
|
522
|
+
type: :belongs_to
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
it 'correctly sorts the properties' do
|
527
|
+
subject.send(:format_fields!)
|
528
|
+
subject.send(:sort_properties!)
|
529
|
+
|
530
|
+
expect(subject.definition).to have_key :properties
|
531
|
+
expect(subject.definition[:properties]).to eq({
|
532
|
+
'task_id' => { 'type' => 'string', 'description' => "`task_id` will only be included in the response if `task` is in the list of included associations. See <a href='#section/Includes'>include</a> section for usage." },
|
533
|
+
'user_id' => { 'type' => 'string', 'description' => "`user_id` will only be included in the response if `user` is in the list of included associations. See <a href='#section/Includes'>include</a> section for usage." }
|
534
|
+
})
|
535
|
+
end
|
536
|
+
end
|
425
537
|
end
|
426
538
|
end
|
427
539
|
end
|