super_diff icon indicating copy to clipboard operation
super_diff copied to clipboard

Unexpected error : unable to convert unpermitted parameters to hash

Open ngouy opened this issue 2 years ago • 9 comments

When I run a specific spec without supper diff, spec is passing When I run it with it, it is failing The spec is using a custom matcher, that is itself a wrapp of a regular matcher:

RSpec::Matchers.define :be_within_last do |expected|
      match do |actual|
        actual = Time.zone.parse(actual) if actual.is_a?(String)
        actual = Time.zone.at(actual) if actual.is_a?(Integer)

        expect(actual).to be_within(expected).of(Time.current)
      end
    end

I have absolutely no clue on how it's working behind the scene. But here is what i can observe with debug breakpoints

It is failing in object_inspection/inspection_tree_builders/default_object.rb:46 In this context object is an instance a spec: RSpec::ExampleGroups::SurveysSubmissions::SurveysSubmissions::Post::<etc...> "does something"

41:                 insert_separated_list(object.instance_variables.sort) do |name|
42:                   as_prefix_when_rendering_to_lines do
43:                     add_text "#{name}="
44:                   end
45:
46:                   add_inspection_of object.instance_variable_get(name) # here
47:                 end
48:               end

One of the object instance_variable is @controller (which carries an instance of a controller) So it runs add_inspection_of(@controller)

Which latter on, recursively, goes to the exact same code where object is the actual @controller In this context, object is now instance of one of a controller

because one of the object.instance_variable is @_params = ActionController::Parameters <instance> And it runs add_inspection_of(@_params), which triggers:

@_params.to_hash (that then triggers) @_params.to_h

actionpack-7.0.4/lib/action_controller/metal/strong_parameters.rb:309 ActionController::Parameters#to_h:

305: def to_h
306:   if permitted?
307:     convert_parameters_to_hashes(@parameters, :to_h)
308:   else
309:     binding.pry # breakpoint
310:     raise UnfilteredParameters
311:   end
312: end

ngouy avatar Nov 01 '22 13:11 ngouy

If don't use my custom matcher (which is just a wrapper) and use directly the "original" rspec helper, it works

ngouy avatar Nov 01 '22 14:11 ngouy

found why

customer matcher has an @matcher_execution_context instance variable, that is "inspected" through the same piece of code with add_inspection_of... This context contains the instance of the spec, that contains @controller, that contains @params that is inspected with to_h

not sure how to solve that

ngouy avatar Nov 01 '22 14:11 ngouy

and as I understand it, to_h is called from "Ruby" itself because it needs to decompose the *args of

image

My args are not even printed when the faulty params are called, to that's my guess of what happens

ngouy avatar Nov 01 '22 15:11 ngouy

also lets say I override to_h in my action controller params to not raise params and return actual hash, super diff continue and deep_inspect the whole actual @matcher_execution_context which is not pretty to look at

Takes literally minutes

ngouy avatar Nov 01 '22 15:11 ngouy

Also for the record: my matcher was not constructed properly and the matching was failing, hence super_diff triggering

(when the custom matcher runs successfully, the issue is not here)

ngouy avatar Nov 01 '22 21:11 ngouy

@ngouy You say you're using a custom matcher and that a controller instance ends up being inspected when the matcher fails. Out of curiosity what is the test look like itself?

mcmire avatar Nov 08 '22 20:11 mcmire

💯 that's exactly that

ngouy avatar Nov 08 '22 20:11 ngouy

Test is a swagger test and it goes something like

post "/whatever" do
  response "200", "it does something" do
    run_test! do
      expect(response["created_at"]).to be_within_last(3.seconds) # my custom matcher call
    end
  end
end

ngouy avatar Nov 08 '22 20:11 ngouy

@ngouy @mcmire we're having the same issue when testing using rails controller functional test like

  it "..." do
    get :index
    expect(response).to be_client_error
  end
  0) BLRegistry::API::V2::TemplatesController does
     Failure/Error: expect(response).to be_client_error

     ActionController::UnfilteredParameters:
       unable to convert unpermitted parameters to hash

We can probably leverage custom diffing object (https://github.com/mcmire/super_diff#diffing-custom-objects) but not sure how complex it is?

For now the poor man solution is to disable super diff for this controller specs

# rails_helper.rb
require "super_diff/rspec-rails" unless defined?(DISABLE_SUPER_DIFF)
# controller_spec.rb
DISABLE_SUPER_DIFF = true
require "rails_helper"

Is there any options to disable super diff for a given test?

huguesbr avatar Jan 26 '23 09:01 huguesbr