Skip to content

Commit

Permalink
validate at least 1 property in subschemas, valid for locale in root …
Browse files Browse the repository at this point in the history
…requires at least 1 property
  • Loading branch information
patodevilla committed Mar 7, 2024
1 parent 13664c5 commit 42a0849
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ GIT
PATH
remote: .
specs:
json_schema_form (0.15.22)
json_schema_form (0.15.23)
activesupport (~> 6)
dry-schema (~> 1.13)
json_schemer (= 2.1.1)
Expand Down
13 changes: 9 additions & 4 deletions lib/jsf/forms/concerns/display_properties.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module DisplayProperties
#
# @return [Boolean] true when hidden
def hidden?
!!self.dig(:displayProperties, :hidden)
!!dig(:displayProperties, :hidden)
end

# Set hidden
Expand All @@ -30,7 +30,7 @@ def hidden=(value)
#
# @return [Boolean] value
def hideOnCreate?
!!self.dig(:displayProperties, :hideOnCreate)
!!dig(:displayProperties, :hideOnCreate)
end

# Set hidden
Expand All @@ -45,7 +45,7 @@ def hideOnCreate=(value)
#
# @return [<Type>] <description>
def sort
self.dig(:displayProperties, :sort)
dig(:displayProperties, :sort)
end

# Set sort
Expand All @@ -60,7 +60,7 @@ def sort=(value)
# @param [String,Symbol] locale
# @return [String]
def i18n_label(locale = DEFAULT_LOCALE)
self.dig(:displayProperties, :i18n, :label, locale)
dig(:displayProperties, :i18n, :label, locale)
end

# Set the i18n label
Expand All @@ -77,6 +77,11 @@ def visible(is_create:)
!self.hidden? && !(is_create && self.hideOnCreate?)
end

# @return [String]
def component
dig(:displayProperties, :component)
end

end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/jsf/forms/field/video.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Video < BaseHash
# @return [Dry::Schema::JSON] Schema
def dry_schema(passthru)
hide_on_create = run_validation?(passthru, :hideOnCreate, optional: true)
exam = run_validation?(passthru, :exam, optional: true)
# exam = run_validation?(passthru, :exam, optional: true)

Dry::Schema.JSON(parent: super) do
required(:displayProperties).hash do
Expand Down
27 changes: 21 additions & 6 deletions lib/jsf/forms/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Form < BaseHash
include JSF::Validations::DrySchemaValidatable
include JSF::Core::Buildable
include JSF::Core::Type::Objectable
include JSF::Forms::Concerns::DisplayProperties

set_strict_type('object')

Expand Down Expand Up @@ -169,7 +170,6 @@ def dry_schema(passthru)
is_subschema = meta[:is_subschema]
scoring = run_validation?(passthru, :scoring, optional: true)
exam = run_validation?(passthru, :exam, optional: true)
parent_key = self.key_name if exam

Dry::Schema.JSON do
config.validate_keys = true
Expand Down Expand Up @@ -234,6 +234,16 @@ def dry_schema(passthru)
def errors(**passthru)
errors_hash = super

if run_validation?(passthru, :subschema_properties) &&
meta[:is_subschema] &&
properties.none?{|_k, v| v.visible(is_create: false) }
add_error_on_path(
errors_hash,
['properties'],
'at least 1 property must exist'
)
end

# validate sorting
if run_validation?(passthru, :sorting)
unless self.verify_sort_order
Expand Down Expand Up @@ -331,25 +341,30 @@ def errors(**passthru)
# respond to 'response_set', also check that response set is
# valid for locale
#
# If no properties are present, returns false unless subschema
#
# @param locale [String,Symbol] locale
# @return [Boolean]
def valid_for_locale?(locale = DEFAULT_LOCALE, ignore_sections: true, ignore_defs: false)
prop = nil
return false if dig('displayProperties', 'component') == 'exam' && i18n_label(locale).to_s.empty?

# require at least 1 property for root schemas
any_property = meta[:is_subschema]

# check properties and their response_sets
each_form(ignore_sections:, ignore_defs:) do |form|
prop = form&.properties&.any? do |k,v|
return false if form.properties.any? do |k,v|
any_property = true

if v.respond_to?(:response_set)
!v.valid_for_locale?(locale) || !v.response_set&.valid_for_locale?(locale)
else
!v.valid_for_locale?(locale)
end
end

break prop if prop
end

!prop
any_property
end

##############
Expand Down
5 changes: 5 additions & 0 deletions lib/jsf/forms/shared_ref.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ def db_id=(id)
self[:$ref] = id
end

# @return [Boolean]
def valid_for_locale?(locale=nil)
true
end

