Git Product home page Git Product logo

api_matchers's Introduction

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

api_matchers's People

Contributors

ahmet avatar benlovell avatar evan-m avatar lucascaton avatar sorens avatar thadeubrito avatar tomas-stefano avatar wafcio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

api_matchers's Issues

same node in multiple places

Given response listing multiple records:

<messages>
  <message><id>4</id></message>
  <message><id>2</id></message>
</message>

response.body.should have_xml_node(:id).with(2) will fail, even though it should not.

incorrect usage of present? leads to problems with testing for boolean values

The problem is

if expected_value.present?

if expected_value is evaluated to a FalseClass, .present? will still return false

1.9.2p320 :001 > false.present?
 => false 
1.9.2p320 :002 > true.present?
 => true 
1.9.2p320 :003 > nil.present?
 => false 
1.9.2p320 :004 > false.nil?
 => false 
1.9.2p320 :005 > true.nil?
 => false 
1.9.2p320 :006 > nil.nil?
 => true 

instead, use.nil? to guard instead of .present?

Exception is raised when call response without body method

ruby '2.1.2'
Rails: 4.0.8

When use the expect(response), expecting that the APIMatchers calls the 'body' method, the spec trows an exception.

Failure/Error: expect(response).to have_json({})
     TypeError:
       no implicit conversion of ActionController::TestResponse into String
     # /Users/tomas-stefano/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/json/common.rb:155:in `initialize'
     # /Users/tomas-stefano/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/json/common.rb:155:in `new'
     # /Users/tomas-stefano/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/json/common.rb:155:in `parse'
     # /Users/tomas-stefano/.rvm/gems/ruby-2.1.2@marketplace/gems/api_matchers-0.5.0/lib/api_matchers/core/parser.rb:5:in `json'
     # /Users/tomas-stefano/.rvm/gems/ruby-2.1.2@marketplace/gems/api_matchers-0.5.0/lib/api_matchers/response_body/have_json.rb:14:in `matches?'
     # /Users/tomas-stefano/.rvm/gems/ruby-2.1.2@marketplace/gems/rspec-expectations-2.14.5/lib/rspec/expectations/handler.rb:24:in `handle_matcher'
     # /Users/tomas-stefano/.rvm/gems/ruby-2.1.2@marketplace/gems/rspec-expectations-2.14.5/lib/rspec/expectations/expectation_target.rb:34:in `to'

Readme examples failing

I tried some examples from the README and they fail for me. Gem Specs all pass against my Ruby and Rspec versions.

I simplified it to a 2 file test in a blank rvm gemset:

https://gist.github.com/3959775

Versions:
gem 'rspec', '2.11.0'
gem 'api_matchers', '0.1.1'
ruby 1.9.3p233 (2012-05-30 revision 35845) [x86_64-darwin11.4.0]

Failures:

  1) APIMatcher examples shouldn't fail
     Failure/Error: "{ 'transaction': { 'id': '54', 'status': 'paid' } }".should have_node(:transaction)
       expected to have node called: 'transaction'. Got: '{ 'transaction': { 'id': '54', 'status': 'paid' } }'
     # ./api_matchers_spec.rb:6:in `block (2 levels) in <top (required)>'

  2) APIMatcher examples also shouldn't fail
     Failure/Error: "{ 'transaction': { 'id': '54', 'status': 'paid' } }".should have_node(:id).with(54)
       expected to have node called: 'id' with value: '54'. Got: '{ 'transaction': { 'id': '54', 'status': 'paid' } }'
     # ./api_matchers_spec.rb:10:in `block (2 levels) in <top (required)>'

Improve expectation messages

The messages are all screw up:

expect(response.body).to have_json({})

Results in an strange error message:

Failure/Error: expect(response.body).to have_json({})
       expect to have json: '{"orders":[]}'. Got: '{"orders"=>[]}'.

The objective is to show the expected and the actual like this:

Failure/Error: expect(response.body).to have_json({})
       expect to have json: '{}'. Got: '{"orders"=>[]}'.

Formatting failures messages

When you dealing with API's that return an certain amout of data, it becames near to impossible to see the diff between the expected and the actual.

error in readme

You have body_method but it should be response_body_method in readme.

Multiple nodes in an array

Hey there.

One thing I just ran into while testing an api that returns a collection of resources wrapped in an array.

Per your example, this works fine:

"{ \"transaction\": { \"id\": \"54\", \"status\": \"paid\" } }".should have_node(:id)
=> true

However, this, when wrapped in an array, does not:

"[{ \"transaction\": { \"id\": \"54\", \"status\": \"paid\" } }]".should have_node(:id)
RSpec::Expectations::ExpectationNotMetError: expected to have node called: 'id'. Got: '[{ "transaction": { "id": "54", "status": "paid" } }]'
from /Users/joel/.rvm/gems/ruby-1.9.2-p320/gems/rspec-expectations-2.11.3/lib/rspec/expectations/fail_with.rb:33:in `fail_with'

Should that be the expected result? I would have expected it to find :id anyway.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.