rack / rack-test

Rack::Test is a small, simple testing API for Rack apps.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Undefined method `size` on 0.8.2

GeekOnCoffee opened this issue · comments

We upgraded from 0.7.0 to 0.8.2 and we're seeing the undefined method size error on form submissions without an attachment field but no file attached. The same form works fine if a file is attached.
We're using shrine for uploads, not sure if that's relevant.

Related to: #210

We're locking to 0.7.0 for now, but I'll be happy to provide more information and/or help test a fix.

Thanks for the report @GeekOnCoffee, much appreciated. Could you include a stack trace also? (We have one in #149, just wanted to double check that this is indeed the same issue, and that one is closed anyway so it's better to have it here.)

I confirm that stacktrace is the same as in #149 (comment)

@GeekOnCoffee
See #215
Bottom line is updating Capybara to 2.17 fixed this for me.

Confirming the same issue @ollieh-m suggestion worked for me

Hey guys! Got the same issue when I was moving along to Rails 5.2.0.rc1. Just downgraded to 0.7.0 again, may try the other fix another time.

Came from this issue: rspec/rspec-rails#1915

Here's a backtrace if you want though....

["/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/uploaded_file.rb:47:in `public_send'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/uploaded_file.rb:47:in `method_missing'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:136:in `build_file_part'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:101:in `block in get_parts'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:92:in `each'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:92:in `map'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:92:in `get_parts'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:87:in `build_parts'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test/utils.rb:77:in `build_multipart'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test.rb:231:in `env_for'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test.rb:128:in `custom_request'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rack-test-0.8.2/lib/rack/test.rb:66:in `post'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/rack_test/browser.rb:69:in `process'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/rack_test/browser.rb:41:in `process_and_follow_redirects'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/rack_test/browser.rb:32:in `submit'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/rack_test/form.rb:78:in `submit'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/rack_test/node.rb:64:in `click'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/node/element.rb:143:in `block in click'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/node/base.rb:85:in `synchronize'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/node/element.rb:143:in `click'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/node/actions.rb:25:in `click_link_or_button'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/session.rb:776:in `block (2 levels) in <class:Session>'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/capybara-2.15.1/lib/capybara/dsl.rb:50:in `block (2 levels) in <module:DSL>'",
 "/Users/nickschwaderer/Documents/webapps/heroku_publi/smnopublicform/spec/features/new_registrations/create_a_new_registration_spec.rb:68:in `block (2 levels) in <top (required)>'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:254:in `instance_exec'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:254:in `block in run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:500:in `block in with_around_and_singleton_context_hooks'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:457:in `block in with_around_example_hooks'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:464:in `block in run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:604:in `block in run_around_example_hooks_for'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:342:in `call'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-rails-3.6.1/lib/rspec/rails/adapters.rb:127:in `block (2 levels) in <module:MinitestLifecycleAdapter>'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:447:in `instance_exec'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:447:in `instance_exec'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:375:in `execute_with'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:606:in `block (2 levels) in run_around_example_hooks_for'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:342:in `call'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:607:in `run_around_example_hooks_for'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:464:in `run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:457:in `with_around_example_hooks'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:500:in `with_around_and_singleton_context_hooks'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example.rb:251:in `run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example_group.rb:627:in `block in run_examples'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example_group.rb:623:in `map'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example_group.rb:623:in `run_examples'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/example_group.rb:589:in `run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:118:in `block (3 levels) in run_specs'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:118:in `map'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:118:in `block (2 levels) in run_specs'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/configuration.rb:1894:in `with_suite_hooks'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:113:in `block in run_specs'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/reporter.rb:79:in `report'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:112:in `run_specs'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:87:in `run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:71:in `run'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/lib/rspec/core/runner.rb:45:in `invoke'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/gems/rspec-core-3.6.0/exe/rspec:4:in `<top (required)>'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/bin/rspec:23:in `load'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/bin/rspec:23:in `<main>'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/bin/ruby_executable_hooks:15:in `eval'",
 "/Users/nickschwaderer/.rvm/gems/ruby-2.3.6/bin/ruby_executable_hooks:15:in `<main>'"]

Next week or so I'll try @ollieh-m 's approach as well

No feedback received from @GeekOnCoffee since a long time. If someone feels the original problem remains, please speak up - closing for now, but will reopen if it turns out to still be a problem with v0.8.3.

Well, this is not resolved IMO. Capybara 2.14.3 test suite fails with these kind of errors:

  1) Capybara::Session DSL #attach_file with multipart form should set a file path by id
     Failure/Error: send(method, new_uri.to_s, attributes, env.merge(options[:headers] || {}))
     NoMethodError:
       undefined method `size' for nil:NilClass
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/uploaded_file.rb:47:in `public_send'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/uploaded_file.rb:47:in `method_missing'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:136:in `build_file_part'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:101:in `block in get_parts'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:92:in `each'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:92:in `map'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:92:in `get_parts'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:87:in `build_parts'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test/utils.rb:77:in `build_multipart'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test.rb:233:in `env_for'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test.rb:128:in `custom_request'
     # /usr/share/gems/gems/rack-test-0.8.3/lib/rack/test.rb:66:in `post'
     # ./lib/capybara/rack_test/browser.rb:64:in `process'
     # ./lib/capybara/rack_test/browser.rb:36:in `process_and_follow_redirects'
     # ./lib/capybara/rack_test/browser.rb:27:in `submit'
     # ./lib/capybara/rack_test/form.rb:79:in `submit'
     # ./lib/capybara/rack_test/node.rb:64:in `click'
     # ./lib/capybara/node/element.rb:143:in `block in click'
     # ./lib/capybara/node/base.rb:85:in `synchronize'
     # ./lib/capybara/node/element.rb:143:in `click'
     # ./lib/capybara/node/actions.rb:61:in `click_button'
     # ./lib/capybara/session.rb:784:in `block (2 levels) in <class:Session>'
     # ./lib/capybara/dsl.rb:50:in `block (2 levels) in <module:DSL>'
     # ./lib/capybara/spec/session/attach_file_spec.rb:33:in `block (3 levels) in <top (required)>'