end

end
Expand Down
1 change: 1 addition & 0 deletions lib/jsf/validations/validatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def run_validation?(passthru, validation_key, optional: false)
else
return false if passthru[:if]&.call(self, validation_key) == false
return false if passthru[:unless]&.call(self, validation_key) == true
# todo except, only

true
end
Expand Down
2 changes: 1 addition & 1 deletion lib/jsf/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module JSF
VERSION = "0.15.22"
VERSION = "0.15.23"
end
8 changes: 8 additions & 0 deletions test/spec/forms/concerns/display_properties_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,12 @@ def test_i18n_label
assert_equal '__some_label__', instance.i18n_label
end

def test_component
SampleSchema.include(JSF::Forms::Concerns::DisplayProperties)
instance = SampleSchema.new

SuperHash::Utils.bury(instance, :displayProperties, :component, 'test')
assert_equal 'test', instance.component
end

end
10 changes: 6 additions & 4 deletions test/spec/forms/form_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ def test_fixtures
{trait: :failing, errors_args: {optional_if: ->(_,k) { k == :failing }}},
{trait: :scoring_and_failing , errors_args: {optional_if: ->(_,k) { %i[scoring failing].include?(k) }}},
],
JSF::Forms::Section => [],
JSF::Forms::Section => [
{trait: nil, errors_args: { unless: ->(_, k) { k == :subschema_properties } }},
],

# fields
JSF::Forms::Field::Checkbox => [
Expand All @@ -45,18 +47,18 @@ def test_fixtures
}

klasses.each do |klass, traits_array|
skip_valid_for_locale = [JSF::Forms::SharedRef, JSF::Forms::Section].include?(klass)
assert_value = ![JSF::Forms::Form].include?(klass) # expected to be false

if traits_array.empty?
hash = JSF::Forms::FormBuilder.example_for(klass)
instance = klass.new(hash)
assert_equal true, instance.valid_for_locale? unless skip_valid_for_locale
assert_equal assert_value, instance.valid_for_locale?
assert_empty instance.errors
else
traits_array.each do |obj|
hash = JSF::Forms::FormBuilder.example_for(klass, obj[:trait])
instance = klass.new(hash)
assert_equal true, instance.valid_for_locale? unless skip_valid_for_locale
assert_equal assert_value, instance.valid_for_locale?
assert_empty instance.errors(**obj[:errors_args])
end
end
Expand Down
30 changes: 18 additions & 12 deletions test/spec/forms/form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ def test_transform

# errors

def test_subschema_properties_validation
error_proc = ->(obj, key) { obj.is_a?(JSF::Forms::Form) && key == :subschema_properties }

form = JSF::Forms::Form.new
assert_empty form.errors(if: error_proc)

form.meta[:is_subschema] = true
refute_empty form.errors(if: error_proc)

form = JSF::Forms::FormBuilder.build(form) do
append_property(:switch_1, example('switch'))
end
assert_empty form.errors(if: error_proc)
end

def test_schema_key_validations
error_proc = ->(obj, key) { obj.is_a?(JSF::Forms::Form) && key == :schema }

Expand Down Expand Up @@ -211,18 +226,8 @@ def test_conditions_format
end

def test_valid_subschema_form
form = JSF::Forms::Form.new(
{
"required": [],
"properties": {},
"allOf": [],
"type": "object"
},
meta: {
is_subschema: true
}
)
assert_empty form.errors
form = JSF::Forms::Form.new({}, meta: { is_subschema: true })
assert_empty form.errors(unless: ->(_, k) { k == :subschema_properties })
end

# valid_for_locale?
Expand Down Expand Up @@ -270,6 +275,7 @@ def test_valid_for_locale_when_invalid_unused_response_set
add_response_set(:response_set_1, example('response_set')).tap do |response_set|
response_set.add_response(example('response'))
end
append_property :dependent_markdown, example('markdown')
end
assert_equal true, form.valid_for_locale?
form.response_sets[:response_set_1][:anyOf].each{|r| r.set_translation(nil) }
Expand Down
4 changes: 2 additions & 2 deletions test/spec/forms/section_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ def test_valid_for_locale
instance[:items] = {}
assert_equal true, instance.valid_for_locale?

# valid form
# valid property
JSF::Forms::FormBuilder.build(instance[:items]) do
append_property(:switch_1, example('switch'))
end
assert_equal true, instance.valid_for_locale?

# invalid form
# invalid property
instance[:items].get_property('switch_1').set_label_for_locale(nil)
assert_equal false, instance.valid_for_locale?

Expand Down

0 comments on commit 42a0849

Please sign in to comment.