propel_api 0.1.4 → 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 +82 -6
- data/lib/generators/propel_api/core/named_base.rb +88 -27
- data/lib/generators/propel_api/core/relationship_inferrer.rb +42 -8
- data/lib/generators/propel_api/templates/config/propel_api.rb.tt +3 -2
- data/lib/generators/propel_api/templates/controllers/api_controller_graphiti.rb +49 -6
- data/lib/generators/propel_api/templates/controllers/api_controller_propel_facets.rb +215 -4
- data/lib/generators/propel_api/templates/scaffold/facet_controller_template.rb.tt +27 -1
- data/lib/generators/propel_api/templates/scaffold/facet_model_template.rb.tt +39 -6
- data/lib/generators/propel_api/templates/seeds/seeds_template.rb.tt +11 -2
- data/lib/generators/propel_api/templates/tests/controller_test_template.rb.tt +279 -36
- data/lib/generators/propel_api/templates/tests/fixtures_template.yml.tt +30 -0
- data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +459 -56
- data/lib/generators/propel_api/templates/tests/model_test_template.rb.tt +25 -7
- data/lib/generators/propel_api/unpack/unpack_generator.rb +52 -30
- data/lib/propel_api.rb +1 -1
- metadata +2 -2
@@ -7,12 +7,23 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
7
7
|
def setup
|
8
8
|
@organization = organizations(:acme_org)
|
9
9
|
@user = users(:john_user)
|
10
|
+
@agency = agencies(:marketing_agency)
|
11
|
+
<% if singular_table_name == 'organization' -%>
|
12
|
+
@<%= singular_table_name %> = <%= table_name %>(:acme_org)
|
13
|
+
<% elsif singular_table_name == 'user' -%>
|
14
|
+
@<%= singular_table_name %> = <%= table_name %>(:john_user)
|
15
|
+
<% elsif singular_table_name == 'agency' -%>
|
16
|
+
@<%= singular_table_name %> = <%= table_name %>(:marketing_agency)
|
17
|
+
<% else -%>
|
10
18
|
@<%= singular_table_name %> = <%= table_name %>(:one)
|
19
|
+
<% end -%>
|
11
20
|
@token = @user.generate_jwt_token
|
12
21
|
@auth_headers = { 'Authorization' => "Bearer #{@token}" }
|
13
22
|
|
14
23
|
# Ensure test <%= singular_table_name %> belongs to test user's organization
|
24
|
+
<% unless singular_table_name == 'organization' -%>
|
15
25
|
@<%= singular_table_name %>.update!(organization: @organization)
|
26
|
+
<% end -%>
|
16
27
|
end
|
17
28
|
|
18
29
|
# === AUTHENTICATION TESTS ===
|
@@ -34,7 +45,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
34
45
|
end
|
35
46
|
|
36
47
|
test "should not access show without authentication" do
|
37
|
-
get <%=
|
48
|
+
get <%= api_singular_route_helper %>_url(@<%= singular_table_name %>)
|
38
49
|
assert_response :unauthorized
|
39
50
|
end
|
40
51
|
|
@@ -46,13 +57,13 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
46
57
|
end
|
47
58
|
|
48
59
|
test "should not update without authentication" do
|
49
|
-
patch <%=
|
60
|
+
patch <%= api_singular_route_helper %>_url(@<%= singular_table_name %>), params: { data: { title: "Updated" } }
|
50
61
|
assert_response :unauthorized
|
51
62
|
end
|
52
63
|
|
53
64
|
test "should not destroy without authentication" do
|
54
65
|
assert_no_difference('<%= class_name %>.count') do
|
55
|
-
delete <%=
|
66
|
+
delete <%= api_singular_route_helper %>_url(@<%= singular_table_name %>)
|
56
67
|
end
|
57
68
|
assert_response :unauthorized
|
58
69
|
end
|
@@ -79,19 +90,19 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
79
90
|
pagination = response_body['pagination']
|
80
91
|
|
81
92
|
# Should include pagination metadata
|
82
|
-
assert_includes pagination.keys, '
|
83
|
-
assert_includes pagination.keys, '
|
84
|
-
assert_includes pagination.keys, '
|
85
|
-
assert_includes pagination.keys, '
|
86
|
-
assert_includes pagination.keys, '
|
87
|
-
assert_includes pagination.keys, '
|
88
|
-
assert_includes pagination.keys, 'prev'
|
93
|
+
assert_includes pagination.keys, 'current_page'
|
94
|
+
assert_includes pagination.keys, 'per_page'
|
95
|
+
assert_includes pagination.keys, 'total_count'
|
96
|
+
assert_includes pagination.keys, 'total_pages'
|
97
|
+
assert_includes pagination.keys, 'next_page'
|
98
|
+
assert_includes pagination.keys, 'prev_page'
|
89
99
|
end
|
90
100
|
|
91
101
|
test "should only show records for user's organization" do
|
92
102
|
# Create record for different organization
|
93
103
|
other_org = Organization.create!(name: "Other Organization")
|
94
104
|
other_<%= singular_table_name %> = <%= class_name %>.create!(
|
105
|
+
|
95
106
|
<% attributes.each_with_index do |attribute, index| -%>
|
96
107
|
<% if attribute.name == "organization" && attribute.type == :references -%>
|
97
108
|
<%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
|
@@ -100,7 +111,13 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
100
111
|
<% elsif attribute.type == :references -%>
|
101
112
|
<%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
|
102
113
|
<% elsif attribute.type == :string -%>
|
114
|
+
<% if attribute.name.to_s.match?(/email/) -%>
|
115
|
+
<%= attribute.name %>: "other@example.com"<%= ',' if index < attributes.length - 1 %>
|
116
|
+
<% elsif attribute.name.to_s.match?(/password/) -%>
|
117
|
+
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
118
|
+
<% else -%>
|
103
119
|
<%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
120
|
+
<% end -%>
|
104
121
|
<% elsif attribute.type == :text -%>
|
105
122
|
<%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
|
106
123
|
<% elsif attribute.type == :integer -%>
|
@@ -109,6 +126,10 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
109
126
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
110
127
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
111
128
|
<%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
|
129
|
+
<% elsif attribute.type == :datetime -%>
|
130
|
+
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
131
|
+
<% elsif attribute.type == :json -%>
|
132
|
+
<%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
|
112
133
|
<% else -%>
|
113
134
|
<%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
|
114
135
|
<% end -%>
|
@@ -131,7 +152,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
131
152
|
# === SHOW TESTS ===
|
132
153
|
|
133
154
|
test "should show <%= singular_table_name %> with authentication" do
|
134
|
-
get <%=
|
155
|
+
get <%= api_singular_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
|
135
156
|
assert_response :success
|
136
157
|
|
137
158
|
response_body = JSON.parse(response.body)
|
@@ -142,13 +163,14 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
142
163
|
end
|
143
164
|
|
144
165
|
test "should return 404 for non-existent <%= singular_table_name %>" do
|
145
|
-
get <%=
|
166
|
+
get <%= api_singular_route_helper %>_url(0), headers: @auth_headers
|
146
167
|
assert_response :not_found
|
147
168
|
end
|
148
169
|
|
149
170
|
test "should not show <%= singular_table_name %> from different organization" do
|
150
171
|
other_org = Organization.create!(name: "Other Organization")
|
151
172
|
other_<%= singular_table_name %> = <%= class_name %>.create!(
|
173
|
+
|
152
174
|
<% attributes.each_with_index do |attribute, index| -%>
|
153
175
|
<% if attribute.name == "organization" && attribute.type == :references -%>
|
154
176
|
<%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
|
@@ -157,7 +179,13 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
157
179
|
<% elsif attribute.type == :references -%>
|
158
180
|
<%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
|
159
181
|
<% elsif attribute.type == :string -%>
|
182
|
+
<% if attribute.name.to_s.match?(/email/) -%>
|
183
|
+
<%= attribute.name %>: "other@example.com"<%= ',' if index < attributes.length - 1 %>
|
184
|
+
<% elsif attribute.name.to_s.match?(/password/) -%>
|
185
|
+
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
186
|
+
<% else -%>
|
160
187
|
<%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
188
|
+
<% end -%>
|
161
189
|
<% elsif attribute.type == :text -%>
|
162
190
|
<%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
|
163
191
|
<% elsif attribute.type == :integer -%>
|
@@ -166,18 +194,39 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
166
194
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
167
195
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
168
196
|
<%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
|
197
|
+
<% elsif attribute.type == :datetime -%>
|
198
|
+
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
199
|
+
<% elsif attribute.type == :json -%>
|
200
|
+
<%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
|
169
201
|
<% else -%>
|
170
202
|
<%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
|
171
203
|
<% end -%>
|
172
204
|
<% end -%>
|
173
205
|
)
|
174
206
|
|
175
|
-
get <%=
|
207
|
+
get <%= api_singular_route_helper %>_url(other_<%= singular_table_name %>), headers: @auth_headers
|
176
208
|
assert_response :not_found
|
177
209
|
end
|
178
210
|
|
179
211
|
# === CREATE TESTS ===
|
180
212
|
|
213
|
+
<% if class_name == 'Organization' -%>
|
214
|
+
test "should block <%= singular_table_name %> creation and direct to signup" do
|
215
|
+
assert_no_difference('<%= class_name %>.count') do
|
216
|
+
post <%= api_route_helper %>_url,
|
217
|
+
params: { data: valid_<%= singular_table_name %>_params },
|
218
|
+
headers: @auth_headers
|
219
|
+
end
|
220
|
+
|
221
|
+
assert_response :forbidden
|
222
|
+
|
223
|
+
response_body = JSON.parse(response.body)
|
224
|
+
assert_includes response_body.keys, 'error'
|
225
|
+
assert_includes response_body.keys, 'message'
|
226
|
+
assert_includes response_body['message'], 'signup'
|
227
|
+
assert_equal 'ORGANIZATION_CREATION_BLOCKED', response_body['code']
|
228
|
+
end
|
229
|
+
<% else -%>
|
181
230
|
test "should create <%= singular_table_name %> with valid params" do
|
182
231
|
assert_difference('<%= class_name %>.count', 1) do
|
183
232
|
post <%= api_route_helper %>_url,
|
@@ -191,10 +240,43 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
191
240
|
assert_includes response_body.keys, 'data'
|
192
241
|
|
193
242
|
created_<%= singular_table_name %> = response_body['data']
|
194
|
-
|
195
|
-
|
243
|
+
assert_not_nil created_<%= singular_table_name %>, "Response should contain <%= singular_table_name %> data"
|
244
|
+
|
245
|
+
<% if class_name != 'Organization' -%>
|
246
|
+
# Verify organization reference (handle both nested and flat formats)
|
247
|
+
if created_<%= singular_table_name %>['organization']
|
248
|
+
assert_equal @organization.id, created_<%= singular_table_name %>['organization']['id']
|
249
|
+
else
|
250
|
+
assert_equal @organization.id, created_<%= singular_table_name %>['organization_id']
|
251
|
+
end
|
252
|
+
<% end -%>
|
253
|
+
|
254
|
+
<% if class_name != 'User' && class_name != 'Organization' && attributes.any? { |attr| attr.name == 'user_id' || (attr.type == :references && attr.name == 'user') } -%>
|
255
|
+
# Verify user reference (handle both nested and flat formats)
|
256
|
+
if created_<%= singular_table_name %>['user']
|
257
|
+
assert_equal @user.id, created_<%= singular_table_name %>['user']['id']
|
258
|
+
elsif created_<%= singular_table_name %>['user_id']
|
259
|
+
assert_equal @user.id, created_<%= singular_table_name %>['user_id']
|
260
|
+
end
|
261
|
+
<% end -%>
|
196
262
|
end
|
263
|
+
<% end -%>
|
197
264
|
|
265
|
+
<% if class_name == 'Organization' -%>
|
266
|
+
test "should block <%= singular_table_name %> creation even with invalid params" do
|
267
|
+
assert_no_difference('<%= class_name %>.count') do
|
268
|
+
post <%= api_route_helper %>_url,
|
269
|
+
params: { data: invalid_<%= singular_table_name %>_params },
|
270
|
+
headers: @auth_headers
|
271
|
+
end
|
272
|
+
|
273
|
+
assert_response :forbidden
|
274
|
+
|
275
|
+
response_body = JSON.parse(response.body)
|
276
|
+
assert_includes response_body.keys, 'error'
|
277
|
+
assert_includes response_body['message'], 'signup'
|
278
|
+
end
|
279
|
+
<% else -%>
|
198
280
|
test "should not create <%= singular_table_name %> with invalid params" do
|
199
281
|
assert_no_difference('<%= class_name %>.count') do
|
200
282
|
post <%= api_route_helper %>_url,
|
@@ -207,34 +289,118 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
207
289
|
response_body = JSON.parse(response.body)
|
208
290
|
assert_includes response_body.keys, 'errors'
|
209
291
|
end
|
292
|
+
<% end -%>
|
210
293
|
|
211
|
-
|
294
|
+
<% if class_name == 'Organization' -%>
|
295
|
+
test "should block <%= singular_table_name %> creation even without explicit IDs" do
|
212
296
|
params = valid_<%= singular_table_name %>_params
|
213
297
|
params.delete(:organization_id) # Don't send organization_id
|
214
298
|
params.delete(:user_id) # Don't send user_id
|
215
299
|
|
216
|
-
|
300
|
+
assert_no_difference('<%= class_name %>.count') do
|
217
301
|
post <%= api_route_helper %>_url,
|
218
302
|
params: { data: params },
|
219
303
|
headers: @auth_headers
|
220
304
|
end
|
221
305
|
|
222
|
-
assert_response :
|
306
|
+
assert_response :forbidden
|
307
|
+
end
|
308
|
+
<% else -%>
|
309
|
+
test "should handle tenancy context based on configuration" do
|
310
|
+
# Check current configuration
|
311
|
+
require_org_id = PropelAuthentication.configuration.require_organization_id
|
312
|
+
require_user_id = PropelAuthentication.configuration.require_user_id
|
313
|
+
<%
|
314
|
+
# Check attributes directly instead of database columns (more reliable during generation)
|
315
|
+
has_agency_id = attributes.any? { |attr| attr.name == 'agency' && attr.type == :references }
|
316
|
+
has_user_id = attributes.any? { |attr| attr.name == 'user' && attr.type == :references }
|
317
|
+
-%>
|
223
318
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
319
|
+
params = valid_<%= singular_table_name %>_params
|
320
|
+
params.delete(:organization_id) # Remove organization_id to test behavior
|
321
|
+
<% if has_user_id -%>
|
322
|
+
params.delete(:user_id) # Remove user_id to test behavior
|
323
|
+
<% end -%>
|
324
|
+
<% if has_agency_id -%>
|
325
|
+
params.delete(:agency_id) # Remove agency_id to test behavior
|
326
|
+
<% end -%>
|
327
|
+
|
328
|
+
if require_org_id<% if has_agency_id %> || true<% end -%> # Agency models always require strict validation
|
329
|
+
# Strict mode: Should fail validation due to missing required tenancy context
|
330
|
+
assert_no_difference('<%= class_name %>.count') do
|
331
|
+
post <%= api_route_helper %>_url,
|
332
|
+
params: { data: params },
|
333
|
+
headers: @auth_headers
|
334
|
+
end
|
335
|
+
|
336
|
+
assert_response :unprocessable_entity
|
337
|
+
|
338
|
+
# Should return validation errors for missing tenancy
|
339
|
+
error_response = JSON.parse(response.body)
|
340
|
+
|
341
|
+
if require_org_id
|
342
|
+
assert_includes error_response['errors'].keys, 'organization_id',
|
343
|
+
"Should require organization_id when require_organization_id = true"
|
344
|
+
end
|
345
|
+
<% if has_user_id -%>
|
346
|
+
if require_user_id
|
347
|
+
assert_includes error_response['errors'].keys, 'user_id',
|
348
|
+
"Should require user_id when require_user_id = true"
|
349
|
+
end
|
350
|
+
<% end -%>
|
351
|
+
<% if has_agency_id -%>
|
352
|
+
# Agency models always require agency_id (business rule)
|
353
|
+
assert_includes error_response['errors'].keys, 'agency_id',
|
354
|
+
"Should require agency_id for models with agency tenancy"
|
355
|
+
<% end -%>
|
356
|
+
else
|
357
|
+
# Auto-assignment mode: Should succeed with auto-assigned tenancy context
|
358
|
+
assert_difference('<%= class_name %>.count', 1) do
|
359
|
+
post <%= api_route_helper %>_url,
|
360
|
+
params: { data: params },
|
361
|
+
headers: @auth_headers
|
362
|
+
end
|
363
|
+
|
364
|
+
assert_response :created
|
365
|
+
|
366
|
+
# Should auto-assign missing tenancy context
|
367
|
+
created_response = JSON.parse(response.body)
|
368
|
+
created_<%= singular_table_name %> = created_response['data']
|
369
|
+
|
370
|
+
<% unless class_name == 'Organization' -%>
|
371
|
+
# Verify organization_id was auto-assigned
|
372
|
+
if created_<%= singular_table_name %>['organization']
|
373
|
+
assert_equal @user.organization.id, created_<%= singular_table_name %>['organization']['id'],
|
374
|
+
"Should auto-assign organization_id when require_organization_id = false"
|
375
|
+
elsif created_<%= singular_table_name %>['organization_id']
|
376
|
+
assert_equal @user.organization.id, created_<%= singular_table_name %>['organization_id'],
|
377
|
+
"Should auto-assign organization_id when require_organization_id = false"
|
378
|
+
end
|
379
|
+
<% end -%>
|
380
|
+
<% if has_user_id && class_name != 'User' -%>
|
381
|
+
# Verify user_id was auto-assigned (if not required to be explicit)
|
382
|
+
unless require_user_id
|
383
|
+
if created_<%= singular_table_name %>['user']
|
384
|
+
assert_equal @user.id, created_<%= singular_table_name %>['user']['id'],
|
385
|
+
"Should auto-assign user_id when require_user_id = false"
|
386
|
+
elsif created_<%= singular_table_name %>['user_id']
|
387
|
+
assert_equal @user.id, created_<%= singular_table_name %>['user_id'],
|
388
|
+
"Should auto-assign user_id when require_user_id = false"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
<% end -%>
|
392
|
+
end
|
228
393
|
end
|
394
|
+
<% end -%>
|
229
395
|
|
230
396
|
# === UPDATE TESTS ===
|
231
397
|
|
232
398
|
test "should update <%= singular_table_name %> with valid params" do
|
233
399
|
<% if attributes.any? { |attr| attr.type == :string && attr.name != "organization" && attr.name != "user" } -%>
|
234
400
|
<% string_attr = attributes.find { |attr| attr.type == :string && attr.name != "organization" && attr.name != "user" } -%>
|
235
|
-
new_<%= string_attr.name %> = "Updated <%= string_attr.name.humanize %>"
|
401
|
+
new_<%= string_attr.name %> = <% if string_attr.name.include?('email') %>"updated_<%= string_attr.name %>@example.com"<% else %>"Updated <%= string_attr.name.humanize %>"<% end %>
|
236
402
|
|
237
|
-
patch <%=
|
403
|
+
patch <%= api_singular_route_helper %>_url(@<%= singular_table_name %>),
|
238
404
|
params: { data: { <%= string_attr.name %>: new_<%= string_attr.name %> } },
|
239
405
|
headers: @auth_headers
|
240
406
|
|
@@ -244,7 +410,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
244
410
|
assert_equal new_<%= string_attr.name %>, @<%= singular_table_name %>.<%= string_attr.name %>
|
245
411
|
<% else -%>
|
246
412
|
# Update test for <%= singular_table_name %> - customize based on your model's attributes
|
247
|
-
patch <%=
|
413
|
+
patch <%= api_singular_route_helper %>_url(@<%= singular_table_name %>),
|
248
414
|
params: { data: valid_<%= singular_table_name %>_params },
|
249
415
|
headers: @auth_headers
|
250
416
|
|
@@ -253,7 +419,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
253
419
|
end
|
254
420
|
|
255
421
|
test "should not update <%= singular_table_name %> with invalid params" do
|
256
|
-
patch <%=
|
422
|
+
patch <%= api_singular_route_helper %>_url(@<%= singular_table_name %>),
|
257
423
|
params: { data: invalid_<%= singular_table_name %>_params },
|
258
424
|
headers: @auth_headers
|
259
425
|
|
@@ -266,6 +432,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
266
432
|
test "should not update <%= singular_table_name %> from different organization" do
|
267
433
|
other_org = Organization.create!(name: "Other Organization")
|
268
434
|
other_<%= singular_table_name %> = <%= class_name %>.create!(
|
435
|
+
|
269
436
|
<% attributes.each_with_index do |attribute, index| -%>
|
270
437
|
<% if attribute.name == "organization" && attribute.type == :references -%>
|
271
438
|
<%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
|
@@ -274,7 +441,13 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
274
441
|
<% elsif attribute.type == :references -%>
|
275
442
|
<%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
|
276
443
|
<% elsif attribute.type == :string -%>
|
444
|
+
<% if attribute.name.to_s.match?(/email/) -%>
|
445
|
+
<%= attribute.name %>: "other@example.com"<%= ',' if index < attributes.length - 1 %>
|
446
|
+
<% elsif attribute.name.to_s.match?(/password/) -%>
|
447
|
+
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
448
|
+
<% else -%>
|
277
449
|
<%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
450
|
+
<% end -%>
|
278
451
|
<% elsif attribute.type == :text -%>
|
279
452
|
<%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
|
280
453
|
<% elsif attribute.type == :integer -%>
|
@@ -283,13 +456,17 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
283
456
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
284
457
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
285
458
|
<%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
|
459
|
+
<% elsif attribute.type == :datetime -%>
|
460
|
+
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
461
|
+
<% elsif attribute.type == :json -%>
|
462
|
+
<%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
|
286
463
|
<% else -%>
|
287
464
|
<%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
|
288
465
|
<% end -%>
|
289
466
|
<% end -%>
|
290
467
|
)
|
291
468
|
|
292
|
-
patch <%=
|
469
|
+
patch <%= api_singular_route_helper %>_url(other_<%= singular_table_name %>),
|
293
470
|
params: { data: valid_<%= singular_table_name %>_params },
|
294
471
|
headers: @auth_headers
|
295
472
|
|
@@ -300,7 +477,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
300
477
|
|
301
478
|
test "should destroy <%= singular_table_name %>" do
|
302
479
|
assert_difference('<%= class_name %>.count', -1) do
|
303
|
-
delete <%=
|
480
|
+
delete <%= api_singular_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
|
304
481
|
end
|
305
482
|
|
306
483
|
assert_response :no_content
|
@@ -309,6 +486,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
309
486
|
test "should not destroy <%= singular_table_name %> from different organization" do
|
310
487
|
other_org = Organization.create!(name: "Other Organization")
|
311
488
|
other_<%= singular_table_name %> = <%= class_name %>.create!(
|
489
|
+
|
312
490
|
<% attributes.each_with_index do |attribute, index| -%>
|
313
491
|
<% if attribute.name == "organization" && attribute.type == :references -%>
|
314
492
|
<%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
|
@@ -317,7 +495,13 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
317
495
|
<% elsif attribute.type == :references -%>
|
318
496
|
<%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
|
319
497
|
<% elsif attribute.type == :string -%>
|
498
|
+
<% if attribute.name.to_s.match?(/email/) -%>
|
499
|
+
<%= attribute.name %>: "other@example.com"<%= ',' if index < attributes.length - 1 %>
|
500
|
+
<% elsif attribute.name.to_s.match?(/password/) -%>
|
501
|
+
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
502
|
+
<% else -%>
|
320
503
|
<%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
504
|
+
<% end -%>
|
321
505
|
<% elsif attribute.type == :text -%>
|
322
506
|
<%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
|
323
507
|
<% elsif attribute.type == :integer -%>
|
@@ -326,6 +510,10 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
326
510
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
327
511
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
328
512
|
<%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
|
513
|
+
<% elsif attribute.type == :datetime -%>
|
514
|
+
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
515
|
+
<% elsif attribute.type == :json -%>
|
516
|
+
<%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
|
329
517
|
<% else -%>
|
330
518
|
<%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
|
331
519
|
<% end -%>
|
@@ -333,7 +521,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
333
521
|
)
|
334
522
|
|
335
523
|
assert_no_difference('<%= class_name %>.count') do
|
336
|
-
delete <%=
|
524
|
+
delete <%= api_singular_route_helper %>_url(other_<%= singular_table_name %>), headers: @auth_headers
|
337
525
|
end
|
338
526
|
|
339
527
|
assert_response :not_found
|
@@ -341,6 +529,18 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
341
529
|
|
342
530
|
# === PARAMETER HANDLING TESTS ===
|
343
531
|
|
532
|
+
<% if class_name == 'Organization' -%>
|
533
|
+
test "should reject <%= singular_table_name %> creation with proper error structure" do
|
534
|
+
post <%= api_route_helper %>_url,
|
535
|
+
params: { data: valid_<%= singular_table_name %>_params },
|
536
|
+
headers: @auth_headers
|
537
|
+
|
538
|
+
assert_response :forbidden
|
539
|
+
response_body = JSON.parse(response.body)
|
540
|
+
assert_includes response_body.keys, 'code'
|
541
|
+
assert_equal 'ORGANIZATION_CREATION_BLOCKED', response_body['code']
|
542
|
+
end
|
543
|
+
<% else -%>
|
344
544
|
test "should accept valid data structure" do
|
345
545
|
post <%= api_route_helper %>_url,
|
346
546
|
params: { data: valid_<%= singular_table_name %>_params },
|
@@ -348,15 +548,40 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
348
548
|
|
349
549
|
assert_response :created
|
350
550
|
end
|
551
|
+
<% end -%>
|
351
552
|
|
553
|
+
<% if class_name == 'Organization' -%>
|
554
|
+
test "should block <%= singular_table_name %> creation regardless of data wrapper" do
|
555
|
+
post <%= api_route_helper %>_url,
|
556
|
+
params: valid_<%= singular_table_name %>_params, # No data wrapper
|
557
|
+
headers: @auth_headers
|
558
|
+
|
559
|
+
assert_response :forbidden
|
560
|
+
end
|
561
|
+
<% else -%>
|
352
562
|
test "should reject params without data wrapper" do
|
353
563
|
post <%= api_route_helper %>_url,
|
354
564
|
params: valid_<%= singular_table_name %>_params, # No data wrapper
|
355
565
|
headers: @auth_headers
|
356
566
|
|
357
|
-
assert_response :
|
567
|
+
assert_response :bad_request
|
358
568
|
end
|
569
|
+
<% end -%>
|
359
570
|
|
571
|
+
<% if class_name == 'Organization' -%>
|
572
|
+
test "should block <%= singular_table_name %> creation regardless of parameter filtering" do
|
573
|
+
params_with_extra = valid_<%= singular_table_name %>_params.merge(
|
574
|
+
forbidden_field: "should_be_ignored",
|
575
|
+
admin_only_field: true
|
576
|
+
)
|
577
|
+
|
578
|
+
post <%= api_route_helper %>_url,
|
579
|
+
params: { data: params_with_extra },
|
580
|
+
headers: @auth_headers
|
581
|
+
|
582
|
+
assert_response :forbidden
|
583
|
+
end
|
584
|
+
<% else -%>
|
360
585
|
test "should filter permitted params only" do
|
361
586
|
params_with_extra = valid_<%= singular_table_name %>_params.merge(
|
362
587
|
forbidden_field: "should_be_ignored",
|
@@ -373,6 +598,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
373
598
|
created_<%= singular_table_name %> = <%= class_name %>.last
|
374
599
|
assert_not created_<%= singular_table_name %>.respond_to?(:forbidden_field)
|
375
600
|
end
|
601
|
+
<% end -%>
|
376
602
|
|
377
603
|
# === JSON FACET RESPONSE TESTS ===
|
378
604
|
|
@@ -404,7 +630,7 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
404
630
|
end
|
405
631
|
|
406
632
|
test "show should return details facet data" do
|
407
|
-
get <%=
|
633
|
+
get <%= api_singular_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
|
408
634
|
assert_response :success
|
409
635
|
|
410
636
|
response_body = JSON.parse(response.body)
|
@@ -431,20 +657,35 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
431
657
|
|
432
658
|
def valid_<%= singular_table_name %>_params
|
433
659
|
{
|
660
|
+
<%
|
661
|
+
# Get list of reference attribute names to avoid duplicating them as string attributes
|
662
|
+
reference_names = attributes.select { |attr| attr.type == :references }.map(&:name)
|
663
|
+
-%>
|
664
|
+
|
434
665
|
<% attributes.each_with_index do |attribute, index| -%>
|
435
666
|
<% if attribute.type == :references -%>
|
436
667
|
<%= attribute.name %>_id: @<%= attribute.name %>.id<%= ',' if index < attributes.length - 1 %>
|
437
|
-
<% elsif attribute.type == :string -%>
|
668
|
+
<% elsif attribute.type == :string && !reference_names.include?(attribute.name) -%>
|
669
|
+
<% if attribute.name.to_s.match?(/email/) -%>
|
670
|
+
<%= attribute.name %>: "test@example.com"<%= ',' if index < attributes.length - 1 %>
|
671
|
+
<% elsif attribute.name.to_s.match?(/password/) -%>
|
672
|
+
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
673
|
+
<% else -%>
|
438
674
|
<%= attribute.name %>: "Test <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
439
|
-
<%
|
675
|
+
<% end -%>
|
676
|
+
<% elsif attribute.type == :text && !reference_names.include?(attribute.name) -%>
|
440
677
|
<%= attribute.name %>: "Test <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
|
441
|
-
<% elsif attribute.type == :integer -%>
|
678
|
+
<% elsif attribute.type == :integer && !reference_names.include?(attribute.name) -%>
|
442
679
|
<%= attribute.name %>: 42<%= ',' if index < attributes.length - 1 %>
|
443
|
-
<% elsif attribute.type == :boolean -%>
|
680
|
+
<% elsif attribute.type == :boolean && !reference_names.include?(attribute.name) -%>
|
444
681
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
445
682
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
446
683
|
<%= attribute.name %>: 123.45<%= ',' if index < attributes.length - 1 %>
|
447
|
-
<%
|
684
|
+
<% elsif attribute.type == :datetime -%>
|
685
|
+
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
686
|
+
<% elsif attribute.type == :json -%>
|
687
|
+
<%= attribute.name %>: {}<%= ',' if index < attributes.length - 1 %>
|
688
|
+
<% elsif !reference_names.include?(attribute.name) -%>
|
448
689
|
<%= attribute.name %>: "test_value"<%= ',' if index < attributes.length - 1 %>
|
449
690
|
<% end -%>
|
450
691
|
<% end -%>
|
@@ -475,6 +716,8 @@ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch
|
|
475
716
|
<%= attribute.name %>: "not_a_number"<%= ',' if index < attributes.length - 1 %>
|
476
717
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
477
718
|
<%= attribute.name %>: "not_a_number"<%= ',' if index < attributes.length - 1 %>
|
719
|
+
<% elsif attribute.type == :references -%>
|
720
|
+
<%= reference_names.include?(attribute.name) ? "#{attribute.name}_id" : attribute.name %>: nil<%= ',' if index < attributes.length - 1 %>
|
478
721
|
<% else -%>
|
479
722
|
<%= attribute.name %>: ""<%= ',' if index < attributes.length - 1 %>
|
480
723
|
<% end -%>
|
@@ -7,6 +7,8 @@ one:
|
|
7
7
|
<%= attribute.name %>: acme_org
|
8
8
|
<% elsif attribute.name == 'user' -%>
|
9
9
|
<%= attribute.name %>: john_user
|
10
|
+
<% elsif attribute.name == 'agency' -%>
|
11
|
+
<%= attribute.name %>: marketing_agency
|
10
12
|
<% else -%>
|
11
13
|
<%= attribute.name %>: one
|
12
14
|
<% end -%>
|
@@ -78,6 +80,14 @@ one:
|
|
78
80
|
<%= attribute.name %>: "2024-06-15 10:30:00"
|
79
81
|
<% elsif attribute.type == :time -%>
|
80
82
|
<%= attribute.name %>: "10:30:00"
|
83
|
+
<% elsif attribute.type == :json || attribute.name.to_s.match?(/^(meta|settings)$/) -%>
|
84
|
+
<% if attribute.name == 'meta' -%>
|
85
|
+
<%= attribute.name %>: { fixture_meta: "test_one", environment: "test", record_type: "<%= singular_table_name %>" }
|
86
|
+
<% elsif attribute.name == 'settings' -%>
|
87
|
+
<%= attribute.name %>: { dark_mode: false, money_format: "usd", language: "en", test_mode: true }
|
88
|
+
<% else -%>
|
89
|
+
<%= attribute.name %>: { test_data: "fixture_one" }
|
90
|
+
<% end -%>
|
81
91
|
<% else -%>
|
82
92
|
<%= attribute.name %>: "test_value_one"
|
83
93
|
<% end -%>
|
@@ -90,6 +100,8 @@ two:
|
|
90
100
|
<%= attribute.name %>: tech_startup
|
91
101
|
<% elsif attribute.name == 'user' -%>
|
92
102
|
<%= attribute.name %>: jane_user
|
103
|
+
<% elsif attribute.name == 'agency' -%>
|
104
|
+
<%= attribute.name %>: tech_agency
|
93
105
|
<% else -%>
|
94
106
|
<%= attribute.name %>: one
|
95
107
|
<% end -%>
|
@@ -161,6 +173,14 @@ two:
|
|
161
173
|
<%= attribute.name %>: "2023-12-25 15:45:00"
|
162
174
|
<% elsif attribute.type == :time -%>
|
163
175
|
<%= attribute.name %>: "15:45:00"
|
176
|
+
<% elsif attribute.type == :json || attribute.name.to_s.match?(/^(meta|settings)$/) -%>
|
177
|
+
<% if attribute.name == 'meta' -%>
|
178
|
+
<%= attribute.name %>: { fixture_meta: "test_two", environment: "test", record_type: "<%= singular_table_name %>" }
|
179
|
+
<% elsif attribute.name == 'settings' -%>
|
180
|
+
<%= attribute.name %>: { dark_mode: true, money_format: "eur", language: "fr", test_mode: true }
|
181
|
+
<% else -%>
|
182
|
+
<%= attribute.name %>: { test_data: "fixture_two" }
|
183
|
+
<% end -%>
|
164
184
|
<% else -%>
|
165
185
|
<%= attribute.name %>: "test_value_two"
|
166
186
|
<% end -%>
|
@@ -173,6 +193,8 @@ three:
|
|
173
193
|
<%= attribute.name %>: acme_org
|
174
194
|
<% elsif attribute.name == 'user' -%>
|
175
195
|
<%= attribute.name %>: confirmed_user
|
196
|
+
<% elsif attribute.name == 'agency' -%>
|
197
|
+
<%= attribute.name %>: sales_agency
|
176
198
|
<% else -%>
|
177
199
|
<%= attribute.name %>: one
|
178
200
|
<% end -%>
|
@@ -244,6 +266,14 @@ three:
|
|
244
266
|
<%= attribute.name %>: "2025-03-10 08:15:00"
|
245
267
|
<% elsif attribute.type == :time -%>
|
246
268
|
<%= attribute.name %>: "08:15:00"
|
269
|
+
<% elsif attribute.type == :json || attribute.name.to_s.match?(/^(meta|settings)$/) -%>
|
270
|
+
<% if attribute.name == 'meta' -%>
|
271
|
+
<%= attribute.name %>: { fixture_meta: "test_three", environment: "test", record_type: "<%= singular_table_name %>" }
|
272
|
+
<% elsif attribute.name == 'settings' -%>
|
273
|
+
<%= attribute.name %>: { dark_mode: true, money_format: "gbp", language: "es", test_mode: true }
|
274
|
+
<% else -%>
|
275
|
+
<%= attribute.name %>: { test_data: "fixture_three" }
|
276
|
+
<% end -%>
|
247
277
|
<% else -%>
|
248
278
|
<%= attribute.name %>: "test_value_three"
|
249
279
|
<% end -%>
|