propel_api 0.3.1.2 → 0.3.1.4
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 +30 -15
- data/README.md +60 -7
- data/lib/generators/propel_api/controller/controller_generator.rb +1 -1
- data/lib/generators/propel_api/core/named_base.rb +18 -4
- data/lib/generators/propel_api/resource/resource_generator.rb +1 -1
- data/lib/generators/propel_api/templates/tests/fixtures_template.yml.tt +6 -6
- data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +133 -18
- data/lib/propel_api.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57d463a766fd115825dccf217caabd982bf849c9aac5a9dfafc7ef11b2a75c04
|
4
|
+
data.tar.gz: 171026f0732372a319fb79946d3c7991293542a7b080bda4559b28427017b741
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0576b9c86f00a1dde3691dfafc7049d6ffcc58c0717c98cab5739b3bee7c354046f711f3eaf061caa11f6c43c29f43008e988c55d706e84dfaa57e8ca0266de4
|
7
|
+
data.tar.gz: fd24e624bd103eb1bdd96c4e85701198b77964716ebf35d267b1d08f75ee7fc8f6016b85c5374eedc111bb7371af8210779874050db707c906290129fdc1d828
|
data/CHANGELOG.md
CHANGED
@@ -10,6 +10,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
10
10
|
### Planned Features
|
11
11
|
- GraphQL adapter support
|
12
12
|
|
13
|
+
## [0.3.1.4] - 2025-09-11
|
14
|
+
|
15
|
+
### 🐛 Critical Bug Fixes
|
16
|
+
- **Polymorphic Parents Parsing Regression**: Fixed `NoMethodError: undefined method 'strip' for Array`
|
17
|
+
- Reverted to original, working `parse_polymorphic_parent_types` implementation
|
18
|
+
- Fixed overcomplicated parsing logic that incorrectly assumed Thor gives Arrays
|
19
|
+
- Thor consistently provides comma-separated String values that need simple `.split(',')` handling
|
20
|
+
- Resolves crash when using `--parents` option with polymorphic generators
|
21
|
+
|
22
|
+
### 📖 Documentation Improvements
|
23
|
+
- **--parents Flag Usage Guide**: Added comprehensive documentation for correct --parents syntax
|
24
|
+
- Fixed misleading error messages that suggested unsupported syntax
|
25
|
+
- Added clear examples of correct vs incorrect --parents usage
|
26
|
+
- Enhanced README with detailed usage guide and common pitfalls
|
27
|
+
- Updated all generator descriptions to show required field_name:Parent1,Parent2 syntax
|
28
|
+
|
29
|
+
## [0.3.1.3] - 2025-09-11
|
30
|
+
|
31
|
+
### 🐛 Bug Fixes
|
32
|
+
- **Polymorphic Association Facet Includes**: Fixed facet includes for polymorphic associations in model templates
|
33
|
+
- Polymorphic associations are now properly included in `details` facet for eager loading
|
34
|
+
- Enhanced model template to handle polymorphic associations in facet includes correctly
|
35
|
+
- Fixed Schedule model and similar polymorphic association issues
|
36
|
+
- **Data Integrity Test Fixes**: Improved model test template for more reliable data integrity tests
|
37
|
+
- Fixed hardcoded test expectations to match actual test data creation
|
38
|
+
- Better handling of polymorphic associations in integrity tests
|
39
|
+
- Enhanced test data generation for name/title fields to use realistic values (e.g., "integrity_test")
|
40
|
+
- Added proper JSON/JSONB field testing support
|
41
|
+
|
13
42
|
## [0.3.1.2] - 2025-09-11
|
14
43
|
|
15
44
|
### 🎉 New Features
|
@@ -27,20 +56,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
27
56
|
- Command-line flag support for per-generator control
|
28
57
|
- Backward compatible with existing configurations
|
29
58
|
|
30
|
-
### 🐛 Bug Fixes
|
31
|
-
- **Polymorphic Association Facet Includes**: Fixed facet includes for polymorphic associations in model templates
|
32
|
-
- Polymorphic associations are now properly included in `details` facet for eager loading
|
33
|
-
- Enhanced model template to handle polymorphic associations in facet includes correctly
|
34
|
-
- Fixed Schedule model and similar polymorphic association issues
|
35
|
-
- **Data Integrity Test Fixes**: Improved model test template for more reliable data integrity tests
|
36
|
-
- Fixed hardcoded test expectations to match actual test data creation
|
37
|
-
- Better handling of polymorphic associations in integrity tests
|
38
|
-
- Enhanced test data generation for name/title fields to use realistic values
|
39
|
-
- Added proper JSON/JSONB field testing support
|
40
|
-
- **HTTP Status Code Consistency**: Fixed tokens controller to use consistent HTTP status codes
|
41
|
-
- Changed validation errors from `:unprocessable_content` (422) to `:bad_request` (400)
|
42
|
-
- Better alignment with standard HTTP parameter validation practices
|
43
|
-
- Improved error handling consistency across authentication endpoints
|
44
59
|
|
45
60
|
## [0.3.1.1] - 2025-09-11
|
46
61
|
|
@@ -92,7 +107,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
92
107
|
- **Integration Test Templates**: Enhanced error handling and parameter validation in generated integration tests
|
93
108
|
|
94
109
|
### ⚠️ Breaking Changes
|
95
|
-
- **REQUIRED --parents for Polymorphic**: Polymorphic associations now require explicit `--parents Parent1,Parent2` declaration. Auto-discovery fallback has been removed. Generator will block with confirmation if --parents is missing.
|
110
|
+
- **REQUIRED --parents for Polymorphic**: Polymorphic associations now require explicit `--parents field_name:Parent1,Parent2` declaration. Auto-discovery fallback has been removed. Generator will block with confirmation if --parents is missing.
|
96
111
|
|
97
112
|
## [0.3.0] - 2025-01-15
|
98
113
|
|
data/README.md
CHANGED
@@ -55,10 +55,10 @@ rails generate propel_api:resource User name:string email:string role:string
|
|
55
55
|
rails generate propel_api:resource Article title:string content:text user:references category:references
|
56
56
|
|
57
57
|
# 🎉 NEW: Polymorphic associations (v0.3.0) - REQUIRES --parents flag
|
58
|
-
rails generate propel_api:resource Comment content:text commentable:references{polymorphic} --parents Post,Video,Product
|
58
|
+
rails generate propel_api:resource Comment content:text commentable:references{polymorphic} --parents commentable:Post,Video,Product
|
59
59
|
|
60
60
|
# Polymorphic with tenancy
|
61
|
-
rails generate propel_api:resource Review rating:integer comment:text review_parent:polymorphic --parents Product,Agency
|
61
|
+
rails generate propel_api:resource Review rating:integer comment:text review_parent:polymorphic --parents review_parent:Product,Agency
|
62
62
|
|
63
63
|
# With Graphiti adapter
|
64
64
|
rails generate propel_api Product name:string price:decimal --adapter=graphiti
|
@@ -81,10 +81,10 @@ PropelApi now provides comprehensive support for polymorphic associations with a
|
|
81
81
|
|
82
82
|
```bash
|
83
83
|
# Generate a Comment that can belong to Posts, Videos, or Products
|
84
|
-
rails generate propel_api:resource Comment body:text commentable:references{polymorphic} --parents Post,Video,Product
|
84
|
+
rails generate propel_api:resource Comment body:text commentable:references{polymorphic} --parents commentable:Post,Video,Product
|
85
85
|
|
86
|
-
# Generate a Review with full tenancy support
|
87
|
-
rails generate propel_api:resource Review rating:integer comment:text review_parent:references{polymorphic} --parents Product,Agency
|
86
|
+
# Generate a Review with full tenancy support
|
87
|
+
rails generate propel_api:resource Review rating:integer comment:text review_parent:references{polymorphic} --parents review_parent:Product,Agency
|
88
88
|
```
|
89
89
|
|
90
90
|
### Key Features
|
@@ -94,7 +94,8 @@ rails generate propel_api:resource Review rating:integer comment:text review_par
|
|
94
94
|
- No need for complex quote escaping or nested syntax
|
95
95
|
|
96
96
|
#### 🎯 Required Parent Specification
|
97
|
-
- `--parents Parent1,Parent2,Parent3` defines valid parent models (REQUIRED for polymorphic associations)
|
97
|
+
- `--parents field_name:Parent1,Parent2,Parent3` defines valid parent models (REQUIRED for polymorphic associations)
|
98
|
+
- Field name must match the polymorphic association name (e.g., `commentable`, `schedule_parent`)
|
98
99
|
- Automatically generates varied test data using different parent types
|
99
100
|
- Generator will block with confirmation if --parents is not provided
|
100
101
|
|
@@ -139,6 +140,58 @@ class Api::V1::CommentsController < Api::V1::ApiController
|
|
139
140
|
end
|
140
141
|
```
|
141
142
|
|
143
|
+
### --parents Flag Usage Guide
|
144
|
+
|
145
|
+
⚠️ **IMPORTANT**: The `--parents` flag requires specific syntax to work correctly.
|
146
|
+
|
147
|
+
#### ✅ **Correct Syntax:**
|
148
|
+
```bash
|
149
|
+
# Single polymorphic field
|
150
|
+
--parents field_name:Parent1,Parent2,Parent3
|
151
|
+
|
152
|
+
# Real examples:
|
153
|
+
--parents commentable:Post,Photo,Video
|
154
|
+
--parents schedule_parent:User,Room,MeetingLink
|
155
|
+
--parents review_parent:Product,Agency
|
156
|
+
|
157
|
+
# Multiple polymorphic fields
|
158
|
+
--parents commentable:Post,Photo schedule_parent:User,Room
|
159
|
+
```
|
160
|
+
|
161
|
+
#### ❌ **Incorrect Syntax (Will Fail):**
|
162
|
+
```bash
|
163
|
+
# Missing field name (Thor can't parse this)
|
164
|
+
--parents Post,Photo,Video
|
165
|
+
|
166
|
+
# Array brackets (not supported)
|
167
|
+
--parents commentable:[Post,Photo,Video]
|
168
|
+
|
169
|
+
# JSON-like syntax (not supported)
|
170
|
+
--parents "{commentable: [Post,Photo,Video]}"
|
171
|
+
```
|
172
|
+
|
173
|
+
#### 🔑 **Key Rules:**
|
174
|
+
1. **Always include field name**: `field_name:Parent1,Parent2`
|
175
|
+
2. **Field name must match polymorphic association**: If your field is `commentable:polymorphic`, use `--parents commentable:...`
|
176
|
+
3. **Use commas to separate parent types**: `Post,Photo,Video` not `Post Photo Video`
|
177
|
+
4. **Whitespace is automatically cleaned**: `Post, Photo, Video` works fine
|
178
|
+
|
179
|
+
### Complete Usage Examples
|
180
|
+
|
181
|
+
```bash
|
182
|
+
# Standard resource with polymorphic association
|
183
|
+
rails generate propel_api:resource Comment content:text commentable:polymorphic --parents commentable:Post,Photo,Video
|
184
|
+
|
185
|
+
# Multi-tenant polymorphic resource
|
186
|
+
rails generate propel_api:resource Review rating:integer organization:references agency:references review_parent:polymorphic --parents review_parent:Product,Agency,User
|
187
|
+
|
188
|
+
# Schedule system with polymorphic parent
|
189
|
+
rails generate propel_api:resource Schedule name:string start_time:datetime schedule_parent:polymorphic --parents schedule_parent:User,Room,MeetingLink
|
190
|
+
|
191
|
+
# Multiple polymorphic associations in one resource
|
192
|
+
rails generate propel_api:resource Attachment file_name:string attachable:polymorphic owner:polymorphic --parents attachable:Post,Comment,Email owner:User,Agency
|
193
|
+
```
|
194
|
+
|
142
195
|
### Breaking Changes from v0.2.x
|
143
196
|
|
144
197
|
⚠️ **Migration Required**: The polymorphic syntax and test generation has been completely rewritten for better reliability and Rails compatibility.
|
@@ -148,7 +201,7 @@ end
|
|
148
201
|
|
149
202
|
The new approach provides:
|
150
203
|
- More reliable test generation
|
151
|
-
- Better fixture management
|
204
|
+
- Better fixture management
|
152
205
|
- Cleaner, more maintainable code
|
153
206
|
- Full Rails compatibility
|
154
207
|
|
@@ -52,7 +52,7 @@ module PropelApi
|
|
52
52
|
class_option :parents,
|
53
53
|
type: :hash,
|
54
54
|
default: {},
|
55
|
-
desc: "Specify parent types for polymorphic associations (e.g., --parents commentable:Post,Photo,Video)"
|
55
|
+
desc: "Specify parent types for polymorphic associations. REQUIRED syntax: --parents model_polymorphic_name:Parent1,Parent2,Parent3 (e.g., --parents commentable:Post,Photo,Video)"
|
56
56
|
|
57
57
|
def validate_model_exists
|
58
58
|
# Ensure attributes are parsed before validation
|
@@ -544,7 +544,14 @@ module PropelApi
|
|
544
544
|
polymorphic_attrs = @attributes.select { |attr| attr.type == :references && attr.respond_to?(:polymorphic?) && attr.polymorphic? }
|
545
545
|
|
546
546
|
polymorphic_attrs.map do |attr|
|
547
|
-
parent_types = polymorphic_parent_types[attr.name.to_s] || discover_available_models.first(
|
547
|
+
parent_types = polymorphic_parent_types[attr.name.to_s] || discover_available_models.first(3)
|
548
|
+
|
549
|
+
# Fallback to User if no parent types specified and no models auto-discovered
|
550
|
+
if parent_types.empty?
|
551
|
+
say "Warning: No parent types specified for polymorphic association '#{attr.name}' and no models found to auto-discover.", :yellow
|
552
|
+
say "Falling back to 'User' as parent type. Use --parents #{attr.name}:Parent1,Parent2,Parent3 to specify parent types.", :yellow
|
553
|
+
parent_types = ['User']
|
554
|
+
end
|
548
555
|
|
549
556
|
# Create one association entry per polymorphic field with all parent types
|
550
557
|
{
|
@@ -554,7 +561,7 @@ module PropelApi
|
|
554
561
|
parent_types: parent_types,
|
555
562
|
# For fixture generation, we'll use the first parent type for fixture "one", second for "two", etc.
|
556
563
|
primary_parent_type: parent_types.first,
|
557
|
-
primary_parent_table: parent_types.first
|
564
|
+
primary_parent_table: parent_types.first&.underscore&.pluralize
|
558
565
|
}
|
559
566
|
end
|
560
567
|
end
|
@@ -572,6 +579,10 @@ module PropelApi
|
|
572
579
|
fixture_name = case parent_type.underscore
|
573
580
|
when 'agency'
|
574
581
|
['marketing_agency', 'tech_agency', 'sales_agency'][fixture_index] || 'marketing_agency'
|
582
|
+
when 'user'
|
583
|
+
['john_user', 'jane_user', 'confirmed_user'][fixture_index] || 'john_user'
|
584
|
+
when 'organization'
|
585
|
+
['acme_org', 'tech_startup', 'acme_org'][fixture_index] || 'acme_org'
|
575
586
|
else
|
576
587
|
['one', 'two', 'three'][fixture_index] || 'one'
|
577
588
|
end
|
@@ -600,15 +611,18 @@ module PropelApi
|
|
600
611
|
def discover_available_models
|
601
612
|
# Auto-discover available models from app/models directory
|
602
613
|
models_dir = File.join(destination_root, 'app/models')
|
603
|
-
return [
|
614
|
+
return [] unless File.directory?(models_dir) # No fallback - return empty array
|
604
615
|
|
605
616
|
model_files = Dir[File.join(models_dir, '*.rb')]
|
606
|
-
model_files.map do |file|
|
617
|
+
models = model_files.map do |file|
|
607
618
|
File.basename(file, '.rb').camelize
|
608
619
|
end.reject do |model|
|
609
620
|
# Skip common non-domain models
|
610
621
|
%w[ApplicationRecord Concerns].include?(model)
|
611
622
|
end.sort
|
623
|
+
|
624
|
+
# Ensure we always return at least one model as fallback
|
625
|
+
models.empty? ? [] : models
|
612
626
|
end
|
613
627
|
end
|
614
628
|
end
|
@@ -74,7 +74,7 @@ module PropelApi
|
|
74
74
|
class_option :parents,
|
75
75
|
type: :hash,
|
76
76
|
default: {},
|
77
|
-
desc: "Specify parent types for polymorphic associations (e.g., --parents commentable:Post,Photo,Video)"
|
77
|
+
desc: "Specify parent types for polymorphic associations. REQUIRED syntax: --parents field_name:Parent1,Parent2,Parent3 (e.g., --parents commentable:Post,Photo,Video)"
|
78
78
|
|
79
79
|
def create_migration
|
80
80
|
initialize_propel_api_settings
|
@@ -97,13 +97,13 @@ one:
|
|
97
97
|
<%= attribute.name %>: "2024-06-15 10:30:00"
|
98
98
|
<% elsif attribute.type == :time -%>
|
99
99
|
<%= attribute.name %>: "10:30:00"
|
100
|
-
<% elsif attribute.type == :json || attribute.
|
100
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
101
101
|
<% if attribute.name == 'metadata' -%>
|
102
102
|
<%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "test", tags: ["fixture", "one"], attributes: { priority: "high", status_info: { verified: true, active: true } } }
|
103
103
|
<% elsif attribute.name == 'settings' -%>
|
104
104
|
<%= attribute.name %>: { ui_preferences: { theme: "light", language: "en", notifications: { email: true, sms: false, push: true } }, feature_flags: { beta_features: false, analytics: true } }
|
105
105
|
<% else -%>
|
106
|
-
<%= attribute.name %>: { test_data: "
|
106
|
+
<%= attribute.name %>: { field_type: "jsonb_field", test_data: { string_value: "sample_text_one", numeric_value: 42, boolean_value: true, array_value: ["item1", "item2", "item3"], nested_object: { property: "value", settings: ["option1", "option2"] } }, metadata: { generated_by: "test_fixture", field_name: "<%= attribute.name %>", fixture_id: "one" } }
|
107
107
|
<% end -%>
|
108
108
|
<% else -%>
|
109
109
|
<%= attribute.name %>: "test_value_one"
|
@@ -201,13 +201,13 @@ two:
|
|
201
201
|
<%= attribute.name %>: "2023-12-25 15:45:00"
|
202
202
|
<% elsif attribute.type == :time -%>
|
203
203
|
<%= attribute.name %>: "15:45:00"
|
204
|
-
<% elsif attribute.type == :json || attribute.
|
204
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
205
205
|
<% if attribute.name == 'metadata' -%>
|
206
206
|
<%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "premium", tags: ["fixture", "two"], attributes: { priority: "medium", status_info: { verified: false, active: true } } }
|
207
207
|
<% elsif attribute.name == 'settings' -%>
|
208
208
|
<%= attribute.name %>: { ui_preferences: { theme: "dark", language: "fr", notifications: { email: true, sms: true, push: false } }, feature_flags: { beta_features: true, analytics: false } }
|
209
209
|
<% else -%>
|
210
|
-
<%= attribute.name %>: { test_data: "
|
210
|
+
<%= attribute.name %>: { field_type: "jsonb_field", test_data: { string_value: "sample_text_two", numeric_value: 84, boolean_value: false, array_value: ["item4", "item5", "item6"], nested_object: { property: "different_value", settings: ["option3", "option4"] } }, metadata: { generated_by: "test_fixture", field_name: "<%= attribute.name %>", fixture_id: "two" } }
|
211
211
|
<% end -%>
|
212
212
|
<% else -%>
|
213
213
|
<%= attribute.name %>: "test_value_two"
|
@@ -305,13 +305,13 @@ three:
|
|
305
305
|
<%= attribute.name %>: "2025-03-10 08:15:00"
|
306
306
|
<% elsif attribute.type == :time -%>
|
307
307
|
<%= attribute.name %>: "08:15:00"
|
308
|
-
<% elsif attribute.type == :json || attribute.
|
308
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
309
309
|
<% if attribute.name == 'metadata' -%>
|
310
310
|
<%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "basic", tags: ["fixture", "three"], attributes: { priority: "low", status_info: { verified: true, active: false } } }
|
311
311
|
<% elsif attribute.name == 'settings' -%>
|
312
312
|
<%= attribute.name %>: { ui_preferences: { theme: "auto", language: "es", notifications: { email: false, sms: true, push: true } }, feature_flags: { beta_features: false, analytics: true } }
|
313
313
|
<% else -%>
|
314
|
-
<%= attribute.name %>: { test_data: "
|
314
|
+
<%= attribute.name %>: { field_type: "jsonb_field", test_data: { string_value: "sample_text_three", numeric_value: 126, boolean_value: true, array_value: ["item7", "item8", "item9"], nested_object: { property: "final_value", settings: ["option5", "option6"] } }, metadata: { generated_by: "test_fixture", field_name: "<%= attribute.name %>", fixture_id: "three" } }
|
315
315
|
<% end -%>
|
316
316
|
<% else -%>
|
317
317
|
<%= attribute.name %>: "test_value_three"
|
@@ -89,7 +89,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
89
89
|
<%= attribute.name %>: "password123"<%= ',' if index < attributes.length - 1 %>
|
90
90
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
91
91
|
<%= attribute.name %>: "https://workflow.example.com"<%= ',' if index < attributes.length - 1 %>
|
92
|
-
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
92
|
+
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
93
93
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
94
94
|
<% else -%>
|
95
95
|
<%= attribute.name %>: "Workflow Test <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
@@ -104,7 +104,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
104
104
|
<%= attribute.name %>: 100.50<%= ',' if index < attributes.length - 1 %>
|
105
105
|
<% elsif attribute.type == :datetime -%>
|
106
106
|
<%= attribute.name %>: Time.current<%= ',' if index < attributes.length - 1 %>
|
107
|
-
<% elsif attribute.type == :json || attribute.
|
107
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
108
108
|
<% if attribute.name == 'metadata' -%>
|
109
109
|
<%= attribute.name %>: { resource_type: "<%= singular_table_name %>", category: "test", tags: ["integration", "auto_generated"], attributes: { priority: "medium", status_info: { verified: true, active: true } } }<%= ',' if index < attributes.length - 1 %>
|
110
110
|
<% elsif attribute.name == 'settings' -%>
|
@@ -117,7 +117,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
117
117
|
feature_flags: { beta_features: false, analytics: true }
|
118
118
|
}<%= ',' if index < attributes.length - 1 %>
|
119
119
|
<% else -%>
|
120
|
-
<%= attribute.name %>: {
|
120
|
+
<%= attribute.name %>: {
|
121
|
+
field_type: "jsonb_field",
|
122
|
+
test_data: {
|
123
|
+
string_value: "api_test_data",
|
124
|
+
numeric_value: 123,
|
125
|
+
boolean_value: true,
|
126
|
+
array_value: ["test1", "test2", "test3"],
|
127
|
+
nested_object: {
|
128
|
+
property: "api_value",
|
129
|
+
settings: ["api_option1", "api_option2"]
|
130
|
+
}
|
131
|
+
},
|
132
|
+
metadata: {
|
133
|
+
generated_by: "integration_test",
|
134
|
+
field_name: "<%= attribute.name %>",
|
135
|
+
test_id: "workflow_test"
|
136
|
+
}
|
137
|
+
}<%= ',' if index < attributes.length - 1 %>
|
121
138
|
<% end -%>
|
122
139
|
|
123
140
|
<% elsif !reference_names.include?(attribute.name) -%>
|
@@ -161,6 +178,8 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
161
178
|
<% elsif attribute.name.to_s.match?(/password/) -%>
|
162
179
|
# Password fields should NOT be returned in API responses for security
|
163
180
|
assert_not_includes created_<%= singular_table_name %>.keys, '<%= attribute.name %>', "Password fields should be filtered from API responses"
|
181
|
+
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
182
|
+
assert_equal "https://workflow.example.com", created_<%= singular_table_name %>['<%= attribute.name %>']
|
164
183
|
<% else -%>
|
165
184
|
assert_equal "Workflow Test <%= attribute.name.humanize %>", created_<%= singular_table_name %>['<%= attribute.name %>']
|
166
185
|
<% end -%>
|
@@ -173,12 +192,12 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
173
192
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
174
193
|
# Rails conventionally serializes decimal/float values as strings in JSON
|
175
194
|
assert_equal "100.5", created_<%= singular_table_name %>['<%= attribute.name %>']
|
176
|
-
<% elsif attribute.type == :datetime || attribute.type == :timestamp || attribute.name.to_s.match?(/_at$/) -%>
|
195
|
+
<% elsif attribute.type == :datetime || attribute.type == :timestamp || (attribute.name.to_s.match?(/_at$/) && attribute.type != :json && attribute.type != :jsonb) -%>
|
177
196
|
# Datetime fields should be properly formatted ISO timestamps, not exact values
|
178
197
|
if created_<%= singular_table_name %>['<%= attribute.name %>'].present?
|
179
198
|
assert_match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, created_<%= singular_table_name %>['<%= attribute.name %>'], "<%= attribute.name %> should be ISO timestamp format")
|
180
199
|
end
|
181
|
-
<% elsif attribute.type == :json || attribute.
|
200
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
182
201
|
<% if attribute.name == 'metadata' -%>
|
183
202
|
# Metadata field should be a hash with generic structure
|
184
203
|
assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>'], "Metadata should be a JSON object"
|
@@ -201,7 +220,35 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
201
220
|
assert_includes created_<%= singular_table_name %>['<%= attribute.name %>']['ui_preferences'].keys, "notifications", "UI preferences should contain notifications"
|
202
221
|
assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>']['ui_preferences']['notifications'], "Notifications should be a hash"
|
203
222
|
<% else -%>
|
204
|
-
|
223
|
+
# Generic JSON field should have standard test structure
|
224
|
+
assert_kind_of Hash, created_<%= singular_table_name %>['<%= attribute.name %>'], "<%= attribute.name.humanize %> should be a JSON object"
|
225
|
+
|
226
|
+
# Verify main structure
|
227
|
+
assert_includes created_<%= singular_table_name %>['<%= attribute.name %>'].keys, "field_type", "<%= attribute.name.humanize %> should contain field_type"
|
228
|
+
assert_includes created_<%= singular_table_name %>['<%= attribute.name %>'].keys, "test_data", "<%= attribute.name.humanize %> should contain test_data"
|
229
|
+
assert_includes created_<%= singular_table_name %>['<%= attribute.name %>'].keys, "metadata", "<%= attribute.name.humanize %> should contain metadata"
|
230
|
+
|
231
|
+
# Verify test_data structure (tests all JSON data types)
|
232
|
+
test_data = created_<%= singular_table_name %>['<%= attribute.name %>']['test_data']
|
233
|
+
assert_kind_of Hash, test_data, "test_data should be a hash"
|
234
|
+
assert_includes test_data.keys, "string_value", "test_data should contain string_value"
|
235
|
+
assert_includes test_data.keys, "numeric_value", "test_data should contain numeric_value"
|
236
|
+
assert_includes test_data.keys, "boolean_value", "test_data should contain boolean_value"
|
237
|
+
assert_includes test_data.keys, "array_value", "test_data should contain array_value"
|
238
|
+
assert_includes test_data.keys, "nested_object", "test_data should contain nested_object"
|
239
|
+
|
240
|
+
# Verify data types
|
241
|
+
assert_kind_of String, test_data['string_value'], "string_value should be a string"
|
242
|
+
assert_kind_of Integer, test_data['numeric_value'], "numeric_value should be a number"
|
243
|
+
assert_kind_of Array, test_data['array_value'], "array_value should be an array"
|
244
|
+
assert_kind_of Hash, test_data['nested_object'], "nested_object should be a hash"
|
245
|
+
|
246
|
+
# Verify metadata structure
|
247
|
+
metadata = created_<%= singular_table_name %>['<%= attribute.name %>']['metadata']
|
248
|
+
assert_kind_of Hash, metadata, "metadata should be a hash"
|
249
|
+
assert_includes metadata.keys, "generated_by", "metadata should contain generated_by"
|
250
|
+
assert_includes metadata.keys, "field_name", "metadata should contain field_name"
|
251
|
+
assert_equal "<%= attribute.name %>", metadata['field_name'], "metadata field_name should match attribute name"
|
205
252
|
<% end -%>
|
206
253
|
<% else -%>
|
207
254
|
assert_equal "workflow_test", created_<%= singular_table_name %>['<%= attribute.name %>']
|
@@ -599,7 +646,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
599
646
|
<%= attribute.name %>: "org1_secure_password"<%= ',' if index < attributes.length - 1 %>
|
600
647
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
601
648
|
<%= attribute.name %>: "https://org1.example.com"<%= ',' if index < attributes.length - 1 %>
|
602
|
-
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
649
|
+
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
603
650
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
604
651
|
<% else -%>
|
605
652
|
<%= attribute.name %>: "Org 1 <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
@@ -612,7 +659,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
612
659
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
613
660
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
614
661
|
<%= attribute.name %>: 11.1<%= ',' if index < attributes.length - 1 %>
|
615
|
-
<% elsif attribute.type == :json || attribute.
|
662
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
616
663
|
<% if attribute.name == 'metadata' -%>
|
617
664
|
<%= attribute.name %>: {
|
618
665
|
resource_type: "<%= singular_table_name %>",
|
@@ -626,7 +673,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
626
673
|
<% elsif attribute.name == 'settings' -%>
|
627
674
|
<%= attribute.name %>: { dark_mode: false, notifications: { email: true, sms: true } }<%= ',' if index < attributes.length - 1 %>
|
628
675
|
<% else -%>
|
629
|
-
<%= attribute.name %>: {
|
676
|
+
<%= attribute.name %>: {
|
677
|
+
field_type: "jsonb_field",
|
678
|
+
test_data: {
|
679
|
+
string_value: "api_test_data",
|
680
|
+
numeric_value: 123,
|
681
|
+
boolean_value: true,
|
682
|
+
array_value: ["test1", "test2", "test3"],
|
683
|
+
nested_object: {
|
684
|
+
property: "api_value",
|
685
|
+
settings: ["api_option1", "api_option2"]
|
686
|
+
}
|
687
|
+
},
|
688
|
+
metadata: {
|
689
|
+
generated_by: "integration_test",
|
690
|
+
field_name: "<%= attribute.name %>",
|
691
|
+
test_id: "workflow_test"
|
692
|
+
}
|
693
|
+
}<%= ',' if index < attributes.length - 1 %>
|
630
694
|
<% end -%>
|
631
695
|
<% else -%>
|
632
696
|
<%= attribute.name %>: "org1_value"<%= ',' if index < attributes.length - 1 %>
|
@@ -649,7 +713,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
649
713
|
<%= attribute.name %>: "org2_secure_password"<%= ',' if index < attributes.length - 1 %>
|
650
714
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
651
715
|
<%= attribute.name %>: "https://org2.example.com"<%= ',' if index < attributes.length - 1 %>
|
652
|
-
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
716
|
+
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
653
717
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
654
718
|
<% else -%>
|
655
719
|
<%= attribute.name %>: "Org 2 <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
@@ -662,7 +726,7 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
662
726
|
<%= attribute.name %>: false<%= ',' if index < attributes.length - 1 %>
|
663
727
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
664
728
|
<%= attribute.name %>: 22.2<%= ',' if index < attributes.length - 1 %>
|
665
|
-
<% elsif attribute.type == :json || attribute.
|
729
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
666
730
|
<% if attribute.name == 'metadata' -%>
|
667
731
|
<%= attribute.name %>: {
|
668
732
|
resource_type: "<%= singular_table_name %>",
|
@@ -676,7 +740,24 @@ class <%= class_name %>ApiTest < ActionDispatch::IntegrationTest
|
|
676
740
|
<% elsif attribute.name == 'settings' -%>
|
677
741
|
<%= attribute.name %>: { dark_mode: true, notifications: { email: false, sms: true } }<%= ',' if index < attributes.length - 1 %>
|
678
742
|
<% else -%>
|
679
|
-
<%= attribute.name %>: {
|
743
|
+
<%= attribute.name %>: {
|
744
|
+
field_type: "jsonb_field",
|
745
|
+
test_data: {
|
746
|
+
string_value: "api_test_data",
|
747
|
+
numeric_value: 123,
|
748
|
+
boolean_value: true,
|
749
|
+
array_value: ["test1", "test2", "test3"],
|
750
|
+
nested_object: {
|
751
|
+
property: "api_value",
|
752
|
+
settings: ["api_option1", "api_option2"]
|
753
|
+
}
|
754
|
+
},
|
755
|
+
metadata: {
|
756
|
+
generated_by: "integration_test",
|
757
|
+
field_name: "<%= attribute.name %>",
|
758
|
+
test_id: "workflow_test"
|
759
|
+
}
|
760
|
+
}<%= ',' if index < attributes.length - 1 %>
|
680
761
|
<% end -%>
|
681
762
|
<% else -%>
|
682
763
|
<%= attribute.name %>: "org2_value"<%= ',' if index < attributes.length - 1 %>
|
@@ -809,7 +890,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
809
890
|
<%= attribute.name %>: "concurrent@example.com"<%= ',' if index < attributes.length - 1 %>
|
810
891
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
811
892
|
<%= attribute.name %>: "https://concurrent.example.com"<%= ',' if index < attributes.length - 1 %>
|
812
|
-
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
893
|
+
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
813
894
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
814
895
|
<% else -%>
|
815
896
|
<%= attribute.name %>: "Concurrent Test <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
|
@@ -822,7 +903,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
822
903
|
<%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
|
823
904
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
824
905
|
<%= attribute.name %>: 50.5<%= ',' if index < attributes.length - 1 %>
|
825
|
-
<% elsif attribute.type == :json || attribute.
|
906
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
826
907
|
<% if attribute.name == 'metadata' -%>
|
827
908
|
<%= attribute.name %>: {
|
828
909
|
resource_type: "<%= singular_table_name %>",
|
@@ -843,7 +924,24 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
843
924
|
feature_flags: { beta_features: false, analytics: true }
|
844
925
|
}<%= ',' if index < attributes.length - 1 %>
|
845
926
|
<% else -%>
|
846
|
-
<%= attribute.name %>: {
|
927
|
+
<%= attribute.name %>: {
|
928
|
+
field_type: "jsonb_field",
|
929
|
+
test_data: {
|
930
|
+
string_value: "api_test_data",
|
931
|
+
numeric_value: 123,
|
932
|
+
boolean_value: true,
|
933
|
+
array_value: ["test1", "test2", "test3"],
|
934
|
+
nested_object: {
|
935
|
+
property: "api_value",
|
936
|
+
settings: ["api_option1", "api_option2"]
|
937
|
+
}
|
938
|
+
},
|
939
|
+
metadata: {
|
940
|
+
generated_by: "integration_test",
|
941
|
+
field_name: "<%= attribute.name %>",
|
942
|
+
test_id: "workflow_test"
|
943
|
+
}
|
944
|
+
}<%= ',' if index < attributes.length - 1 %>
|
847
945
|
<% end -%>
|
848
946
|
<% else -%>
|
849
947
|
<%= attribute.name %>: "concurrent_test"<%= ',' if index < attributes.length - 1 %>
|
@@ -928,7 +1026,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
928
1026
|
<%= attribute.name %>: "bulk#{i}@example.com"<%= ',' if index < attributes.length - 1 %>
|
929
1027
|
<% elsif attribute.name.to_s.match?(/\A(url|website|web_address|domain|domain_name)\z/i) -%>
|
930
1028
|
<%= attribute.name %>: "https://bulk#{i}.example.com"<%= ',' if index < attributes.length - 1 %>
|
931
|
-
<% elsif attribute.name.to_s.end_with?('_type') -%>
|
1029
|
+
<% elsif attribute.name.to_s.end_with?('_type') && attribute.name.to_s.match?(/_parent_type$/) -%>
|
932
1030
|
<%= attribute.name %>: @<%= attribute.name.gsub('_type', '') %>.class.name<%= ',' if index < attributes.length - 1 %>
|
933
1031
|
<% else -%>
|
934
1032
|
<%= attribute.name %>: "Bulk Test <%= attribute.name.humanize %> #{i}"<%= ',' if index < attributes.length - 1 %>
|
@@ -941,7 +1039,7 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
941
1039
|
<%= attribute.name %>: i.even?<%= ',' if index < attributes.length - 1 %>
|
942
1040
|
<% elsif attribute.type == :decimal || attribute.type == :float -%>
|
943
1041
|
<%= attribute.name %>: i * 10.5<%= ',' if index < attributes.length - 1 %>
|
944
|
-
<% elsif attribute.type == :json || attribute.
|
1042
|
+
<% elsif attribute.type == :json || attribute.type == :jsonb -%>
|
945
1043
|
<% if attribute.name == 'metadata' -%>
|
946
1044
|
<%= attribute.name %>: {
|
947
1045
|
resource_type: "<%= singular_table_name %>",
|
@@ -955,7 +1053,24 @@ if attributes.any? { |attr| attr.type == :references && attr.name == 'user' } &&
|
|
955
1053
|
<% elsif attribute.name == 'settings' -%>
|
956
1054
|
<%= attribute.name %>: { dark_mode: i.even?, notifications: { email: true, sms: i.even? } }<%= ',' if index < attributes.length - 1 %>
|
957
1055
|
<% else -%>
|
958
|
-
<%= attribute.name %>: {
|
1056
|
+
<%= attribute.name %>: {
|
1057
|
+
field_type: "jsonb_field",
|
1058
|
+
test_data: {
|
1059
|
+
string_value: "api_test_data",
|
1060
|
+
numeric_value: 123,
|
1061
|
+
boolean_value: true,
|
1062
|
+
array_value: ["test1", "test2", "test3"],
|
1063
|
+
nested_object: {
|
1064
|
+
property: "api_value",
|
1065
|
+
settings: ["api_option1", "api_option2"]
|
1066
|
+
}
|
1067
|
+
},
|
1068
|
+
metadata: {
|
1069
|
+
generated_by: "integration_test",
|
1070
|
+
field_name: "<%= attribute.name %>",
|
1071
|
+
test_id: "workflow_test"
|
1072
|
+
}
|
1073
|
+
}<%= ',' if index < attributes.length - 1 %>
|
959
1074
|
<% end -%>
|
960
1075
|
<% else -%>
|
961
1076
|
<%= attribute.name %>: "bulk_#{i}"<%= ',' if index < attributes.length - 1 %>
|
data/lib/propel_api.rb
CHANGED