Skip to content

Conversation

@mahdiarn
Copy link

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

Check defined on RSpec.configure instead of RSpec to avoid undefined method exception

💡 Motivation and Context

Issue happened on:

  • dry-validation-matchers 1.2.2
  • Ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [arm64-darwin21]
  • Rails 7.0.4.3
  • Gemfile depends on rspec-rails gem only and not depends on rspec-core directly
  • dry-validation-matchers gem was defined after rspec-rails gem

Issue trigger:

  • run rails c
  • run rails s -b 0.0.0.0

Error log when exception raised:

/Users/username/.rvm/gems/ruby-3.0.0/gems/dry-validation-matchers-1.2.2/lib/dry/validation/matchers/integrations/rspec.rb:2:in `<main>': undefined method `configure' for RSpec:Module (NoMethodError)
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/zeitwerk-2.6.7/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/dry-validation-matchers-1.2.2/lib/dry/validation/matchers.rb:5:in `<main>'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/zeitwerk-2.6.7/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/dry-validation-matchers-1.2.2/lib/dry-validation-matchers.rb:1:in `<main>'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/zeitwerk-2.6.7/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bundler-2.3.23/lib/bundler/runtime.rb:60:in `block (2 levels) in require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bundler-2.3.23/lib/bundler/runtime.rb:55:in `each'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bundler-2.3.23/lib/bundler/runtime.rb:55:in `block in require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bundler-2.3.23/lib/bundler/runtime.rb:44:in `each'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bundler-2.3.23/lib/bundler/runtime.rb:44:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bundler-2.3.23/lib/bundler.rb:187:in `require'
	from /Users/username/Documents/hyrd/repo/hyrd-api/config/application.rb:7:in `<main>'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/railties-7.0.4.2/lib/rails/commands/server/server_command.rb:137:in `block in perform'
	from <internal:kernel>:90:in `tap'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/railties-7.0.4.2/lib/rails/commands/server/server_command.rb:134:in `perform'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/railties-7.0.4.2/lib/rails/command/base.rb:87:in `perform'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/railties-7.0.4.2/lib/rails/command.rb:48:in `invoke'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/railties-7.0.4.2/lib/rails/commands.rb:18:in `<main>'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/username/.rvm/gems/ruby-3.0.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from bin/rails:4:in `<main>'

Analysis:

  • Based on the conditions mentioned above, the rspec-rails behavior was extending RSpec module, that makes the RSpec module defined but the configure method was not defined (ref)

Solution:

  • We do checking the RSpec.configure defined or not instead of checking RSpec. This also makes the checking more relate with the execution inside if defined? block because it only call the configure method

Alternative solution on this issue:

  • adding rspec-core to the gemfile and defined it before dry-validation-helper
    or
  • defining dry-validation-helper gem before rspec-rails gem

💚 How did you test it?

rake spec result:

Integration with RSpec
  is expected to validate for required `username` (filled with string) exists
  is expected to validate for optional `mobile` (filled with string) exists
  is expected to validate for optional `email` exists
  is expected to validate for optional `email` (macro usage `email`) exists
  is expected to validate for optional `decimal_value` (macro usage `{:precision=>5}`) exists

Dry::Validation::Matchers::ValidateMatcher
  checks value against `min_size`
  checks value against `max_size`
  attribute is required
    matches
  passing message details
    there are no details
      does not pollute the sentence with artifacts
  failing message details
    there are no details
      does not pollute the sentence with artifacts
  attribute is optional
    matches
  checking `filled` type that is more specific than rule
    matches
  checking `required` only
    matches
  checking `filled`
    matches
  checking `filled` type `str`
    matches
  checking `filled` type `int`
    matches
  checking `filled` type `float`
    matches
  checking `filled` type `decimal`
    matches
  checking `filled` type `bool`
    matches
  checking `filled` type `date`
    matches
  checking `filled` type `time`
    matches
  checking `filled` type `date_time`
    matches
  checking `filled` type `array`
    matches
  checking `filled` type `hash`
    matches
  checking value `included_in`
    matches
  given a wrong class to match
    raises an intelligible error
  #macro_use?
    when have one parameter
      returns true when macro uses
      returns false when macro unused
    when have two parameters
      returns true when macro uses
      returns false when macro unused
  #description
    gives an apt description of passing spec
    gives an apt description of passing macro spec
  #failure_message
commit cd95a5418774485d496215a56a11551bbc911213 (HEAD -> fix-rspec-rails-dependencies)
    gives enough clues to the developer
    gives enough clues to the developer when testing macro

Dry::Validation::Matchers
  has a version number

Finished in 0.19905 seconds (files took 0.4541 seconds to load)
35 examples, 0 failures

another testing methods:

  1. Run the rspec
  2. Run the rails c
  3. Run the rails s -b 0.0.0.0

📝 Checklist

  • I reviewed submitted code
  • I added tests to verify changes
  • I updated reference documentation to reflect the change
  • All tests passing
  • No breaking changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant