Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Collection of RSpec matchers for APIs
Ruby
branch: master

README.markdown

API Matchers Build Status

Collection of RSpec matchers for your API.

Response Body Matchers

  • have_node
  • have_json_node
  • have_xml_node
  • have_json

Response Status Matchers

  • be_ok
  • create_resource
  • be_a_bad_request
  • be_unauthorized
  • be_forbidden
  • be_internal_server_error
  • be_not_found

Other Matchers

  • be_in_xml
  • be_in_json

Install

Include the gem to your test group in you Gemfile:

group :test do
  gem 'api_matchers'
  # other gems
end

Or install it manually: gem install api_matchers.

Usage

Including in RSpec

To include all this matchers you need to include the APIMatchers::RSpecMatchers module:

RSpec.configure do |config|
  config.include APIMatchers::RSpecMatchers
end

Have Node Matcher

The have_node matcher parse the actual and see if have the expcted node with the expected value. The default that have_node will parse is JSON.

You can verify if node exists:

expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_node(:transaction)

Or if node exist with a value:

expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_node(:id).with(54)
expect('{ "error": "not_authorized" }').to have_node(:error).with('not_authorized')
expect('{"parcels":1 }').to have_node(:parcels).with(1)

To see the json node and see if include a text, you can do this:

expect('{"error": "Transaction error: Name cant be blank"}').to have_node(:error).including_text("Transaction error")

You can verify boolean values too:

expect('{"creditcard":true}').to have_node(:creditcard).with(true)

HAVE NODE Matcher Configuration

You can configure if you want xml (JSON is the default):

APIMatchers.setup do |config|
  config.content_type = :xml
end
expect('<transaction><id>200</id><status>paid</status></transaction>').to have_node(:status)

Using the with method:

expect('<transaction><id>200</id><status>paid</status></transaction>').to have_node(:status).with('paid')

Or you can use the have_xml_node matcher:

expect("<error>Transaction error: Name can't be blank</error>").to have_xml_node(:error).with("Transaction error: Name can't be blank")

To see the xml node and see if include a text, you can do this:

expect("<error>Transaction error: Name can't be blank</error>").to have_xml_node(:error).including_text("Transaction error")

If you work with xml and json in the same API, check the have_json_node and have_xml_node matchers.

You can configure the name of the method and then you will be able to use without the #body method, for example:

APIMatchers.setup do |config|
  config.response_body_method = :body
end

expect(response).to have_node(:foo).with('bar')

Instead of:

expect(response.body).to have_node(:foo)

Have JSON Node Matcher

expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_json_node(:id).with(54)

Have XML Node Matcher

expect("<product><name>gateway</name></product>").to have_xml_node(:name).with('gateway')

Have JSON Matcher

Sometimes, you want to compare the entire JSON structure:

expect("['Foo', 'Bar', 'Baz']").to have_json(['Foo', 'Bar', 'Baz'])

Create Resource Matcher

This matchers see the HTTP STATUS CODE is equal to 201.

expect(response.status).to create_resource

BAD REQUEST Matcher

This BAD REQUEST is a matcher that see if the HTTP STATUS code is equal to 400.

expect(response.status).to be_a_bad_request
expect(response.status).to be_bad_request

UNAUTHORIZED Matcher

This UNAUTHORIZED is a matcher that see if the HTTP STATUS code is equal to 401.

expect(response.status).to be_unauthorized
expect(response.body).to have_node(:message).with('Invalid Credentials')

FORBIDDEN Matcher

This is a matcher to see if the HTTP STATUS code is equal to 403.

expect(response.status).to be_forbidden

INTERNAL SERVER ERROR Matcher

This INTERNAL SERVER Error is a matcher that see if the HTTP STATUS code is equal to 500.

expect(response.status).to be_internal_server_error
expect(response.body).to have_node(:message).with('An Internal Error Occurs in our precious app. :S')

HTTP STATUS CODE Configuration

You can configure the name method to call the http status code:

APIMatchers.setup do |config|
  config.http_status_method = :status
end

Then you can use without call the #status method:

expect(response).to create_resource

This configurations affects this matchers:

  • be_ok
  • create_resource
  • be_a_bad_request
  • be_internal_server_error
  • be_unauthorized
  • be_forbidden
  • be_not_found

Be in XML Matcher

This is a matcher that see if the content type is xml:

expect(response.headers['Content-Type']).to be_in_xml

Be in JSON Matcher

This is a matcher that see if the content type is in JSON:

expect(response.headers['Content-Type']).to be_in_json

Headers Configuration

You can configure the name method to call the headers and content type:

APIMatchers.setup do |config|
  config.header_method           = :headers
  config.header_content_type_key = 'Content-Type'
end

And then you will be able to use without call the #headers calling the #['Content-Type'] method:

expect(response).to be_in_json
expect(response).to be_in_xml

Acknowlegments

  • Special thanks to Daniel Konishi to contribute in the product that I extracted the matchers to this gem.

Contributors

  • Stephen Orens
  • Lucas Caton
Something went wrong with that request. Please try again.