9

I'm starting a new project, my first with Rails 5.1.0. I have a pb with my first request spec.

describe 'Users', type: :request do
  it 'are created from external data' do
    json_string = File.read('path/to/test_data/user_data.json')
    params = { user: JSON.parse(json_string) }
    headers = { "CONTENT_TYPE" => "application/json" }

    expect do
      post '/api/v1/users', params.to_s, headers
    end.to change {
      User.count
    }.by(1)

    expect(response.status).to eq 200
  end
end

this spec return the error ArgumentError: wrong number of arguments (given 3, expected 1). The official documentation don't say much.

If I take out the .to_s, and send a hash, like this:

post '/api/v1/users', params, headers

I got another error:

ArgumentError: unknown keyword: user

Any thought?

Ruff9
  • 1,163
  • 15
  • 34

2 Answers2

18

I think they changed the syntax recently. Now it should use keyword args. So, something like this:

post '/api/v1/users', params: params, headers: headers
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • I just stumbled in this problem myself while upgrading my application from Rails 4.2 to 5.1. I think the change is undocumented in Rspec because it just delegates to a Rails helper, but my question is: is there an optimal way to upgrade the specs to the new format, or use the old one without monkey patching too much? I have >900 specs, of which ~150 are failing for this problem and ~150 more for other reasons, and I'd like to change them as little as possible in order to spot and fix the “real” problems first. – wiz May 04 '17 at 14:56
  • @wiz: good question. I don't know about such way. So far I've been manually changing each occurrence. – Sergio Tulentsev May 04 '17 at 15:11
  • For what it's worth, I traced the `post` method down to `ActionDispatch::Integration::Session#process`, I guess that's what was changed between Rails 4 and 5. I can't say I'm familiar with Rails internals, but perhaps the change was documented there at some point? – wiz May 04 '17 at 15:25
13

Here's a little addendum to Sergio's answer. If you are upgrading from Rails 4 to Rails 5, have lots of tests, and aren't too keen on changing them all – at least not until you've finished upgrading – I've found a way to make them work with the old method signature.

In my spec_helper I added

module FixLegacyTestRequests
  def get(path, par = {}, hdr = {})
    process(:get, path, params: par, headers: hdr)
  end
  def post(path, par = {}, hdr = {})
    process(:post, path, params: par, headers: hdr)
  end
  def put(path, par = {}, hdr = {})
    process(:put, path, params: par, headers: hdr)
  end
  def delete(path, par = {}, hdr = {})
    process(:delete, path, params: par, headers: hdr)
  end
end

and then I added this configuration for each test:

RSpec.configure do |config|
  config.before :each do |example|
    extend(FixLegacyTestRequests) # to be removed at some point!
  end
end

My tests went back to working, and I think it should be safe because it's only applied to the currently running test and shouldn't pollute any gem's code such as with a monkey patch.

Community
  • 1
  • 1
wiz
  • 606
  • 5
  • 9