Unexpected error : unable to convert unpermitted parameters to hash
ngouy opened this issue · 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
If don't use my custom matcher (which is just a wrapper) and use directly the "original" rspec helper, it works
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
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
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 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?
💯 that's exactly that
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 @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?