How to test a Ruby Roda app using RSpec--passing an argument to app.new with initialize

250 views
Skip to first unread message

Nick A

unread,
Mar 3, 2022, 6:49:43 PM3/3/22
to Roda
Hello, I posted this on StackOverflow but think it might be more appropriate here.

This question probably has a simple answer but I can't find any examples for what I am trying to do--Use Roda with RSpec3 so it is difficult to troubleshoot.

I am using Marston and Dees 'Effective Testing w/ RSpec3' book which uses Sinatra instead of Roda. I am having difficulty passing an object to API.new. From the book, this is what works with Sinatra but fails with 'wrong number of arguments' error when I substitute Roda.

Depending on whether I pass arguments with super or no no arguments with super(), the error switches to indicate that the failure occurs either at the initialize method or in the call to Rack::Test::Methods post in the spec.

I see that in Rack::Test in github repo README I may have to use Rack::Builder.parse_file("config.ru") but that didn't help.

Thanks for any thoughts, Nick

Here are the two errors that rspec shows.

When using super no brackets...

Failures:

  1. MbrTrak::API POST /users when the user is successfully recorded returns the user id Failure/Error: post '/users', JSON.generate(user)

    ArgumentError: wrong number of arguments (given 1, expected 0)

    ./spec/unit/app/api_spec.rb:21:in `block (4 levels) in module:MbrTrak'

And when using super()...

  1. MbrTrak::API POST /users when the user is successfully recorded returns the user id Failure/Error: super()

    ArgumentError: wrong number of arguments (given 0, expected 1)

    ./app/api.rb:8:in `initialize' ./spec/unit/app/api_spec.rb:10:in `new' ./spec/unit/app/api_spec.rb:10:in `app' ./spec/unit/app/api_spec.rb:21:in `block (4 levels) in module:MbrTrak'

Here is my api_spec.rb

  1. require_relative '../../../app/api'
    require 'rack/test'

    module MbrTrak
      RecordResult = Struct.new(:success?, :expense_id, :error_message)
     
      RSpec.describe API do
        include Rack::Test::Methods
        def app
          API.new(directory: directory)
        end
        let(:directory) { instance_double('MbrTrak::Directory')}
       
        describe 'POST /users' do
          context 'when the user is successfully recorded' do
            it 'returns the user id' do
              user = { 'some' => 'user' }
              allow(directory).to receive(:record)
                .with(user)
                .and_return(RecordResult.new(true, 417, nil))
              post '/users', JSON.generate(user)
              parsed = JSON.parse(last_response.body)
              expect(parsed).to include('user_id' => 417)
            end
          end
        end
      end
    end
and my api.rb file
  1. require 'roda'
    require 'json'

    module MbrTrak
      class API < Roda
        def initialize(directory: Directory.new)
          @directory = directory
          super()
        end
        plugin :render, escape: true
        plugin :json
        route do |r|
          r.on "users" do
            r.is Integer do |id|
              r.get do
                JSON.generate([])
              end
            end
            r.post do
              user = JSON.parse(request.body.read)
              result = @directory.record(user)
              JSON.generate('user_id' => result.user_id)
            end
          end
        end
      end
    end
and my config.ru
  1. require "./app/api"

    run MbrTrak::API
and finally, Gemfile.lock
  1. GEM
      remote: https://rubygems.org/
      specs:
        addressable (2.8.0)
          public_suffix (>= 2.0.2, < 5.0)
        bcrypt (3.1.16)
        coderay (1.1.3)
        diff-lcs (1.5.0)
        domain_name (0.5.20190701)
          unf (>= 0.0.5, < 1.0.0)
        dry-inflector (0.2.1)
        erubi (1.10.0)
        http (2.2.2)
          addressable (~> 2.3)
          http-cookie (~> 1.0)
          http-form_data (~> 1.0.1)
          http_parser.rb (~> 0.6.0)
        http-cookie (1.0.4)
          domain_name (~> 0.5)
        http-form_data (1.0.3)
        http_parser.rb (0.6.0)
        lucid_http (0.11.1)
          http (~> 2.1)
        nio4r (2.5.8)
        pg (1.3.2)
        public_suffix (4.0.6)
        puma (5.6.2)
          nio4r (~> 2.0)
        rack (2.2.3)
        rack-test (1.1.0)
          rack (>= 1.0, < 3)
        rack-unreloader (1.8.0)
        rake (13.0.6)
        roda (3.53.0)
          rack
        rspec (3.11.0)
          rspec-core (~> 3.11.0)
          rspec-expectations (~> 3.11.0)
          rspec-mocks (~> 3.11.0)
        rspec-core (3.11.0)
          rspec-support (~> 3.11.0)
        rspec-expectations (3.11.0)
          diff-lcs (>= 1.2.0, < 2.0)
          rspec-support (~> 3.11.0)
        rspec-its (1.2.0)
          rspec-core (>= 3.0.0)
          rspec-expectations (>= 3.0.0)
        rspec-mocks (3.11.0)
          diff-lcs (>= 1.2.0, < 2.0)
          rspec-support (~> 3.11.0)
        rspec-roda (0.2.2)
          dry-inflector
          rack-test (~> 1.0)
          roda
          rspec (~> 3.7)
          rspec-its (~> 1.2.0)
        rspec-support (3.11.0)
        rspec_sequel_matchers (0.5.0)
          sequel (>= 3.8.0)
        sequel (5.53.0)
        tilt (2.0.10)
        unf (0.1.4)
          unf_ext
        unf_ext (0.0.8)

    PLATFORMS
      ruby

    DEPENDENCIES
      bcrypt
      coderay
      erubi
      lucid_http
      pg
      puma
      rack-test
      rack-unreloader
      rake
      roda
      rspec
      rspec-roda
      rspec_sequel_matchers
      sequel
      tilt

    BUNDLED WITH
       2.1.4

Jeremy Evans

unread,
Mar 3, 2022, 7:20:21 PM3/3/22
to ruby...@googlegroups.com
On Thu, Mar 3, 2022 at 3:49 PM Nick A <mega...@gmail.com> wrote:
Hello, I posted this on StackOverflow but think it might be more appropriate here.
  1. module MbrTrak
      class API < Roda
        def initialize(directory: Directory.new)
          @directory = directory
          super()
        end

Here is the specific problem.  You are overriding Roda#initialize in an incompatible way, and calling super with no argument, when it is supposed to accept a rack env hash.

The more general problem is your testing.  You should not attempt to manually instantiate Roda instances.  Instead, use the Rack API:  API.call(rack_env_hash).  You'll have to build the env hash manually, or use something like Rack::MockRequest (comes with Rack).  A Roda app is the Roda subclass (API in your case), not an instance of that subclass (an instance is created per request).

Thanks,
Jeremy
Reply all
Reply to author
Forward
0 new messages