API for Testing Rack Apps with easy


$ [sudo] gem install sonar


require 'sonar'


Simply include Sonar in your tests.

Or use it directly, by initialize a session via


When mixin used, call app RackApp inside testing suite to set app to be tested.

Minitest Example:

require 'sonar'

class MyTests < MiniTest::Unit::TestCase

    include Sonar

    def setup
        app MyRackApp

    def test
        get '/url'
        assert_equal last_response.status, 200

Specular Example: do
    app MyRackApp

    get '/url'
    expect(last_response.status) == 200

Multiple apps can be tested within same suite.
Each app will run own session.

Minitest Example:

require 'sonar'

class MyTests < MiniTest::Unit::TestCase

    include Sonar

    def setup
        app MyRackApp

    def test
        # querying default app
        get '/url'
        assert_equal last_response.status, 200

        # testing ForumApp
        app ForumApp
        get '/posts'
        assert_equal last_response.status, 200

        # back to default app
        app MyRackApp
        get '/url'
        assert_equal last_response.status, 200

When using session manually, you should set app at initialization.


session = MyRackApp
session.get '/url'
assert_equal session.last_response.status, 200

Resetting App

Sometimes you need to start over with a new app in pristine state, i.e. no cookies, no headers etc.

To achieve this, simply call reset_app! (or reset_browser!).

This will reset currently tested app. Other tested apps will stay untouched.

When creating sessions manually, app can NOT be switched/reset.
To test another app, simply create another session.


Use one of get, post, put, patch, delete, options, head to make requests via Sonar browser.

To make a secure request, add s_ prefix:

s_get  '/path'
s_post '/path'
# etc.

To make a request via XHR, aka Ajax, add _x suffix:

get_x  '/path'
post_x '/path'
# etc.

To make a secure request via XHR, add both s_ and _x:

s_get_x  '/path'
s_post_x '/path'
# etc.

In terms of arguments, making HTTP requests via Sonar is identical to calling regular Ruby methods.
That's it, you do not need to join parameters into a string.
Just pass them as usual arguments:

post '/news', :create, :title => rand
post '/news', :update, id, :title => rand
get  '/news', :delete, id


Previous example works just fine, however it is redundant and inconsistent.
Just imagine that tested app changed its base URL from /news to /headlines.

The solution is simple.
Use map to define a base URL that will be prepended to each request,
except ones starting with a slash or a protocol(http://, https:// etc.) of course. do
    app MyRackApp
    map '/news'

    post :create, :title => rand
    post :update, id, :title => rand
    get  :delete, id

Note: requests starting with a slash or protocol(http://, https:// etc.) wont use base URL defined by map.

Note: when you switching tested app, make sure you also change the map.

To disable mapping, simply call map nil


Set cookies:

cookies['name'] = 'value'

Read cookies:

cookie = cookies['name']

Delete a cookie:

cookies.delete 'name'

Clear all cookies:


Each app uses its own cookies jar.


Sonar allow to set headers that will be sent to app on all consequent requests.

Set headers:

header['User-Agent']   = 'Sonar'
header['Content-Type'] = 'text/plain'
header['rack.input']   = 'someString'
# etc.

Read headers:

header = headers['User-Agent']
# etc.

Delete a header:

headers.delete 'User-Agent'

Clear all headers:


Each app uses its own headers.


Basic Auth:

authorize 'user', 'pass'

Reset earlier set Basic authorization header:


Digest Auth:

digest_authorize 'user', 'pass'

Reset earlier set Digest authorization header:


Reset ANY earlier set authorization header:


Follow Redirects

By default, Sonar wont follow redirects.

If last response is a redirect and you want Sonar to follow it, use follow_redirect!