standardapi 6.0.0.26 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +15 -6
- data/lib/standard_api.rb +5 -0
- data/lib/standard_api/access_control_list.rb +114 -0
- data/lib/standard_api/active_record/connection_adapters/postgresql/schema_statements.rb +21 -0
- data/lib/standard_api/controller.rb +75 -78
- data/lib/standard_api/errors.rb +9 -0
- data/lib/standard_api/helpers.rb +66 -13
- data/lib/standard_api/includes.rb +9 -0
- data/lib/standard_api/middleware/query_encoding.rb +3 -3
- data/lib/standard_api/railtie.rb +13 -2
- data/lib/standard_api/route_helpers.rb +5 -5
- data/lib/standard_api/test_case.rb +24 -14
- data/lib/standard_api/test_case/calculate_tests.rb +10 -4
- data/lib/standard_api/test_case/create_tests.rb +13 -15
- data/lib/standard_api/test_case/index_tests.rb +14 -4
- data/lib/standard_api/test_case/schema_tests.rb +25 -3
- data/lib/standard_api/test_case/show_tests.rb +1 -0
- data/lib/standard_api/test_case/update_tests.rb +8 -9
- data/lib/standard_api/version.rb +1 -1
- data/lib/standard_api/views/application/_record.json.jbuilder +33 -30
- data/lib/standard_api/views/application/_record.streamer +36 -34
- data/lib/standard_api/views/application/_schema.json.jbuilder +68 -0
- data/lib/standard_api/views/application/_schema.streamer +78 -0
- data/lib/standard_api/views/application/new.streamer +1 -1
- data/lib/standard_api/views/application/schema.json.jbuilder +1 -12
- data/lib/standard_api/views/application/schema.streamer +1 -16
- data/test/standard_api/caching_test.rb +43 -0
- data/test/standard_api/helpers_test.rb +172 -0
- data/test/standard_api/performance.rb +39 -0
- data/test/standard_api/route_helpers_test.rb +33 -0
- data/test/standard_api/standard_api_test.rb +699 -0
- data/test/standard_api/test_app.rb +1 -0
- data/test/standard_api/test_app/app/controllers/acl/account_acl.rb +15 -0
- data/test/standard_api/test_app/app/controllers/acl/property_acl.rb +27 -0
- data/test/standard_api/test_app/app/controllers/acl/reference_acl.rb +7 -0
- data/test/standard_api/test_app/controllers.rb +13 -45
- data/test/standard_api/test_app/models.rb +38 -4
- data/test/standard_api/test_app/test/factories.rb +4 -3
- data/test/standard_api/test_app/views/photos/_photo.json.jbuilder +1 -0
- data/test/standard_api/test_app/views/photos/_photo.streamer +18 -0
- data/test/standard_api/test_app/views/photos/_schema.json.jbuilder +1 -0
- data/test/standard_api/test_app/views/photos/_schema.streamer +3 -0
- data/test/standard_api/test_app/views/photos/schema.json.jbuilder +1 -1
- data/test/standard_api/test_app/views/photos/schema.streamer +1 -0
- data/test/standard_api/test_helper.rb +238 -0
- metadata +33 -17
- data/test/standard_api/test_app/log/test.log +0 -129516
data/lib/standard_api/errors.rb
CHANGED
@@ -2,6 +2,15 @@ module StandardAPI
|
|
2
2
|
class StandardAPIError < StandardError
|
3
3
|
end
|
4
4
|
|
5
|
+
class ParameterMissing < StandardAPIError
|
6
|
+
attr_reader :param
|
7
|
+
|
8
|
+
def initialize(param)
|
9
|
+
@param = param
|
10
|
+
super("param is missing or the value is empty: #{param}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
class UnpermittedParameters < StandardAPIError
|
6
15
|
attr_reader :params
|
7
16
|
|
data/lib/standard_api/helpers.rb
CHANGED
@@ -1,6 +1,58 @@
|
|
1
1
|
module StandardAPI
|
2
2
|
module Helpers
|
3
|
-
|
3
|
+
|
4
|
+
def preloadables(record, includes)
|
5
|
+
preloads = {}
|
6
|
+
|
7
|
+
includes.each do |key, value|
|
8
|
+
if reflection = record.klass.reflections[key]
|
9
|
+
case value
|
10
|
+
when true
|
11
|
+
preloads[key] = value
|
12
|
+
when Hash, ActiveSupport::HashWithIndifferentAccess
|
13
|
+
if !value.keys.any? { |x| ['when', 'where', 'limit', 'offset', 'order', 'distinct'].include?(x) }
|
14
|
+
if !reflection.polymorphic?
|
15
|
+
preloads[key] = preloadables_hash(reflection.klass, value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
preloads.empty? ? record : record.preload(preloads)
|
23
|
+
end
|
24
|
+
|
25
|
+
def preloadables_hash(klass, iclds)
|
26
|
+
preloads = {}
|
27
|
+
|
28
|
+
iclds.each do |key, value|
|
29
|
+
if reflection = klass.reflections[key]
|
30
|
+
case value
|
31
|
+
when true
|
32
|
+
preloads[key] = value
|
33
|
+
when Hash, ActiveSupport::HashWithIndifferentAccess
|
34
|
+
if !value.keys.any? { |x| ['when', 'where', 'limit', 'offset', 'order', 'distinct'].include?(x) }
|
35
|
+
if !reflection.polymorphic?
|
36
|
+
preloads[key] = preloadables_hash(reflection.klass, value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
preloads
|
44
|
+
end
|
45
|
+
|
46
|
+
def schema_partial(model)
|
47
|
+
path = model.model_name.plural
|
48
|
+
|
49
|
+
if lookup_context.exists?("schema", path, true)
|
50
|
+
[path, "schema"].join('/')
|
51
|
+
else
|
52
|
+
'application/schema'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
4
56
|
def model_partial(record)
|
5
57
|
if lookup_context.exists?(record.model_name.element, record.model_name.plural, true)
|
6
58
|
[record.model_name.plural, record.model_name.element].join('/')
|
@@ -17,7 +69,7 @@ module StandardAPI
|
|
17
69
|
false
|
18
70
|
end
|
19
71
|
end
|
20
|
-
|
72
|
+
|
21
73
|
def cache_key(record, includes)
|
22
74
|
timestamp_keys = ['cached_at'] + record.class.column_names.select{|x| x.ends_with? "_cached_at"}
|
23
75
|
if includes.empty?
|
@@ -27,21 +79,22 @@ module StandardAPI
|
|
27
79
|
"#{record.model_name.cache_key}/#{record.id}-#{digest_hash(sort_hash(includes))}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
|
28
80
|
end
|
29
81
|
end
|
30
|
-
|
31
|
-
def can_cache_relation?(
|
82
|
+
|
83
|
+
def can_cache_relation?(record, relation, subincludes)
|
84
|
+
return false if record.new_record?
|
32
85
|
cache_columns = ["#{relation}_cached_at"] + cached_at_columns_for_includes(subincludes).map {|c| "#{relation}_#{c}"}
|
33
|
-
if (cache_columns -
|
86
|
+
if (cache_columns - record.class.column_names).empty?
|
34
87
|
true
|
35
88
|
else
|
36
89
|
false
|
37
90
|
end
|
38
91
|
end
|
39
|
-
|
92
|
+
|
40
93
|
def association_cache_key(record, relation, subincludes)
|
41
94
|
timestamp = ["#{relation}_cached_at"] + cached_at_columns_for_includes(subincludes).map {|c| "#{relation}_#{c}"}
|
42
|
-
timestamp.map! { |col| record.send(col) }
|
95
|
+
timestamp = (timestamp & record.class.column_names).map! { |col| record.send(col) }
|
43
96
|
timestamp = timestamp.max
|
44
|
-
|
97
|
+
|
45
98
|
case association = record.class.reflect_on_association(relation)
|
46
99
|
when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::HasOneReflection, ActiveRecord::Reflection::ThroughReflection
|
47
100
|
"#{record.model_name.cache_key}/#{record.id}/#{includes_to_cache_key(relation, subincludes)}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
|
@@ -56,13 +109,13 @@ module StandardAPI
|
|
56
109
|
raise ArgumentError, 'Unkown association type'
|
57
110
|
end
|
58
111
|
end
|
59
|
-
|
112
|
+
|
60
113
|
def cached_at_columns_for_includes(includes)
|
61
114
|
includes.select { |k,v| !['when', 'where', 'limit', 'order', 'distinct', 'distinct_on'].include?(k) }.map do |k, v|
|
62
115
|
["#{k}_cached_at"] + cached_at_columns_for_includes(v).map { |v2| "#{k}_#{v2}" }
|
63
116
|
end.flatten
|
64
117
|
end
|
65
|
-
|
118
|
+
|
66
119
|
def includes_to_cache_key(relation, subincludes)
|
67
120
|
if subincludes.empty?
|
68
121
|
relation.to_s
|
@@ -70,7 +123,7 @@ module StandardAPI
|
|
70
123
|
"#{relation}-#{digest_hash(sort_hash(subincludes))}"
|
71
124
|
end
|
72
125
|
end
|
73
|
-
|
126
|
+
|
74
127
|
def sort_hash(hash)
|
75
128
|
hash.keys.sort.reduce({}) do |seed, key|
|
76
129
|
if seed[key].is_a?(Hash)
|
@@ -81,7 +134,7 @@ module StandardAPI
|
|
81
134
|
seed
|
82
135
|
end
|
83
136
|
end
|
84
|
-
|
137
|
+
|
85
138
|
def digest_hash(*hashes)
|
86
139
|
hashes.compact!
|
87
140
|
hashes.map! { |h| sort_hash(h) }
|
@@ -141,4 +194,4 @@ module StandardAPI
|
|
141
194
|
end
|
142
195
|
|
143
196
|
end
|
144
|
-
end
|
197
|
+
end
|
@@ -20,6 +20,15 @@ module StandardAPI
|
|
20
20
|
normalized[k] = case k.to_s
|
21
21
|
when 'when', 'where', 'order'
|
22
22
|
case v
|
23
|
+
when Array
|
24
|
+
v.map do |x|
|
25
|
+
case x
|
26
|
+
when Hash then x.to_h
|
27
|
+
when ActionController::Parameters then x.to_unsafe_h
|
28
|
+
else
|
29
|
+
x
|
30
|
+
end
|
31
|
+
end
|
23
32
|
when Hash then v.to_h
|
24
33
|
when ActionController::Parameters then v.to_unsafe_h
|
25
34
|
end
|
@@ -13,8 +13,8 @@ require 'msgpack'
|
|
13
13
|
module StandardAPI
|
14
14
|
module Middleware
|
15
15
|
class QueryEncoding
|
16
|
-
MSGPACK_MIME_TYPE = "application/msgpack"
|
17
|
-
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_QUERY_ENCODING"
|
16
|
+
MSGPACK_MIME_TYPE = "application/msgpack"
|
17
|
+
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_QUERY_ENCODING"
|
18
18
|
|
19
19
|
def initialize(app)
|
20
20
|
@app = app
|
@@ -31,4 +31,4 @@ module StandardAPI
|
|
31
31
|
|
32
32
|
end
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
data/lib/standard_api/railtie.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
module StandardAPI
|
2
2
|
class Railtie < ::Rails::Railtie
|
3
3
|
|
4
|
-
initializer 'standardapi' do
|
4
|
+
initializer 'standardapi', :before => :set_autoload_paths do |app|
|
5
|
+
if app.root.join('app', 'controllers', 'acl').exist?
|
6
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
7
|
+
inflect.acronym 'ACL'
|
8
|
+
end
|
9
|
+
|
10
|
+
app.config.autoload_paths << app.root.join('app', 'controllers', 'acl').to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveSupport.on_load(:before_configuration) do
|
14
|
+
::ActionDispatch::Routing::Mapper.send :include, StandardAPI::RouteHelpers
|
15
|
+
end
|
16
|
+
|
5
17
|
ActiveSupport.on_load(:action_view) do
|
6
18
|
::ActionView::Base.send :include, StandardAPI::Helpers
|
7
|
-
::ActionDispatch::Routing::Mapper.send :include, StandardAPI::RouteHelpers
|
8
19
|
end
|
9
20
|
end
|
10
21
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module StandardAPI
|
2
2
|
module RouteHelpers
|
3
|
-
|
3
|
+
|
4
4
|
# StandardAPI wrapper for ActionDispatch::Routing::Mapper::Resources#resources
|
5
5
|
#
|
6
6
|
# Includes the following routes
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# GET /schema
|
9
9
|
# GET /calculate
|
10
10
|
#
|
@@ -20,7 +20,7 @@ module StandardAPI
|
|
20
20
|
# end
|
21
21
|
def standard_resources(*resources, &block)
|
22
22
|
options = resources.extract_options!.dup
|
23
|
-
|
23
|
+
|
24
24
|
resources(*resources, options) do
|
25
25
|
get :schema, on: :collection
|
26
26
|
get :calculate, on: :collection
|
@@ -33,7 +33,7 @@ module StandardAPI
|
|
33
33
|
# StandardAPI wrapper for ActionDispatch::Routing::Mapper::Resources#resource
|
34
34
|
#
|
35
35
|
# Includes the following routes
|
36
|
-
#
|
36
|
+
#
|
37
37
|
# GET /schema
|
38
38
|
# GET /calculate
|
39
39
|
#
|
@@ -49,7 +49,7 @@ module StandardAPI
|
|
49
49
|
# end
|
50
50
|
def standard_resource(*resource, &block)
|
51
51
|
options = resource.extract_options!.dup
|
52
|
-
|
52
|
+
|
53
53
|
resource(*resource, options) do
|
54
54
|
get :schema, on: :collection
|
55
55
|
get :calculate, on: :collection
|
@@ -18,15 +18,14 @@ module StandardAPI::TestCase
|
|
18
18
|
assert_equal(expected, *args)
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def self.included(klass)
|
23
23
|
[:filters, :orders, :includes].each do |attribute|
|
24
24
|
klass.send(:class_attribute, attribute)
|
25
25
|
end
|
26
26
|
|
27
27
|
begin
|
28
|
-
|
29
|
-
model_class = model_class_name.constantize
|
28
|
+
model_class = klass.name.gsub(/Test$/, '').constantize.model
|
30
29
|
|
31
30
|
klass.send(:filters=, model_class.attribute_names)
|
32
31
|
klass.send(:orders=, model_class.attribute_names)
|
@@ -53,14 +52,14 @@ module StandardAPI::TestCase
|
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
56
|
-
def supports_format(format)
|
55
|
+
def supports_format(format, action=nil)
|
57
56
|
count = controller_class.view_paths.count do |path|
|
58
|
-
!Dir.glob("#{path.instance_variable_get(:@path)}/{#{model.name.underscore},application}
|
57
|
+
!Dir.glob("#{path.instance_variable_get(:@path)}/{#{model.name.underscore},application}/**/#{action || '*'}.#{format}*").empty?
|
59
58
|
end
|
60
|
-
|
59
|
+
|
61
60
|
count > 0
|
62
61
|
end
|
63
|
-
|
62
|
+
|
64
63
|
def default_orders
|
65
64
|
controller_class.new.send(:default_orders)
|
66
65
|
end
|
@@ -76,7 +75,7 @@ module StandardAPI::TestCase
|
|
76
75
|
def model
|
77
76
|
self.class.model
|
78
77
|
end
|
79
|
-
|
78
|
+
|
80
79
|
def mask
|
81
80
|
{}
|
82
81
|
end
|
@@ -98,11 +97,11 @@ module StandardAPI::TestCase
|
|
98
97
|
def singular_name
|
99
98
|
model.model_name.singular
|
100
99
|
end
|
101
|
-
|
100
|
+
|
102
101
|
def plural_name
|
103
102
|
model.model_name.plural
|
104
103
|
end
|
105
|
-
|
104
|
+
|
106
105
|
def create_webmocks(attributes)
|
107
106
|
attributes.each do |attribute, value|
|
108
107
|
self.class.model.validators_on(attribute)
|
@@ -122,7 +121,7 @@ module StandardAPI::TestCase
|
|
122
121
|
value
|
123
122
|
end
|
124
123
|
end
|
125
|
-
|
124
|
+
|
126
125
|
def normalize_to_json(record, attribute, value)
|
127
126
|
value = normalize_attribute(record, attribute, value)
|
128
127
|
return nil if value.nil?
|
@@ -138,8 +137,19 @@ module StandardAPI::TestCase
|
|
138
137
|
|
139
138
|
def view_attributes(record)
|
140
139
|
return [] if record.nil?
|
141
|
-
record.attributes.select
|
140
|
+
record.attributes.select do |x|
|
141
|
+
!@controller.send(:excludes_for, record.class).include?(x.to_sym)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def update_attributes(record)
|
146
|
+
return [] if record.nil?
|
147
|
+
record.attributes.select do |x|
|
148
|
+
!record.class.readonly_attributes.include?(x.to_s) &&
|
149
|
+
!@controller.send(:excludes_for, record.class).include?(x.to_sym)
|
150
|
+
end
|
142
151
|
end
|
152
|
+
alias_method :create_attributes, :update_attributes
|
143
153
|
|
144
154
|
module ClassMethods
|
145
155
|
|
@@ -149,7 +159,7 @@ module StandardAPI::TestCase
|
|
149
159
|
|
150
160
|
def controller_class
|
151
161
|
controller_class_name = self.name.gsub(/Test$/, '')
|
152
|
-
controller_class_name.constantize
|
162
|
+
controller_class_name.constantize
|
153
163
|
rescue NameError => e
|
154
164
|
raise e if e.message != "uninitialized constant #{controller_class_name}"
|
155
165
|
end
|
@@ -166,7 +176,7 @@ module StandardAPI::TestCase
|
|
166
176
|
return @model if defined?(@model) && @model
|
167
177
|
|
168
178
|
klass_name = controller_class.name.gsub(/Controller$/, '').singularize
|
169
|
-
|
179
|
+
|
170
180
|
begin
|
171
181
|
@model = klass_name.constantize
|
172
182
|
rescue NameError
|
@@ -12,7 +12,7 @@ module StandardAPI
|
|
12
12
|
create_model
|
13
13
|
|
14
14
|
math_column = model.columns.find { |x| CALCULATE_COLUMN_TYPES.include?(x.sql_type) }
|
15
|
-
|
15
|
+
|
16
16
|
if math_column
|
17
17
|
column = math_column
|
18
18
|
selects = [{ count: column.name }, { maximum: column.name }, { minimum: column.name }, { average: column.name }]
|
@@ -26,8 +26,14 @@ module StandardAPI
|
|
26
26
|
calculations = @controller.instance_variable_get('@calculations')
|
27
27
|
expectations = selects.map { |s| model.send(s.keys.first, column.name) }
|
28
28
|
expectations = [expectations] if expectations.length > 1
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
if math_column
|
31
|
+
assert_equal expectations.map { |a| a.map { |b| b.round(9) } },
|
32
|
+
calculations.map { |a| a.map { |b| b.round(9) } }
|
33
|
+
else
|
34
|
+
assert_equal expectations.map { |b| b.round(9) },
|
35
|
+
calculations.map { |b| b.round(9) }
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
test '#calculate.json params[:where]' do
|
@@ -35,7 +41,7 @@ module StandardAPI
|
|
35
41
|
create_model
|
36
42
|
|
37
43
|
math_column = model.columns.find { |x| CALCULATE_COLUMN_TYPES.include?(x.sql_type) }
|
38
|
-
|
44
|
+
|
39
45
|
if math_column
|
40
46
|
column = math_column
|
41
47
|
selects = [{ count: column.name}, { maximum: column.name }, { minimum: column.name }, { average: column.name }]
|
@@ -22,7 +22,7 @@ module StandardAPI
|
|
22
22
|
json = JSON.parse(response.body)
|
23
23
|
assert json.is_a?(Hash)
|
24
24
|
|
25
|
-
|
25
|
+
create_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
|
26
26
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
27
27
|
if value.is_a?(BigDecimal)
|
28
28
|
assert_equal_or_nil normalize_to_json(m, key, attrs[key.to_sym]).to_s.to_f, json[key.to_s].to_s.to_f, message
|
@@ -53,9 +53,9 @@ module StandardAPI
|
|
53
53
|
json = JSON.parse(response.body)
|
54
54
|
assert json.is_a?(Hash)
|
55
55
|
m.reload
|
56
|
-
|
56
|
+
create_attributes(m).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
|
57
57
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
58
|
-
assert_equal_or_nil normalize_attribute(m, key, attrs[key.to_sym]), value, message
|
58
|
+
assert_equal_or_nil normalize_attribute(m, key, attrs[key.to_sym]), normalize_attribute(m, key, value), message
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -64,8 +64,7 @@ module StandardAPI
|
|
64
64
|
trait = FactoryBot.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
65
65
|
|
66
66
|
if !trait
|
67
|
-
|
68
|
-
warn("No invalid trait for #{model.name}. Skipping invalid tests")
|
67
|
+
skip("No invalid trait for #{model.name}. Skipping invalid tests")
|
69
68
|
return
|
70
69
|
end
|
71
70
|
|
@@ -85,15 +84,15 @@ module StandardAPI
|
|
85
84
|
end
|
86
85
|
|
87
86
|
test '#create.html' do
|
88
|
-
return unless supports_format(:html)
|
87
|
+
return unless supports_format(:html, :create)
|
88
|
+
|
89
|
+
attrs = attributes_for(singular_name, :nested).select do |k,v|
|
90
|
+
!model.readonly_attributes.include?(k.to_s)
|
91
|
+
end
|
89
92
|
|
90
|
-
attrs = attributes_for(singular_name, :nested).select{ |k,v| !model.readonly_attributes.include?(k.to_s) }
|
91
93
|
mask.each { |k, v| attrs[k] = v }
|
92
94
|
create_webmocks(attrs)
|
93
95
|
|
94
|
-
file_upload = attrs.any? { |k, v| v.is_a?(Rack::Test::UploadedFile) }
|
95
|
-
as = file_upload ? nil : :json
|
96
|
-
|
97
96
|
assert_difference("#{model.name}.count") do
|
98
97
|
post resource_path(:create), params: { singular_name => attrs }, as: :html
|
99
98
|
assert_response :redirect
|
@@ -101,13 +100,12 @@ module StandardAPI
|
|
101
100
|
end
|
102
101
|
|
103
102
|
test '#create.html with invalid attributes renders edit action' do
|
104
|
-
return unless supports_format(:html)
|
103
|
+
return unless supports_format(:html, :create)
|
105
104
|
|
106
105
|
trait = FactoryBot.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
107
106
|
|
108
107
|
if !trait
|
109
|
-
|
110
|
-
warn("No invalid trait for #{model.name}. Skipping invalid tests")
|
108
|
+
skip("No invalid trait for #{model.name}. Skipping invalid tests")
|
111
109
|
return
|
112
110
|
end
|
113
111
|
|
@@ -146,7 +144,7 @@ module StandardAPI
|
|
146
144
|
next if !association
|
147
145
|
|
148
146
|
if ['belongs_to', 'has_one'].include?(association.macro.to_s)
|
149
|
-
|
147
|
+
create_attributes(m.send(included)) do |key, value|
|
150
148
|
assert_equal json[included.to_s][key.to_s], normalize_to_json(m, key, value)
|
151
149
|
end
|
152
150
|
else
|
@@ -160,7 +158,7 @@ module StandardAPI
|
|
160
158
|
nil
|
161
159
|
end
|
162
160
|
|
163
|
-
|
161
|
+
create_attributes(m2).each do |key, value|
|
164
162
|
message = "Model / Attribute: #{m2.class.name}##{key}"
|
165
163
|
if m_json[key.to_s].nil?
|
166
164
|
assert_nil normalize_to_json(m2, key, value), message
|