The full log is here:

https://apps.fedoraproject.org/koschei/package/rubygem-capybara
https://kojipkgs.fedoraproject.org/work/tasks/6657/25396657/build.log

Thanks for the info @voxik. I looked into this but am having a bit of a hard time understanding why this happens. This is the failing code (from utils.rb):

      def build_file_part(parameter_name, uploaded_file)
        uploaded_file.set_encoding(Encoding::BINARY) if uploaded_file.respond_to?(:set_encoding)
        <<-EOF
--#{MULTIPART_BOUNDARY}\r
Content-Disposition: form-data; name="#{parameter_name}"; filename="#{escape(uploaded_file.original_filename)}"\r
Content-Type: #{uploaded_file.content_type}\r
Content-Length: #{uploaded_file.size}\r
\r
#{uploaded_file.read}\r
EOF
      end

The uploaded_file.size is the thing that breaks it.

Do you have a repo that reproduces this? Like a branch in your gem's repo or so? It would help immensely when trying to understand why this happens now. Thanks in advance.

It seem that derived classes does not call rack-test initialize method and therefore the tempfile is uninitialized.

Interesting, I fail to create test case which would prove this. But I am pretty sure that the UploadedFile#initialize method is not called in this case.

Isn't the uploaded_file serialized somewhere?

So I got to Rack::Test::Session#post and it seems that there already is the uninitialized UploadedFile object. Going deeper to Capybara.

I reached this point:

https://github.com/teamcapybara/capybara/blob/2.14.3/lib/capybara/rack_test/form.rb#L43

And this call simply does not call UploadedFile#initialize although it should IMO. Not really sure why.

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [i386-linux]

These lines probably have the clue: https://github.com/teamcapybara/capybara/blob/2.14.3/lib/capybara/rack_test/form.rb#L3-L16

Subclassing UploadedFile, overriding its constructor but not calling the base class constructor? That's some incredibly weird code there, to be honest. 😄

This commit has the details: teamcapybara/capybara@95a297e#diff-c88a9acbdd8b694a0468c4e3839bbbb6

@voxik Is it critical for you to have this working with this (outdated) version of capybara? The latest version is 2.18.0 according to rubygems.org.

So I'm inclined to close this as "known broken". The combination rack-test >= 0.71 and capybara < 2.17 is simply a no-go, because of the slightly edgy way capybara uses rack-test internals. Do you agree?

Unfortunately I am stuck with old Capybara, because newer Capybara has new dependencies, which are not in Fedora yet.

Anyway, I took the commit from Capybara, which workaround the issue and I submitted the teamcapybara/capybara#1981, which changes Capybara to call the #initialize method of parent class.

Please feel free to close this issue. There is probably nothing else what could be done here (although documenting the incompatibility might help, but who would read it, right? 😉 )

There is probably nothing else what could be done here (although documenting the incompatibility might help, but who would read it, right? 😉

Unfortunately, this is quite true. But I will add a note in the README anyway. Thanks for your feedback!

Howdy all! Just pinging to remind myself that I got this again. (On rack test 1.0.0 I think?) Bumping down to 0.7.0 solved it for me! :)

@Schwad Interesting. If you can make a reproducible test case, we can give it a look. Closing so we don't keep this old issue alive (it's better to open up a new one for 1.0.0)