Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected error : unable to convert unpermitted parameters to hash #159

Open
ngouy opened this issue Nov 1, 2022 · 9 comments
Open

Unexpected error : unable to convert unpermitted parameters to hash #159

ngouy opened this issue Nov 1, 2022 · 9 comments
Labels

Comments

@ngouy
Copy link

ngouy commented Nov 1, 2022

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
Copy link
Author

ngouy commented Nov 1, 2022

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

@ngouy
Copy link
Author

ngouy commented Nov 1, 2022

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
Copy link
Author

ngouy commented Nov 1, 2022

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
Copy link
Author

ngouy commented Nov 1, 2022

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
Copy link
Author

ngouy commented Nov 1, 2022

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)

@mcmire
Copy link
Owner

mcmire commented Nov 8, 2022

@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?

@ngouy
Copy link
Author

ngouy commented Nov 8, 2022

💯 that's exactly that

@ngouy
Copy link
Author

ngouy commented Nov 8, 2022

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

@huguesbr
Copy link

@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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants