hanami-controller/test/action/params_test.rb

471 lines
14 KiB
Ruby

require 'test_helper'
require 'rack'
describe Hanami::Action::Params do
it 'is frozen'
# This is temporary suspended.
# We need to get the dependency Hanami::Validations, more stable before to enable this back.
#
# it 'is frozen' do
# params = Hanami::Action::Params.new({id: '23'})
# params.must_be :frozen?
# end
describe 'raw params' do
before do
@params = Class.new(Hanami::Action::Params)
end
describe "when this feature isn't enabled" do
before do
@action = ParamsAction.new
end
it 'raw gets all params' do
File.open('test/assets/multipart-upload.png', 'rb') do |upload|
@action.call('id' => '1', 'unknown' => '2', 'upload' => upload, '_csrf_token' => '3')
@action.params[:id].must_equal '1'
@action.params[:unknown].must_equal '2'
FileUtils.cmp(@action.params[:upload], upload).must_equal true
@action.params[:_csrf_token].must_equal '3'
@action.params.raw.fetch('id').must_equal '1'
@action.params.raw.fetch('unknown').must_equal '2'
@action.params.raw.fetch('upload').must_equal upload
@action.params.raw.fetch('_csrf_token').must_equal '3'
end
end
end
describe 'when this feature is enabled' do
before do
@action = WhitelistedUploadDslAction.new
end
it 'raw gets all params' do
Tempfile.create('multipart-upload') do |upload|
@action.call('id' => '1', 'unknown' => '2', 'upload' => upload, '_csrf_token' => '3')
@action.params[:id].must_equal '1'
@action.params[:unknown].must_equal nil
@action.params[:upload].must_equal upload
@action.params[:_csrf_token].must_equal '3'
@action.params.raw.fetch('id').must_equal '1'
@action.params.raw.fetch('unknown').must_equal '2'
@action.params.raw.fetch('upload').must_equal upload
@action.params.raw.fetch('_csrf_token').must_equal '3'
end
end
end
end
describe 'whitelisting' do
before do
@params = Class.new(Hanami::Action::Params)
end
describe "when this feature isn't enabled" do
before do
@action = ParamsAction.new
end
it 'creates a Params innerclass' do
assert defined?(ParamsAction::Params),
'expected ParamsAction::Params to be defined'
assert ParamsAction::Params.ancestors.include?(Hanami::Action::Params),
'expected ParamsAction::Params to be a Hanami::Action::Params subclass'
end
describe 'in testing mode' do
it 'returns all the params as they are' do
# For unit tests in Hanami projects, developers may want to define
# params with symbolized keys.
_, _, body = @action.call(a: '1', b: '2', c: '3')
body.must_equal [%({:a=>"1", :b=>"2", :c=>"3"})]
end
end
describe 'in a Rack context' do
it 'returns all the params as they are' do
# Rack params are always stringified
response = Rack::MockRequest.new(@action).request('PATCH', '?id=23', params: { 'x' => { 'foo' => 'bar' } })
response.body.must_match %({:id=>"23", :x=>{:foo=>"bar"}})
end
end
describe 'with Hanami::Router' do
it 'returns all the params as they are' do
# Hanami::Router params are always symbolized
_, _, body = @action.call('router.params' => { id: '23' })
body.must_equal [%({:id=>"23"})]
end
end
end
describe 'when this feature is enabled' do
describe 'with an explicit class' do
before do
@action = WhitelistedParamsAction.new
end
# For unit tests in Hanami projects, developers may want to define
# params with symbolized keys.
describe 'in testing mode' do
it 'returns only the listed params' do
_, _, body = @action.call(id: 23, unknown: 4, article: { foo: 'bar', tags: [:cool] })
body.must_equal [%({:id=>23, :article=>{:tags=>[:cool]}})]
end
it "doesn't filter _csrf_token" do
_, _, body = @action.call(_csrf_token: 'abc')
body.must_equal [%({:_csrf_token=>"abc"})]
end
end
describe "in a Rack context" do
it 'returns only the listed params' do
response = Rack::MockRequest.new(@action).request('PATCH', "?id=23", params: { x: { foo: 'bar' } })
response.body.must_match %({:id=>"23"})
end
it "doesn't filter _csrf_token" do
response = Rack::MockRequest.new(@action).request('PATCH', "?id=1", params: { _csrf_token: 'def', x: { foo: 'bar' } })
response.body.must_match %(:_csrf_token=>"def", :id=>"1")
end
end
describe "with Hanami::Router" do
it 'returns all the params coming from the router, even if NOT whitelisted' do
_, _, body = @action.call({ 'router.params' => {id: 23, another: 'x'}})
body.must_equal [%({:id=>23, :another=>"x"})]
end
end
end
describe "with an anoymous class" do
before do
@action = WhitelistedDslAction.new
end
it 'creates a Params innerclass' do
assert defined?(WhitelistedDslAction::Params),
"expected WhitelistedDslAction::Params to be defined"
assert WhitelistedDslAction::Params.ancestors.include?(Hanami::Action::Params),
"expected WhitelistedDslAction::Params to be a Hanami::Action::Params subclass"
end
describe "in testing mode" do
it 'returns only the listed params' do
_, _, body = @action.call({username: 'jodosha', unknown: 'field'})
body.must_equal [%({:username=>"jodosha"})]
end
end
describe "in a Rack context" do
it 'returns only the listed params' do
response = Rack::MockRequest.new(@action).request('PATCH', "?username=jodosha", params: { x: { foo: 'bar' } })
response.body.must_match %({:username=>"jodosha"})
end
end
describe "with Hanami::Router" do
it 'returns all the router params, even if NOT whitelisted' do
_, _, body = @action.call({ 'router.params' => {username: 'jodosha', y: 'x'}})
body.must_equal [%({:username=>"jodosha", :y=>"x"})]
end
end
end
end
end
describe 'validations' do
it "isn't valid with empty params" do
params = TestParams.new({})
params.valid?.must_equal false
params.errors.fetch(:email).must_equal ['is missing']
params.errors.fetch(:name).must_equal ['is missing']
params.errors.fetch(:tos).must_equal ['is missing']
params.errors.fetch(:address).must_equal ['is missing']
params.error_messages.must_equal ['Email is missing', 'Name is missing', 'Tos is missing', 'Age is missing', 'Address is missing']
end
it "isn't valid with empty nested params" do
params = NestedParams.new(signup: {})
params.valid?.must_equal false
params.errors.fetch(:signup).fetch(:name).must_equal ['is missing']
params.error_messages.must_equal ['Name is missing', 'Age is missing', 'Age must be greater than or equal to 18']
end
it "is it valid when all the validation criteria are met" do
params = TestParams.new(email: 'test@hanamirb.org',
password: '123456',
password_confirmation: '123456',
name: 'Luca',
tos: '1',
age: '34',
address: {
line_one: '10 High Street',
deep: {
deep_attr: 'blue'
}
}
)
params.valid?.must_equal true
params.errors.must_be_empty
params.error_messages.must_be_empty
end
it "has input available through the hash accessor" do
params = TestParams.new(name: 'John', age: '1', address: { line_one: '10 High Street' })
params[:name].must_equal('John')
params[:age].must_equal(1)
params[:address][:line_one].must_equal('10 High Street')
end
it "allows nested hash access via symbols" do
params = TestParams.new(name: 'John', address: { line_one: '10 High Street', deep: { deep_attr: 1 } })
params[:name].must_equal 'John'
params[:address][:line_one].must_equal '10 High Street'
params[:address][:deep][:deep_attr].must_equal 1
end
end
describe '#get' do
describe 'with data' do
before do
@params = TestParams.new(
name: 'John',
address: { line_one: '10 High Street', deep: { deep_attr: 1 } },
array: [{ name: 'Lennon' }, { name: 'Wayne' }]
)
end
it 'returns nil for nil argument' do
@params.get(nil).must_be_nil
end
it 'returns nil for unknown param' do
@params.get(:unknown).must_be_nil
end
it 'allows to read top level param' do
@params.get(:name).must_equal 'John'
end
it 'allows to read nested param' do
@params.get(:address, :line_one).must_equal '10 High Street'
end
it 'returns nil for uknown nested param' do
@params.get(:address, :unknown).must_be_nil
end
it 'allows to read datas under arrays' do
@params.get(:array, 0, :name).must_equal 'Lennon'
@params.get(:array, 1, :name).must_equal 'Wayne'
end
end
describe 'without data' do
before do
@params = TestParams.new({})
end
it 'returns nil for nil argument' do
@params.get(nil).must_be_nil
end
it 'returns nil for unknown param' do
@params.get(:unknown).must_be_nil
end
it 'returns nil for top level param' do
@params.get(:name).must_be_nil
end
it 'returns nil for nested param' do
@params.get(:address, :line_one).must_be_nil
end
it 'returns nil for uknown nested param' do
@params.get(:address, :unknown).must_be_nil
end
end
end
describe '#to_h' do
let(:params) { TestParams.new(name: 'Jane') }
it "returns a ::Hash" do
params.to_h.must_be_kind_of ::Hash
end
it "returns unfrozen Hash" do
params.to_h.wont_be :frozen?
end
it "prevents informations escape"
# it "prevents informations escape" do
# hash = params.to_h
# hash.merge!({name: 'L'})
# params.to_h.must_equal(Hash['id' => '23'])
# end
it 'handles nested params' do
input = {
'address' => {
'deep' => {
'deep_attr' => 'foo'
}
}
}
expected = {
address: {
deep: {
deep_attr: 'foo'
}
}
}
actual = TestParams.new(input).to_h
actual.must_equal(expected)
actual.must_be_kind_of(::Hash)
actual[:address].must_be_kind_of(::Hash)
actual[:address][:deep].must_be_kind_of(::Hash)
end
describe 'when whitelisting' do
# This is bug 113.
it 'handles nested params' do
input = {
'name' => 'John',
'age' => 1,
'address' => {
'line_one' => '10 High Street',
'deep' => {
'deep_attr' => 'hello'
}
}
}
expected = {
name: 'John',
age: 1,
address: {
line_one: '10 High Street',
deep: {
deep_attr: 'hello'
}
}
}
actual = TestParams.new(input).to_h
actual.must_equal(expected)
actual.must_be_kind_of(::Hash)
actual[:address].must_be_kind_of(::Hash)
actual[:address][:deep].must_be_kind_of(::Hash)
end
end
end
describe '#to_hash' do
let(:params) { TestParams.new(name: 'Jane') }
it "returns a ::Hash" do
params.to_hash.must_be_kind_of ::Hash
end
it "returns unfrozen Hash" do
params.to_hash.wont_be :frozen?
end
it "prevents informations escape"
# it "prevents informations escape" do
# hash = params.to_hash
# hash.merge!({name: 'L'})
# params.to_hash.must_equal(Hash['id' => '23'])
# end
it 'handles nested params' do
input = {
'address' => {
'deep' => {
'deep_attr' => 'foo'
}
}
}
expected = {
address: {
deep: {
deep_attr: 'foo'
}
}
}
actual = TestParams.new(input).to_hash
actual.must_equal(expected)
actual.must_be_kind_of(::Hash)
actual[:address].must_be_kind_of(::Hash)
actual[:address][:deep].must_be_kind_of(::Hash)
end
describe 'when whitelisting' do
# This is bug 113.
it 'handles nested params' do
input = {
'name' => 'John',
'age' => 1,
'address' => {
'line_one' => '10 High Street',
'deep' => {
'deep_attr' => 'hello'
}
}
}
expected = {
name: 'John',
age: 1,
address: {
line_one: '10 High Street',
deep: {
deep_attr: 'hello'
}
}
}
actual = TestParams.new(input).to_hash
actual.must_equal(expected)
actual.must_be_kind_of(::Hash)
actual[:address].must_be_kind_of(::Hash)
actual[:address][:deep].must_be_kind_of(::Hash)
end
it 'does not stringify values' do
input = { 'name' => 123 }
params = TestParams.new(input)
params[:name].must_equal(123)
end
end
end
end