propel_api 0.3.2 → 0.3.3
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 +60 -0
- data/README.md +46 -1
- data/lib/generators/propel_api/core/named_base.rb +47 -76
- data/lib/generators/propel_api/install/install_generator.rb +43 -2
- data/lib/generators/propel_api/templates/concerns/propel_controller_filters_concern.rb +141 -0
- data/lib/generators/propel_api/templates/concerns/propel_model_filters_concern.rb +128 -0
- data/lib/generators/propel_api/templates/controllers/api_controller_propel_facets.rb +1 -0
- data/lib/generators/propel_api/templates/lib/XX_dynamic_scope_generator.rb +360 -0
- data/lib/generators/propel_api/templates/lib/propel_dynamic_scope_generator.rb +474 -0
- data/lib/generators/propel_api/templates/lib/propel_filter_operators.rb +16 -0
- data/lib/generators/propel_api/templates/scaffold/facet_model_template.rb.tt +14 -0
- data/lib/generators/propel_api/templates/seeds/seeds_template.rb.tt +100 -6
- data/lib/generators/propel_api/templates/tests/controller_test_template.rb.tt +9 -0
- data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +660 -10
- data/lib/generators/propel_api/templates/tests/model_test_template.rb.tt +7 -0
- data/lib/propel_api.rb +1 -1
- metadata +11 -5
@@ -114,7 +114,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
114
114
|
<% elsif attribute.name.to_s.match?(/password/) -%>
|
115
115
|
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
116
116
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
117
|
-
<%= attribute.name %>: "https://workflow.
|
117
|
+
<%= attribute.name %>: "https://workflow.com"<%= ',' if index < attributes.length - 1 %>
|
118
118
|
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
119
119
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
120
120
|
<% else -%>
|
@@ -205,7 +205,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
205
205
|
# Password fields should NOT be returned in API responses for security
|
206
206
|
assert_not_includes created_<%= singular_table_name %>.keys, '<%= attribute.name %>', "Password fields should be filtered from API responses"
|
207
207
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
208
|
-
assert_equal "https://workflow.
|
208
|
+
assert_equal "https://workflow.com", created_<%= singular_table_name %>['<%= attribute.name %>']
|
209
209
|
<% else -%>
|
210
210
|
assert_equal "Workflow Test <%= attribute.name.humanize %>", created_<%= singular_table_name %>['<%= attribute.name %>']
|
211
211
|
<% end -%>
|
@@ -408,7 +408,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
408
408
|
<% elsif attribute.name.include?('email') -%>
|
409
409
|
<%= attribute.name %>: "pagination#{i}@example.com"<%= ',' if index < attributes.length - 1 %>
|
410
410
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
411
|
-
<%= attribute.name %>: "https://pagination#{i}.
|
411
|
+
<%= attribute.name %>: "https://pagination#{i}.com"<%= ',' if index < attributes.length - 1 %>
|
412
412
|
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
413
413
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
414
414
|
<% else -%>
|
@@ -460,6 +460,589 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
460
460
|
end
|
461
461
|
<% end -%>
|
462
462
|
|
463
|
+
# === FILTERING AND SORTING TESTS ===
|
464
|
+
|
465
|
+
<% # Generate filtering tests only if we have filterable attributes -%>
|
466
|
+
<% filterable_attributes = attributes.reject { |attr|
|
467
|
+
attr.name.match?(/password|token|secret|key|salt|encrypted|digest|hash|auth/i) ||
|
468
|
+
attr.name.match?(/_at$/) ||
|
469
|
+
attr.name.match?(/_id$/) ||
|
470
|
+
attr.type == :references
|
471
|
+
} -%>
|
472
|
+
<% if filterable_attributes.any? -%>
|
473
|
+
test "basic field filtering" do
|
474
|
+
<% if class_name == 'Organization' -%>
|
475
|
+
# Test against existing fixture data (acme_org)
|
476
|
+
# The API only returns the current user's organization due to multi-tenancy
|
477
|
+
|
478
|
+
# Test exact match filtering against fixture data
|
479
|
+
get <%= api_route_helper %>_url,
|
480
|
+
params: { name_eq: "Acme Corporation" },
|
481
|
+
headers: @auth_headers
|
482
|
+
assert_response :success
|
483
|
+
|
484
|
+
exact_response = JSON.parse(response.body)
|
485
|
+
assert_equal 1, exact_response['data'].size, "Should find exactly 1 organization with name = 'Acme Corporation'"
|
486
|
+
assert_equal "Acme Corporation", exact_response['data'][0]['name'], "Should return the correct record"
|
487
|
+
|
488
|
+
# Test contains filtering against fixture data
|
489
|
+
get <%= api_route_helper %>_url,
|
490
|
+
params: { name_contains: "Acme" },
|
491
|
+
headers: @auth_headers
|
492
|
+
assert_response :success
|
493
|
+
|
494
|
+
contains_response = JSON.parse(response.body)
|
495
|
+
assert_equal 1, contains_response['data'].size, "Should find exactly 1 organization containing 'Acme'"
|
496
|
+
assert_equal "Acme Corporation", contains_response['data'][0]['name']
|
497
|
+
|
498
|
+
# Test starts_with filtering
|
499
|
+
get <%= api_route_helper %>_url,
|
500
|
+
params: { name_starts_with: "Acme" },
|
501
|
+
headers: @auth_headers
|
502
|
+
assert_response :success
|
503
|
+
|
504
|
+
starts_response = JSON.parse(response.body)
|
505
|
+
assert_equal 1, starts_response['data'].size, "Should find exactly 1 organization starting with 'Acme'"
|
506
|
+
assert_equal "Acme Corporation", starts_response['data'][0]['name']
|
507
|
+
|
508
|
+
# Test ends_with filtering
|
509
|
+
get <%= api_route_helper %>_url,
|
510
|
+
params: { name_ends_with: "Corporation" },
|
511
|
+
headers: @auth_headers
|
512
|
+
assert_response :success
|
513
|
+
|
514
|
+
ends_response = JSON.parse(response.body)
|
515
|
+
assert_equal 1, ends_response['data'].size, "Should find exactly 1 organization ending with 'Corporation'"
|
516
|
+
assert_equal "Acme Corporation", ends_response['data'][0]['name']
|
517
|
+
|
518
|
+
# Test 'in' filtering
|
519
|
+
get <%= api_route_helper %>_url,
|
520
|
+
params: { name_in: "Acme Corporation" },
|
521
|
+
headers: @auth_headers
|
522
|
+
assert_response :success
|
523
|
+
|
524
|
+
in_response = JSON.parse(response.body)
|
525
|
+
assert_equal 1, in_response['data'].size, "Should find exactly 1 organization with name in list"
|
526
|
+
returned_names = in_response['data'].map { |item| item['name'] }
|
527
|
+
assert_equal ["Acme Corporation"], returned_names, "Should return the correct record"
|
528
|
+
<% else -%>
|
529
|
+
# Create test data with known values for filtering
|
530
|
+
<% filterable_attributes.select { |attr| [:string, :text].include?(attr.type) }.first(1).each do |attr| -%>
|
531
|
+
<% if attr.name.match?(/email|mail/i) -%>
|
532
|
+
<%= singular_table_name %>_1 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": "green_apple_test@example.com")
|
533
|
+
<%= singular_table_name %>_2 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": "black_cherry_test@example.com")
|
534
|
+
<%= singular_table_name %>_3 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": "red_grape_test@example.com")
|
535
|
+
<% else -%>
|
536
|
+
<%= singular_table_name %>_1 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": "Green Apple")
|
537
|
+
<%= singular_table_name %>_2 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": "Black Cherry")
|
538
|
+
<%= singular_table_name %>_3 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": "Red Grape")
|
539
|
+
<% end -%>
|
540
|
+
|
541
|
+
# Test exact match filtering
|
542
|
+
<% if attr.name.match?(/email|mail/i) -%>
|
543
|
+
get <%= api_route_helper %>_url,
|
544
|
+
params: { <%= attr.name %>_eq: "green_apple_test@example.com" },
|
545
|
+
headers: @auth_headers
|
546
|
+
assert_response :success
|
547
|
+
|
548
|
+
exact_response = JSON.parse(response.body)
|
549
|
+
assert_equal 1, exact_response['data'].size, "Should find exactly 1 <%= singular_table_name %> with <%= attr.name %> = 'green_apple_test@example.com'"
|
550
|
+
assert_equal "green_apple_test@example.com", exact_response['data'][0]['<%= attr.name %>'], "Should return the correct record"
|
551
|
+
<% else -%>
|
552
|
+
get <%= api_route_helper %>_url,
|
553
|
+
params: { <%= attr.name %>_eq: "Green Apple" },
|
554
|
+
headers: @auth_headers
|
555
|
+
assert_response :success
|
556
|
+
|
557
|
+
exact_response = JSON.parse(response.body)
|
558
|
+
assert_equal 1, exact_response['data'].size, "Should find exactly 1 <%= singular_table_name %> with <%= attr.name %> = 'Green Apple'"
|
559
|
+
assert_equal "Green Apple", exact_response['data'][0]['<%= attr.name %>'], "Should return the correct record"
|
560
|
+
<% end -%>
|
561
|
+
|
562
|
+
# Test contains filtering
|
563
|
+
<% if attr.name.match?(/email|mail/i) -%>
|
564
|
+
get <%= api_route_helper %>_url,
|
565
|
+
params: { <%= attr.name %>_contains: "apple" },
|
566
|
+
headers: @auth_headers
|
567
|
+
assert_response :success
|
568
|
+
|
569
|
+
contains_response = JSON.parse(response.body)
|
570
|
+
assert_equal 1, contains_response['data'].size, "Should find exactly 1 <%= singular_table_name %> containing 'apple'"
|
571
|
+
assert_equal "green_apple_test@example.com", contains_response['data'][0]['<%= attr.name %>']
|
572
|
+
<% else -%>
|
573
|
+
get <%= api_route_helper %>_url,
|
574
|
+
params: { <%= attr.name %>_contains: "Apple" },
|
575
|
+
headers: @auth_headers
|
576
|
+
assert_response :success
|
577
|
+
|
578
|
+
contains_response = JSON.parse(response.body)
|
579
|
+
assert_equal 1, contains_response['data'].size, "Should find exactly 1 <%= singular_table_name %> containing 'Apple'"
|
580
|
+
assert_equal "Green Apple", contains_response['data'][0]['<%= attr.name %>']
|
581
|
+
<% end -%>
|
582
|
+
|
583
|
+
# Test starts_with filtering
|
584
|
+
<% if attr.name.match?(/email|mail/i) -%>
|
585
|
+
get <%= api_route_helper %>_url,
|
586
|
+
params: { <%= attr.name %>_starts_with: "black" },
|
587
|
+
headers: @auth_headers
|
588
|
+
assert_response :success
|
589
|
+
|
590
|
+
starts_response = JSON.parse(response.body)
|
591
|
+
assert_equal 1, starts_response['data'].size, "Should find exactly 1 <%= singular_table_name %> starting with 'black'"
|
592
|
+
assert_equal "black_cherry_test@example.com", starts_response['data'][0]['<%= attr.name %>']
|
593
|
+
<% else -%>
|
594
|
+
get <%= api_route_helper %>_url,
|
595
|
+
params: { <%= attr.name %>_starts_with: "Black" },
|
596
|
+
headers: @auth_headers
|
597
|
+
assert_response :success
|
598
|
+
|
599
|
+
starts_response = JSON.parse(response.body)
|
600
|
+
assert_equal 1, starts_response['data'].size, "Should find exactly 1 <%= singular_table_name %> starting with 'Black'"
|
601
|
+
assert_equal "Black Cherry", starts_response['data'][0]['<%= attr.name %>']
|
602
|
+
<% end -%>
|
603
|
+
|
604
|
+
# Test ends_with filtering
|
605
|
+
<% if attr.name.match?(/email|mail/i) -%>
|
606
|
+
get <%= api_route_helper %>_url,
|
607
|
+
params: { <%= attr.name %>_ends_with: "test@example.com" },
|
608
|
+
headers: @auth_headers
|
609
|
+
assert_response :success
|
610
|
+
|
611
|
+
ends_response = JSON.parse(response.body)
|
612
|
+
assert_equal 3, ends_response['data'].size, "Should find exactly 3 <%= table_name %> ending with 'test@example.com'"
|
613
|
+
# All three test records end with test@example.com
|
614
|
+
<% else -%>
|
615
|
+
get <%= api_route_helper %>_url,
|
616
|
+
params: { <%= attr.name %>_ends_with: "Grape" },
|
617
|
+
headers: @auth_headers
|
618
|
+
assert_response :success
|
619
|
+
|
620
|
+
ends_response = JSON.parse(response.body)
|
621
|
+
assert_equal 1, ends_response['data'].size, "Should find exactly 1 <%= singular_table_name %> ending with 'Grape'"
|
622
|
+
assert_equal "Red Grape", ends_response['data'][0]['<%= attr.name %>']
|
623
|
+
<% end -%>
|
624
|
+
|
625
|
+
# Test 'in' filtering
|
626
|
+
<% if attr.name.match?(/email|mail/i) -%>
|
627
|
+
get <%= api_route_helper %>_url,
|
628
|
+
params: { <%= attr.name %>_in: "green_apple_test@example.com,black_cherry_test@example.com" },
|
629
|
+
headers: @auth_headers
|
630
|
+
assert_response :success
|
631
|
+
|
632
|
+
in_response = JSON.parse(response.body)
|
633
|
+
assert_equal 2, in_response['data'].size, "Should find exactly 2 <%= table_name %> with <%= attr.name %> in list"
|
634
|
+
returned_<%= attr.name.pluralize %> = in_response['data'].map { |item| item['<%= attr.name %>'] }.sort
|
635
|
+
assert_equal ["black_cherry_test@example.com", "green_apple_test@example.com"], returned_<%= attr.name.pluralize %>, "Should return the correct records"
|
636
|
+
<% else -%>
|
637
|
+
get <%= api_route_helper %>_url,
|
638
|
+
params: { <%= attr.name %>_in: "Green Apple,Black Cherry" },
|
639
|
+
headers: @auth_headers
|
640
|
+
assert_response :success
|
641
|
+
|
642
|
+
in_response = JSON.parse(response.body)
|
643
|
+
assert_equal 2, in_response['data'].size, "Should find exactly 2 <%= table_name %> with <%= attr.name %> in list"
|
644
|
+
returned_<%= attr.name.pluralize %> = in_response['data'].map { |item| item['<%= attr.name %>'] }.sort
|
645
|
+
assert_equal ["Black Cherry", "Green Apple"], returned_<%= attr.name.pluralize %>, "Should return the correct records"
|
646
|
+
<% end -%>
|
647
|
+
|
648
|
+
# Clean up test data to avoid interference with other tests
|
649
|
+
[<%= singular_table_name %>_1, <%= singular_table_name %>_2, <%= singular_table_name %>_3].each do |record|
|
650
|
+
record.destroy if record.persisted?
|
651
|
+
end
|
652
|
+
<% end -%>
|
653
|
+
<% end -%>
|
654
|
+
end
|
655
|
+
<% end -%>
|
656
|
+
|
657
|
+
<% # Test numeric filtering if we have numeric attributes -%>
|
658
|
+
<% numeric_attributes = filterable_attributes.select { |attr| [:integer, :decimal, :float].include?(attr.type) } -%>
|
659
|
+
<% if numeric_attributes.any? -%>
|
660
|
+
test "numeric field filtering" do
|
661
|
+
<% numeric_attributes.first(1).each do |attr| -%>
|
662
|
+
# Create test data with known numeric values that don't overlap with fixtures
|
663
|
+
# Fixtures typically have values 1, 2, 3 - we use 100, 200, 300, 400 to avoid conflicts
|
664
|
+
unique_id = SecureRandom.hex(4)
|
665
|
+
<%= singular_table_name %>_1 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": 100)
|
666
|
+
<%= singular_table_name %>_2 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": 200)
|
667
|
+
<%= singular_table_name %>_3 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": 300)
|
668
|
+
<%= singular_table_name %>_4 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": 400)
|
669
|
+
|
670
|
+
# Test greater than
|
671
|
+
get <%= api_route_helper %>_url,
|
672
|
+
params: { <%= attr.name %>_gt: "250" },
|
673
|
+
headers: @auth_headers
|
674
|
+
assert_response :success
|
675
|
+
|
676
|
+
gt_response = JSON.parse(response.body)
|
677
|
+
# Filter for only our test records to avoid fixture interference
|
678
|
+
test_ids = [<%= singular_table_name %>_1.id, <%= singular_table_name %>_2.id, <%= singular_table_name %>_3.id, <%= singular_table_name %>_4.id]
|
679
|
+
test_records_gt = gt_response['data'].select { |item| test_ids.include?(item['id']) }
|
680
|
+
assert_equal 2, test_records_gt.size, "Should find exactly 2 test <%= table_name %> with <%= attr.name %> > 250"
|
681
|
+
gt_values = test_records_gt.map { |item| item['<%= attr.name %>'] }.sort
|
682
|
+
<% if attr.type == :decimal || attr.type == :float -%>
|
683
|
+
# Rails serializes decimal/float fields as strings in JSON to preserve precision
|
684
|
+
assert_equal ["300.0", "400.0"], gt_values, "Should return test records with <%= attr.name %> > 250 (as strings)"
|
685
|
+
<% else -%>
|
686
|
+
assert_equal [300, 400], gt_values, "Should return test records with <%= attr.name %> > 250"
|
687
|
+
<% end -%>
|
688
|
+
|
689
|
+
# Test less than or equal
|
690
|
+
get <%= api_route_helper %>_url,
|
691
|
+
params: { <%= attr.name %>_lte: "250" },
|
692
|
+
headers: @auth_headers
|
693
|
+
assert_response :success
|
694
|
+
|
695
|
+
lte_response = JSON.parse(response.body)
|
696
|
+
# Filter for only our test records to avoid fixture interference
|
697
|
+
test_records_lte = lte_response['data'].select { |item| test_ids.include?(item['id']) }
|
698
|
+
assert_equal 2, test_records_lte.size, "Should find exactly 2 test <%= table_name %> with <%= attr.name %> <= 250"
|
699
|
+
lte_values = test_records_lte.map { |item| item['<%= attr.name %>'] }.sort
|
700
|
+
<% if attr.type == :decimal || attr.type == :float -%>
|
701
|
+
# Rails serializes decimal/float fields as strings in JSON to preserve precision
|
702
|
+
assert_equal ["100.0", "200.0"], lte_values, "Should return test records with <%= attr.name %> <= 250 (as strings)"
|
703
|
+
<% else -%>
|
704
|
+
assert_equal [100, 200], lte_values, "Should return test records with <%= attr.name %> <= 250"
|
705
|
+
<% end -%>
|
706
|
+
|
707
|
+
# Test range filtering
|
708
|
+
get <%= api_route_helper %>_url,
|
709
|
+
params: { <%= attr.name %>_range: "150,350" },
|
710
|
+
headers: @auth_headers
|
711
|
+
assert_response :success
|
712
|
+
|
713
|
+
range_response = JSON.parse(response.body)
|
714
|
+
# Filter for only our test records to avoid fixture interference
|
715
|
+
test_records_range = range_response['data'].select { |item| test_ids.include?(item['id']) }
|
716
|
+
assert_equal 2, test_records_range.size, "Should find exactly 2 test <%= table_name %> with <%= attr.name %> between 150 and 350"
|
717
|
+
range_values = test_records_range.map { |item| item['<%= attr.name %>'] }.sort
|
718
|
+
<% if attr.type == :decimal || attr.type == :float -%>
|
719
|
+
# Rails serializes decimal/float fields as strings in JSON to preserve precision
|
720
|
+
assert_equal ["200.0", "300.0"], range_values, "Should return test records with <%= attr.name %> in range 150-350 (as strings)"
|
721
|
+
<% else -%>
|
722
|
+
assert_equal [200, 300], range_values, "Should return test records with <%= attr.name %> in range 150-350"
|
723
|
+
<% end -%>
|
724
|
+
|
725
|
+
# Test 'in' filtering for numeric values
|
726
|
+
get <%= api_route_helper %>_url,
|
727
|
+
params: { <%= attr.name %>_in: "100,300,999" },
|
728
|
+
headers: @auth_headers
|
729
|
+
assert_response :success
|
730
|
+
|
731
|
+
in_response = JSON.parse(response.body)
|
732
|
+
# Filter for only our test records to avoid fixture interference
|
733
|
+
test_records_in = in_response['data'].select { |item| test_ids.include?(item['id']) }
|
734
|
+
assert_equal 2, test_records_in.size, "Should find exactly 2 test <%= table_name %> with <%= attr.name %> in [100,300,999]"
|
735
|
+
in_values = test_records_in.map { |item| item['<%= attr.name %>'] }.sort
|
736
|
+
<% if attr.type == :decimal || attr.type == :float -%>
|
737
|
+
# Rails serializes decimal/float fields as strings in JSON to preserve precision
|
738
|
+
assert_equal ["100.0", "300.0"], in_values, "Should return test records with <%= attr.name %> in list (as strings)"
|
739
|
+
<% else -%>
|
740
|
+
assert_equal [100, 300], in_values, "Should return test records with <%= attr.name %> in list"
|
741
|
+
<% end -%>
|
742
|
+
|
743
|
+
# Clean up test data to avoid interference with other tests
|
744
|
+
[<%= singular_table_name %>_1, <%= singular_table_name %>_2, <%= singular_table_name %>_3, <%= singular_table_name %>_4].each do |record|
|
745
|
+
record.destroy if record.persisted?
|
746
|
+
end
|
747
|
+
<% end -%>
|
748
|
+
end
|
749
|
+
<% end -%>
|
750
|
+
|
751
|
+
<% # Test boolean filtering if we have boolean attributes -%>
|
752
|
+
<% boolean_attributes = filterable_attributes.select { |attr| attr.type == :boolean } -%>
|
753
|
+
<% if boolean_attributes.any? -%>
|
754
|
+
test "boolean field filtering" do
|
755
|
+
<% boolean_attributes.first(1).each do |attr| -%>
|
756
|
+
# Create test data with known boolean values
|
757
|
+
<%= singular_table_name %>_true = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": true)
|
758
|
+
<%= singular_table_name %>_false = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": false)
|
759
|
+
|
760
|
+
# Test filtering for true values
|
761
|
+
get <%= api_route_helper %>_url,
|
762
|
+
params: { <%= attr.name %>_eq: "true" },
|
763
|
+
headers: @auth_headers
|
764
|
+
assert_response :success
|
765
|
+
|
766
|
+
true_response = JSON.parse(response.body)
|
767
|
+
# Filter for only our test records to avoid fixture interference
|
768
|
+
test_ids = [<%= singular_table_name %>_true.id, <%= singular_table_name %>_false.id]
|
769
|
+
test_records_true = true_response['data'].select { |item| test_ids.include?(item['id']) }
|
770
|
+
true_count = test_records_true.count { |item| item['<%= attr.name %>'] == true }
|
771
|
+
assert_equal 1, true_count, "Should find exactly 1 test <%= singular_table_name %> with <%= attr.name %> = true"
|
772
|
+
|
773
|
+
# Test filtering for false values
|
774
|
+
get <%= api_route_helper %>_url,
|
775
|
+
params: { <%= attr.name %>_eq: "false" },
|
776
|
+
headers: @auth_headers
|
777
|
+
assert_response :success
|
778
|
+
|
779
|
+
false_response = JSON.parse(response.body)
|
780
|
+
# Filter for only our test records to avoid fixture interference
|
781
|
+
test_records_false = false_response['data'].select { |item| test_ids.include?(item['id']) }
|
782
|
+
false_count = test_records_false.count { |item| item['<%= attr.name %>'] == false }
|
783
|
+
assert_equal 1, false_count, "Should find exactly 1 test <%= singular_table_name %> with <%= attr.name %> = false"
|
784
|
+
|
785
|
+
# Clean up test data to avoid interference with other tests
|
786
|
+
[<%= singular_table_name %>_true, <%= singular_table_name %>_false].each do |record|
|
787
|
+
record.destroy if record.persisted?
|
788
|
+
end
|
789
|
+
<% end -%>
|
790
|
+
end
|
791
|
+
<% end -%>
|
792
|
+
|
793
|
+
<% # Test datetime filtering if we have datetime attributes -%>
|
794
|
+
<% datetime_attributes = filterable_attributes.select { |attr| [:datetime, :date, :time].include?(attr.type) } -%>
|
795
|
+
<% if datetime_attributes.any? -%>
|
796
|
+
test "datetime field filtering" do
|
797
|
+
<% datetime_attributes.first(1).each do |attr| -%>
|
798
|
+
# Create test data with known datetime values that don't overlap with fixtures
|
799
|
+
# Use dates far in the future to avoid conflicts with fixture data
|
800
|
+
base_time = Time.parse("2030-06-15 14:30:00 UTC")
|
801
|
+
<%= singular_table_name %>_1 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": base_time - 2.days)
|
802
|
+
<%= singular_table_name %>_2 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": base_time - 1.day)
|
803
|
+
<%= singular_table_name %>_3 = create_<%= singular_table_name %>_for_filtering("<%= attr.name %>": base_time + 1.day)
|
804
|
+
|
805
|
+
# Test 'before' filtering
|
806
|
+
get <%= api_route_helper %>_url,
|
807
|
+
params: { <%= attr.name %>_before: base_time.iso8601 },
|
808
|
+
headers: @auth_headers
|
809
|
+
assert_response :success
|
810
|
+
|
811
|
+
before_response = JSON.parse(response.body)
|
812
|
+
# Filter for only our test records to avoid fixture interference
|
813
|
+
test_ids = [<%= singular_table_name %>_1.id, <%= singular_table_name %>_2.id, <%= singular_table_name %>_3.id]
|
814
|
+
test_records_before = before_response['data'].select { |item| test_ids.include?(item['id']) }
|
815
|
+
before_count = test_records_before.count { |item| item['<%= attr.name %>'].present? && Time.parse(item['<%= attr.name %>']) < base_time }
|
816
|
+
assert_equal 2, before_count, "Should find exactly 2 test <%= table_name %> with <%= attr.name %> before #{base_time}"
|
817
|
+
|
818
|
+
# Test 'after' filtering
|
819
|
+
get <%= api_route_helper %>_url,
|
820
|
+
params: { <%= attr.name %>_after: base_time.iso8601 },
|
821
|
+
headers: @auth_headers
|
822
|
+
assert_response :success
|
823
|
+
|
824
|
+
after_response = JSON.parse(response.body)
|
825
|
+
# Filter for only our test records to avoid fixture interference
|
826
|
+
test_records_after = after_response['data'].select { |item| test_ids.include?(item['id']) }
|
827
|
+
after_count = test_records_after.count { |item| item['<%= attr.name %>'].present? && Time.parse(item['<%= attr.name %>']) > base_time }
|
828
|
+
assert_equal 1, after_count, "Should find exactly 1 test <%= singular_table_name %> with <%= attr.name %> after #{base_time}"
|
829
|
+
|
830
|
+
# Test 'year' filtering
|
831
|
+
get <%= api_route_helper %>_url,
|
832
|
+
params: { <%= attr.name %>_year: "2030" },
|
833
|
+
headers: @auth_headers
|
834
|
+
assert_response :success
|
835
|
+
|
836
|
+
year_response = JSON.parse(response.body)
|
837
|
+
# Filter for only our test records to avoid fixture interference
|
838
|
+
test_records_year = year_response['data'].select { |item| test_ids.include?(item['id']) }
|
839
|
+
year_count = test_records_year.count { |item| item['<%= attr.name %>'].present? && Time.parse(item['<%= attr.name %>']).year == 2030 }
|
840
|
+
assert_equal 3, year_count, "Should find exactly 3 test <%= table_name %> with <%= attr.name %> in year 2030"
|
841
|
+
|
842
|
+
# Test 'month' filtering
|
843
|
+
get <%= api_route_helper %>_url,
|
844
|
+
params: { <%= attr.name %>_month: "6" },
|
845
|
+
headers: @auth_headers
|
846
|
+
assert_response :success
|
847
|
+
|
848
|
+
month_response = JSON.parse(response.body)
|
849
|
+
# Filter for only our test records to avoid fixture interference
|
850
|
+
test_records_month = month_response['data'].select { |item| test_ids.include?(item['id']) }
|
851
|
+
month_count = test_records_month.count { |item| item['<%= attr.name %>'].present? && Time.parse(item['<%= attr.name %>']).month == 6 }
|
852
|
+
assert_equal 3, month_count, "Should find exactly 3 test <%= table_name %> with <%= attr.name %> in month 6"
|
853
|
+
|
854
|
+
# Clean up test data to avoid interference with other tests
|
855
|
+
[<%= singular_table_name %>_1, <%= singular_table_name %>_2, <%= singular_table_name %>_3].each do |record|
|
856
|
+
record.destroy if record.persisted?
|
857
|
+
end
|
858
|
+
<% end -%>
|
859
|
+
end
|
860
|
+
<% end -%>
|
861
|
+
|
862
|
+
test "sorting functionality" do
|
863
|
+
<% if class_name == 'Organization' -%>
|
864
|
+
# Test sorting with existing fixture data
|
865
|
+
# Due to multi-tenancy, we only have access to the current user's organization
|
866
|
+
|
867
|
+
# Test ascending sort
|
868
|
+
get <%= api_route_helper %>_url,
|
869
|
+
params: { order_by: "name" },
|
870
|
+
headers: @auth_headers
|
871
|
+
assert_response :success
|
872
|
+
|
873
|
+
asc_response = JSON.parse(response.body)
|
874
|
+
assert asc_response['data'].size >= 1, "Should have at least 1 record for sorting test"
|
875
|
+
|
876
|
+
# Test that the single organization is returned and properly formatted
|
877
|
+
organization_data = asc_response['data'][0]
|
878
|
+
assert_equal "Acme Corporation", organization_data['name'], "Should return the correct organization name"
|
879
|
+
assert organization_data.key?('id'), "Should include organization ID"
|
880
|
+
assert organization_data.key?('website'), "Should include organization website"
|
881
|
+
|
882
|
+
# Test descending sort
|
883
|
+
get <%= api_route_helper %>_url,
|
884
|
+
params: { order_by: "-name" },
|
885
|
+
headers: @auth_headers
|
886
|
+
assert_response :success
|
887
|
+
|
888
|
+
desc_response = JSON.parse(response.body)
|
889
|
+
assert desc_response['data'].size >= 1, "Should have at least 1 record for descending sort test"
|
890
|
+
|
891
|
+
# Test that the single organization is returned (descending sort of 1 item is the same as ascending)
|
892
|
+
organization_data_desc = desc_response['data'][0]
|
893
|
+
assert_equal "Acme Corporation", organization_data_desc['name'], "Should return the correct organization name"
|
894
|
+
<% elsif filterable_attributes.any? -%>
|
895
|
+
<% sortable_attr = filterable_attributes.first -%>
|
896
|
+
# Create test data for sorting
|
897
|
+
<% if sortable_attr.name.match?(/email|mail/i) -%>
|
898
|
+
<%= singular_table_name %>_1 = create_<%= singular_table_name %>_for_filtering("<%= sortable_attr.name %>": "red_grape_test@example.com")
|
899
|
+
<%= singular_table_name %>_2 = create_<%= singular_table_name %>_for_filtering("<%= sortable_attr.name %>": "green_apple_test@example.com")
|
900
|
+
<%= singular_table_name %>_3 = create_<%= singular_table_name %>_for_filtering("<%= sortable_attr.name %>": "black_cherry_test@example.com")
|
901
|
+
<% else -%>
|
902
|
+
<%= singular_table_name %>_1 = create_<%= singular_table_name %>_for_filtering("<%= sortable_attr.name %>": <% if [:string, :text].include?(sortable_attr.type) %>"Red Grape"<% elsif [:integer, :decimal, :float].include?(sortable_attr.type) %>30<% elsif sortable_attr.type == :boolean %>true<% else %>"red_grape_value"<% end %>)
|
903
|
+
<%= singular_table_name %>_2 = create_<%= singular_table_name %>_for_filtering("<%= sortable_attr.name %>": <% if [:string, :text].include?(sortable_attr.type) %>"Green Apple"<% elsif [:integer, :decimal, :float].include?(sortable_attr.type) %>10<% elsif sortable_attr.type == :boolean %>false<% else %>"green_apple_value"<% end %>)
|
904
|
+
<%= singular_table_name %>_3 = create_<%= singular_table_name %>_for_filtering("<%= sortable_attr.name %>": <% if [:string, :text].include?(sortable_attr.type) %>"Black Cherry"<% elsif [:integer, :decimal, :float].include?(sortable_attr.type) %>20<% elsif sortable_attr.type == :boolean %>true<% else %>"black_cherry_value"<% end %>)
|
905
|
+
<% end -%>
|
906
|
+
|
907
|
+
# Test ascending sort
|
908
|
+
get <%= api_route_helper %>_url,
|
909
|
+
params: { order_by: "<%= sortable_attr.name %>" },
|
910
|
+
headers: @auth_headers
|
911
|
+
assert_response :success
|
912
|
+
|
913
|
+
asc_response = JSON.parse(response.body)
|
914
|
+
assert asc_response['data'].size >= 3, "Should have at least 3 records for sorting test"
|
915
|
+
|
916
|
+
# Extract sorted values (only from our test records)
|
917
|
+
test_ids = [<%= singular_table_name %>_1.id, <%= singular_table_name %>_2.id, <%= singular_table_name %>_3.id]
|
918
|
+
test_records = asc_response['data'].select { |item| test_ids.include?(item['id']) }
|
919
|
+
asc_values = test_records.map { |item| item['<%= sortable_attr.name %>'] }
|
920
|
+
|
921
|
+
<% if sortable_attr.name.match?(/email|mail/i) -%>
|
922
|
+
assert_equal ["black_cherry_test@example.com", "green_apple_test@example.com", "red_grape_test@example.com"], asc_values, "Records should be sorted by <%= sortable_attr.name %> in ascending order"
|
923
|
+
<% elsif [:string, :text].include?(sortable_attr.type) -%>
|
924
|
+
assert_equal ["Black Cherry", "Green Apple", "Red Grape"], asc_values, "Records should be sorted by <%= sortable_attr.name %> in ascending order"
|
925
|
+
<% elsif [:integer, :decimal, :float].include?(sortable_attr.type) -%>
|
926
|
+
assert_equal [10, 20, 30], asc_values, "Records should be sorted by <%= sortable_attr.name %> in ascending order"
|
927
|
+
<% else -%>
|
928
|
+
assert_equal asc_values.sort, asc_values, "Records should be sorted by <%= sortable_attr.name %> in ascending order"
|
929
|
+
<% end -%>
|
930
|
+
|
931
|
+
# Test descending sort
|
932
|
+
get <%= api_route_helper %>_url,
|
933
|
+
params: { order_by: "-<%= sortable_attr.name %>" },
|
934
|
+
headers: @auth_headers
|
935
|
+
assert_response :success
|
936
|
+
|
937
|
+
desc_response = JSON.parse(response.body)
|
938
|
+
test_records_desc = desc_response['data'].select { |item| test_ids.include?(item['id']) }
|
939
|
+
desc_values = test_records_desc.map { |item| item['<%= sortable_attr.name %>'] }
|
940
|
+
|
941
|
+
<% if sortable_attr.name.match?(/email|mail/i) -%>
|
942
|
+
assert_equal ["red_grape_test@example.com", "green_apple_test@example.com", "black_cherry_test@example.com"], desc_values, "Records should be sorted by <%= sortable_attr.name %> in descending order"
|
943
|
+
<% elsif [:string, :text].include?(sortable_attr.type) -%>
|
944
|
+
assert_equal ["Red Grape", "Green Apple", "Black Cherry"], desc_values, "Records should be sorted by <%= sortable_attr.name %> in descending order"
|
945
|
+
<% elsif [:integer, :decimal, :float].include?(sortable_attr.type) -%>
|
946
|
+
assert_equal [30, 20, 10], desc_values, "Records should be sorted by <%= sortable_attr.name %> in descending order"
|
947
|
+
<% else -%>
|
948
|
+
assert_equal asc_values.sort.reverse, desc_values, "Records should be sorted by <%= sortable_attr.name %> in descending order"
|
949
|
+
<% end -%>
|
950
|
+
<% else -%>
|
951
|
+
# No filterable attributes available for sorting test
|
952
|
+
get <%= api_route_helper %>_url, headers: @auth_headers
|
953
|
+
assert_response :success
|
954
|
+
|
955
|
+
response_data = JSON.parse(response.body)
|
956
|
+
assert response_data['data'].is_a?(Array), "Should return array of records"
|
957
|
+
<% end -%>
|
958
|
+
end
|
959
|
+
|
960
|
+
test "filtering security - should reject sensitive field filtering" do
|
961
|
+
# Test that sensitive field filtering is rejected/ignored
|
962
|
+
get <%= api_route_helper %>_url,
|
963
|
+
params: {
|
964
|
+
password_eq: "hack_attempt",
|
965
|
+
token_contains: "secret",
|
966
|
+
encrypted_data_eq: "malicious"
|
967
|
+
},
|
968
|
+
headers: @auth_headers
|
969
|
+
assert_response :success
|
970
|
+
|
971
|
+
# Should succeed but ignore the sensitive filters
|
972
|
+
security_response = JSON.parse(response.body)
|
973
|
+
assert security_response['data'].is_a?(Array), "Should return normal results, ignoring sensitive filters"
|
974
|
+
end
|
975
|
+
|
976
|
+
test "filtering error handling" do
|
977
|
+
# Test invalid operator
|
978
|
+
get <%= api_route_helper %>_url,
|
979
|
+
params: { invalid_field_invalid_op: "value" },
|
980
|
+
headers: @auth_headers
|
981
|
+
assert_response :success # Should succeed but ignore invalid filter
|
982
|
+
|
983
|
+
# Test malformed range
|
984
|
+
<% if filterable_attributes.select { |attr| [:integer, :decimal, :float].include?(attr.type) }.any? -%>
|
985
|
+
<% numeric_attr = filterable_attributes.select { |attr| [:integer, :decimal, :float].include?(attr.type) }.first -%>
|
986
|
+
get <%= api_route_helper %>_url,
|
987
|
+
params: { <%= numeric_attr.name %>_range: "invalid_range" },
|
988
|
+
headers: @auth_headers
|
989
|
+
assert_response :success # Should succeed but ignore malformed filter
|
990
|
+
<% end -%>
|
991
|
+
|
992
|
+
# Test empty filter values
|
993
|
+
<% if filterable_attributes.any? -%>
|
994
|
+
<% test_attr = filterable_attributes.first -%>
|
995
|
+
get <%= api_route_helper %>_url,
|
996
|
+
params: { <%= test_attr.name %>_eq: "" },
|
997
|
+
headers: @auth_headers
|
998
|
+
assert_response :success
|
999
|
+
<% end -%>
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
private
|
1003
|
+
|
1004
|
+
def create_<%= singular_table_name %>_for_filtering(**attributes)
|
1005
|
+
# Use unique identifiers to avoid conflicts with existing test data
|
1006
|
+
unique_id = SecureRandom.hex(4)
|
1007
|
+
base_attributes = {
|
1008
|
+
<% attributes.each_with_index do |attribute, index| -%>
|
1009
|
+
<% if attribute.type == :references -%>
|
1010
|
+
<%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
|
1011
|
+
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
1012
|
+
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
1013
|
+
<% elsif [:string, :text].include?(attribute.type) -%>
|
1014
|
+
<% if attribute.name.match?(/email|email_address|mail/i) -%>
|
1015
|
+
<%= attribute.name %>: "test_<%= attribute.name %>_#{unique_id}@example.com"<%= ',' if index < attributes.length - 1 %>
|
1016
|
+
<% elsif attribute.name.match?(/password/i) -%>
|
1017
|
+
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
1018
|
+
<% elsif attribute.name.match?(/\A(url|website|web_address|domain|domain_name)\z/i) || attribute.name.match?(/_url$|_link$/i) -%>
|
1019
|
+
<%= attribute.name %>: "https://test_<%= attribute.name %>_#{unique_id}.com"<%= ',' if index < attributes.length - 1 %>
|
1020
|
+
<% elsif attribute.name.match?(/username/i) -%>
|
1021
|
+
<%= attribute.name %>: "test_<%= attribute.name %>_#{unique_id}"<%= ',' if index < attributes.length - 1 %>
|
1022
|
+
<% else -%>
|
1023
|
+
<%= attribute.name %>: "Test <%= attribute.name.humanize %> #{unique_id}"<%= ',' if index < attributes.length - 1 %>
|
1024
|
+
<% end -%>
|
1025
|
+
<% elsif attribute.type == :integer -%>
|
1026
|
+
<%= attribute.name %>: 1<%= ',' if index < attributes.length - 1 %>
|
1027
|
+
<% elsif attribute.type == :boolean -%>
|
1028
|
+
<%= attribute.name %>: false<%= ',' if index < attributes.length - 1 %>
|
1029
|
+
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
1030
|
+
<%= attribute.name %>: 1.0<%= ',' if index < attributes.length - 1 %>
|
1031
|
+
<% elsif [:datetime, :date, :time].include?(attribute.type) -%>
|
1032
|
+
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
1033
|
+
<% else -%>
|
1034
|
+
<%= attribute.name %>: "test_value"<%= ',' if index < attributes.length - 1 %>
|
1035
|
+
<% end -%>
|
1036
|
+
<% end -%>
|
1037
|
+
<% # Add password_confirmation if password field exists but password_confirmation doesn't -%>
|
1038
|
+
<% if attributes.any? { |attr| attr.name.match?(/password/i) && !attr.name.match?(/confirmation/i) } && !attributes.any? { |attr| attr.name.match?(/password_confirmation/i) } -%>
|
1039
|
+
password_confirmation: "password123"
|
1040
|
+
<% end -%>
|
1041
|
+
}.merge(attributes)
|
1042
|
+
|
1043
|
+
<%= class_name %>.create!(base_attributes)
|
1044
|
+
end
|
1045
|
+
|
463
1046
|
# === ERROR HANDLING WORKFLOW TESTS ===
|
464
1047
|
|
465
1048
|
test "error handling workflow" do
|
@@ -544,7 +1127,40 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
544
1127
|
unique_id = "#{Time.current.to_i}_#{SecureRandom.hex(6)}"
|
545
1128
|
test_params = { email_address: "tenancy_test_#{unique_id}@example.com", username: "tenancy_test_#{unique_id}", password: "password123" }
|
546
1129
|
<% else -%>
|
547
|
-
test_params = {
|
1130
|
+
test_params = { <%
|
1131
|
+
# Use appropriate field name based on model type
|
1132
|
+
case class_name
|
1133
|
+
when 'Agency', 'Organization'
|
1134
|
+
field_name = 'name'
|
1135
|
+
field_value = "Test #{class_name}"
|
1136
|
+
when 'Agent'
|
1137
|
+
field_name = 'title'
|
1138
|
+
field_value = "Test #{class_name}"
|
1139
|
+
else
|
1140
|
+
# Default to title for other models, but check if name field exists
|
1141
|
+
if attributes.any? { |attr| attr.name == 'name' && attr.type == :string }
|
1142
|
+
field_name = 'name'
|
1143
|
+
field_value = "Test #{class_name}"
|
1144
|
+
elsif attributes.any? { |attr| attr.name == 'title' && attr.type == :string }
|
1145
|
+
field_name = 'title'
|
1146
|
+
field_value = "Test #{class_name}"
|
1147
|
+
else
|
1148
|
+
# Fallback to first string attribute if no name/title found
|
1149
|
+
string_attr = attributes.find { |attr| attr.type == :string && !['organization', 'agency', 'user', 'agent'].include?(attr.name) }
|
1150
|
+
if string_attr
|
1151
|
+
field_name = string_attr.name
|
1152
|
+
field_value = if string_attr.name.match?(/email/)
|
1153
|
+
"test@example.com"
|
1154
|
+
else
|
1155
|
+
"Test #{string_attr.name.humanize}"
|
1156
|
+
end
|
1157
|
+
else
|
1158
|
+
field_name = 'name' # Final fallback
|
1159
|
+
field_value = "Test #{class_name}"
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
%><%= field_name %>: "<%= field_value %>"<% polymorphic_associations.each do |assoc| -%>, <%= assoc[:field_name] %>_id: @<%= assoc[:field_name] %>.id, <%= assoc[:field_name] %>_type: @<%= assoc[:field_name] %>.class.name<% end -%> }
|
548
1164
|
<% end -%>
|
549
1165
|
<% end -%>
|
550
1166
|
|
@@ -613,7 +1229,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
613
1229
|
headers: @auth_headers
|
614
1230
|
<% else -%>
|
615
1231
|
post <%= api_route_helper %>_url,
|
616
|
-
params: { data: { organization_id: @organization.id, agency_id: 99999,
|
1232
|
+
params: { data: { organization_id: @organization.id, agency_id: 99999, <%=
|
1233
|
+
# Use appropriate field name for security tests
|
1234
|
+
case class_name
|
1235
|
+
when 'Agency', 'Organization'
|
1236
|
+
'name'
|
1237
|
+
when 'Agent'
|
1238
|
+
'title'
|
1239
|
+
else
|
1240
|
+
# Check which field the model actually has
|
1241
|
+
if attributes.any? { |attr| attr.name == 'name' && attr.type == :string }
|
1242
|
+
'name'
|
1243
|
+
elsif attributes.any? { |attr| attr.name == 'title' && attr.type == :string }
|
1244
|
+
'title'
|
1245
|
+
else
|
1246
|
+
'name' # Fallback
|
1247
|
+
end
|
1248
|
+
end
|
1249
|
+
%>: "Test <%= class_name %>"<% polymorphic_associations.each do |assoc| -%>, <%= assoc[:field_name] %>_id: @<%= assoc[:field_name] %>.id, <%= assoc[:field_name] %>_type: @<%= assoc[:field_name] %>.class.name<% end -%> } },
|
617
1250
|
headers: @auth_headers
|
618
1251
|
<% end -%>
|
619
1252
|
|
@@ -632,7 +1265,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
632
1265
|
headers: @auth_headers
|
633
1266
|
<% else -%>
|
634
1267
|
post <%= api_route_helper %>_url,
|
635
|
-
params: { data: { organization_id: 99999,
|
1268
|
+
params: { data: { organization_id: 99999, <%=
|
1269
|
+
# Use appropriate field name for security tests
|
1270
|
+
case class_name
|
1271
|
+
when 'Agency', 'Organization'
|
1272
|
+
'name'
|
1273
|
+
when 'Agent'
|
1274
|
+
'title'
|
1275
|
+
else
|
1276
|
+
# Check which field the model actually has
|
1277
|
+
if attributes.any? { |attr| attr.name == 'name' && attr.type == :string }
|
1278
|
+
'name'
|
1279
|
+
elsif attributes.any? { |attr| attr.name == 'title' && attr.type == :string }
|
1280
|
+
'title'
|
1281
|
+
else
|
1282
|
+
'name' # Fallback
|
1283
|
+
end
|
1284
|
+
end
|
1285
|
+
%>: "Test <%= class_name %>"<% polymorphic_associations.each do |assoc| -%>, <%= assoc[:field_name] %>_id: @<%= assoc[:field_name] %>.id, <%= assoc[:field_name] %>_type: @<%= assoc[:field_name] %>.class.name<% end -%> } },
|
636
1286
|
headers: @auth_headers
|
637
1287
|
<% end -%>
|
638
1288
|
|
@@ -708,7 +1358,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
708
1358
|
<% elsif attribute.name.include?('password') -%>
|
709
1359
|
<%= attribute.name %>: "org1_secure_password"<%= ',' if index < attributes.length - 1 %>
|
710
1360
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
711
|
-
<%= attribute.name %>: "https://org1.
|
1361
|
+
<%= attribute.name %>: "https://org1.com"<%= ',' if index < attributes.length - 1 %>
|
712
1362
|
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
713
1363
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
714
1364
|
<% else -%>
|
@@ -775,7 +1425,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
775
1425
|
<% elsif attribute.name.include?('password') -%>
|
776
1426
|
<%= attribute.name %>: "org2_secure_password"<%= ',' if index < attributes.length - 1 %>
|
777
1427
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
778
|
-
<%= attribute.name %>: "https://org2.
|
1428
|
+
<%= attribute.name %>: "https://org2.com"<%= ',' if index < attributes.length - 1 %>
|
779
1429
|
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
780
1430
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
781
1431
|
<% else -%>
|
@@ -952,7 +1602,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
952
1602
|
<% elsif attribute.name.include?('email') -%>
|
953
1603
|
<%= attribute.name %>: "concurrent@example.com"<%= ',' if index < attributes.length - 1 %>
|
954
1604
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
955
|
-
<%= attribute.name %>: "https://concurrent.
|
1605
|
+
<%= attribute.name %>: "https://concurrent.com"<%= ',' if index < attributes.length - 1 %>
|
956
1606
|
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
957
1607
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
958
1608
|
<% else -%>
|
@@ -1088,7 +1738,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
1088
1738
|
<% elsif attribute.name.include?('email') -%>
|
1089
1739
|
<%= attribute.name %>: "bulk#{i}@example.com"<%= ',' if index < attributes.length - 1 %>
|
1090
1740
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
1091
|
-
<%= attribute.name %>: "https://bulk#{i}.
|
1741
|
+
<%= attribute.name %>: "https://bulk#{i}.com"<%= ',' if index < attributes.length - 1 %>
|
1092
1742
|
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
1093
1743
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
1094
1744
|
<% else -%>
|