# API Matchers [![Build Status](https://travis-ci.org/tomas-stefano/api_matchers.png?branch=master)](https://travis-ci.org/tomas-stefano/api_matchers) 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: ```ruby 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: ```ruby 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: ```ruby expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_node(:transaction) ``` Or if node exist with a value: ```ruby expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_node(:id).with(54) ``` ```ruby expect('{ "error": "not_authorized" }').to have_node(:error).with('not_authorized') ``` ```ruby expect('{"parcels":1 }').to have_node(:parcels).with(1) ``` To see the json node and see if include a text, you can do this: ```ruby expect('{"error": "Transaction error: Name cant be blank"}').to have_node(:error).including_text("Transaction error") ``` You can verify boolean values too: ```ruby expect('{"creditcard":true}').to have_node(:creditcard).with(true) ``` ### HAVE NODE Matcher Configuration You can configure if you want xml (JSON is the default): ```ruby APIMatchers.setup do |config| config.content_type = :xml end ``` ```ruby expect('200paid').to have_node(:status) ``` Using the `with` method: ```ruby expect('200paid').to have_node(:status).with('paid') ``` Or you can use the `have_xml_node` matcher: ```ruby expect("Transaction error: Name can't be blank").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: ```ruby expect("Transaction error: Name can't be blank").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: ```ruby APIMatchers.setup do |config| config.response_body_method = :body end expect(response).to have_node(:foo).with('bar') ``` Instead of: ```ruby expect(response.body).to have_node(:foo) ``` ### Have JSON Node Matcher ```ruby expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_json_node(:id).with(54) ``` ### Have XML Node Matcher ```ruby expect("gateway").to have_xml_node(:name).with('gateway') ``` ### Have JSON Matcher Sometimes, you want to compare the entire JSON structure: ```ruby expect("['Foo', 'Bar', 'Baz']").to have_json(['Foo', 'Bar', 'Baz']) ``` ### Create Resource Matcher This matchers see the HTTP STATUS CODE is equal to 201. ```ruby 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. ```ruby 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. ```ruby 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. ```ruby 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. ```ruby 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: ```ruby APIMatchers.setup do |config| config.http_status_method = :status end ``` Then you can use without call the **#status** method: ```ruby 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: ```ruby 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: ```ruby expect(response.headers['Content-Type']).to be_in_json ``` ### Headers Configuration You can configure the name method to call the headers and content type: ```ruby 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: ```ruby 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