propel_api 0.1.4 → 0.2.1

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.
@@ -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 <%= api_route_helper %>_url(@<%= singular_table_name %>)
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 <%= api_route_helper %>_url(@<%= singular_table_name %>), params: { data: { title: "Updated" } }
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 <%= api_route_helper %>_url(@<%= singular_table_name %>)
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, 'page'
83
- assert_includes pagination.keys, 'items'
84
- assert_includes pagination.keys, 'count'
85
- assert_includes pagination.keys, 'pages'
86
- assert_includes pagination.keys, 'last'
87
- assert_includes pagination.keys, 'next'
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 <%= api_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
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 <%= api_route_helper %>_url(0), headers: @auth_headers
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 <%= api_route_helper %>_url(other_<%= singular_table_name %>), headers: @auth_headers
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
- assert_equal @organization.id, created_<%= singular_table_name %>['organization']['id']
195
- assert_equal @user.id, created_<%= singular_table_name %>['user']['id']
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
- test "should auto-assign organization and user on create" do
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
- assert_difference('<%= class_name %>.count', 1) do
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 :created
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
- # Should automatically assign current user's organization and user
225
- created_<%= singular_table_name %> = <%= class_name %>.last
226
- assert_equal @organization.id, created_<%= singular_table_name %>.organization_id
227
- assert_equal @user.id, created_<%= singular_table_name %>.user_id
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 <%= api_route_helper %>_url(@<%= singular_table_name %>),
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 <%= api_route_helper %>_url(@<%= singular_table_name %>),
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 <%= api_route_helper %>_url(@<%= singular_table_name %>),
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 <%= api_route_helper %>_url(other_<%= singular_table_name %>),
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 <%= api_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
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 <%= api_route_helper %>_url(other_<%= singular_table_name %>), headers: @auth_headers
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 :unprocessable_entity
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 <%= api_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
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
- <% elsif attribute.type == :text -%>
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
- <% else -%>
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 -%>