README.md in airborne-0.0.17 vs README.md in airborne-0.0.18

- old
+ new

@@ -6,30 +6,37 @@ [![airborne gem stable downloads](http://img.shields.io/gem/dv/airborne/stable.svg?style=flat-square)](http://rubygems.org/gems/airborne) RSpec driven API testing framework inspired by [frisby.js](https://github.com/vlucas/frisby) ## Installation + Install Airborne: gem install airborne + +Or add it to your Gemfile: + gem 'airborne' + ##Creating Tests - require 'airborne' - - describe 'sample spec' do - it 'should validate types' do - get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } - expect_json_types({name: :string}) - end - - it 'should validate values' do - get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } - expect_json({:name => "John Doe"}) - end - end +```ruby +require 'airborne' +describe 'sample spec' do + it 'should validate types' do + get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } + expect_json_types({name: :string}) + end + + it 'should validate values' do + get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } + expect_json({:name => "John Doe"}) + end +end +``` + When calling expect_json_types, these are the valid types that can be tested against: * `:int` or `:integer` * `:float` * `:bool` or `:boolean` @@ -43,175 +50,221 @@ * `:array_of_objects` * `:array_of_arrays` If the properties are optional and may not appear in the response, you can append `_or_null` to the types above. - describe 'sample spec' do - it 'should validate types' do - get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } or { "name" : "John Doe", "age" : 45 } - expect_json_types({name: :string, age: :int_or_null}) - end - end +```ruby +describe 'sample spec' do + it 'should validate types' do + get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } or { "name" : "John Doe", "age" : 45 } + expect_json_types({name: :string, age: :int_or_null}) + end +end +``` Additionally, if an entire object could be null, but you'd still want to test the types if it does exist, you can wrap the expectations in a call to `optional`: - it 'should allow optional nested hash' do - get '/simple_path_get' #may or may not return coordinates - expect_json_types("address.coordinates", optional({lattitude: :float, longitutde: :float})) - end +```ruby +it 'should allow optional nested hash' do + get '/simple_path_get' #may or may not return coordinates + expect_json_types("address.coordinates", optional({lattitude: :float, longitutde: :float})) +end +``` -When calling `expect_json`, you can optionally provide a block and run your own `rspec` expectations: +When calling `expect_json` or `expect_json_types`, you can optionally provide a block and run your own `rspec` expectations: - describe 'sample spec' do - it 'should validate types' do - get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } - expect_json({name: lambda |name| expect(name.length).to eq(8)}) - end - end - +```ruby +describe 'sample spec' do + it 'should validate types' do + get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } + expect_json({name: -> (name){expect(name.length).to eq(8)}}) + end +end +``` ##Making requests + Airborne uses `rest_client` to make the HTTP request, and supports all HTTP verbs. When creating a test, you can call any of the following methods: `get`, `post`, `put`, `patch`, `delete`. This will then give you access the following properties: * `response` - The HTTP response returned from the request * `headers` - A symbolized hash of the response headers returned by the request * `body` - The raw HTTP body returned from the request * `json_body` - A symbolized hash representation of the JSON returned by the request Fo example: - it 'should validate types' do - get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } - name = json_body[:name] #name will equal "John Doe" - body_as_string = body - end +```ruby +it 'should validate types' do + get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" } + name = json_body[:name] #name will equal "John Doe" + body_as_string = body +end +``` - When calling any of the methods above, you can pass request headers to be used. - get 'http://example.com/api/v1/my_api', {'x-auth-token' => 'my_token'} +```ruby +get 'http://example.com/api/v1/my_api', {'x-auth-token' => 'my_token'} +``` For requests that require a body (`post`, `put`, `patch`) you can pass the body as a hash as well: - post 'http://example.com/api/v1/my_api', {:name => 'John Doe'}, {'x-auth-token' => 'my_token'} - +```ruby +post 'http://example.com/api/v1/my_api', {:name => 'John Doe'}, {'x-auth-token' => 'my_token'} +``` + ##API + * `expect_json_types` - Tests the types of the JSON property values returned * `expect_json` - Tests the values of the JSON property values returned * `expect_json_keys` - Tests the existence of the specified keys in the JSON object * `expect_status` - Tests the HTTP status code returned * `expect_header` - Tests for a specified header in the response * `expect_header_contains` - Partial match test on a specified header ##Path Matching + When calling `expect_json_types`, `expect_json` or `expect_json_keys` you can optionaly specify a path as a first parameter. For example, if our API returns the following JSON: - { - "name": "Alex", - "address": { - "street": "Area 51", - "city": "Roswell", - "state": "NM", - "coordinates":{ - "lattitude": 33.3872, - "longitude": 104.5281 - } - } +```json +{ + "name": "Alex", + "address": { + "street": "Area 51", + "city": "Roswell", + "state": "NM", + "coordinates": { + "lattitude": 33.3872, + "longitude": 104.5281 } + } +} +``` This test would only test the address object: - describe 'path spec' do - it 'should allow simple path and verify only that path' do - get 'http://example.com/api/v1/simple_path_get' - expect_json_types('address', {street: :string, city: :string, state: :string, coordinates: :object }) - #or this - expect_json_types('address', {street: :string, city: :string, state: :string, coordinates: { lattitude: :float, longitude: :float } }) - end - end +```ruby +describe 'path spec' do + it 'should allow simple path and verify only that path' do + get 'http://example.com/api/v1/simple_path_get' + expect_json_types('address', {street: :string, city: :string, state: :string, coordinates: :object }) + #or this + expect_json_types('address', {street: :string, city: :string, state: :string, coordinates: { lattitude: :float, longitude: :float } }) + end +end +``` Alternativley, if we only want to test `coordinates` we can dot into just the `coordinates`: - it 'should allow nested paths' do - get 'http://example.com/api/v1/simple_path_get' - expect_json('address.coordinates', {lattitude: 33.3872, longitutde: 104.5281} ) - end +```ruby +it 'should allow nested paths' do + get 'http://example.com/api/v1/simple_path_get' + expect_json('address.coordinates', {lattitude: 33.3872, longitutde: 104.5281} ) +end +``` When dealing with `arrays`, we can optionally test all (`*`) or a single (`?` - any, `0` - index) element of the array: Given the following JSON: +```json +{ + "cars": [ { - "cars":[ - {"make": "Tesla", "model": "Model S"}, - {"make": "Lamborghini", "model": "Aventador"} - ] + "make": "Tesla", + "model": "Model S" + }, + { + "make": "Lamborghini", + "model": "Aventador" } + ] +} +``` We can test against just the first car like this: - it 'should index into array and test against specific element' do - get '/array_api' - expect_json('cars.0', {make: "Tesla", model: "Model S"}) - end +```ruby +it 'should index into array and test against specific element' do + get '/array_api' + expect_json('cars.0', {make: "Tesla", model: "Model S"}) +end +``` To test the types of all elements in the array: - it 'should test all elements of the array' do - get 'http://example.com/api/v1/array_api - expect_json('cars.?', {make: "Tesla", model: "Model S"}) # tests that one car in array matches the tesla - expect_json_types('cars.*', {make: :string, model: :string}) # tests all cars in array for make and model of type string - end +```ruby +it 'should test all elements of the array' do + get 'http://example.com/api/v1/array_api' + expect_json('cars.?', {make: "Tesla", model: "Model S"}) # tests that one car in array matches the tesla + expect_json_types('cars.*', {make: :string, model: :string}) # tests all cars in array for make and model of type string +end +``` `*` and `?` work for nested arrays as well. Given the following JSON: +```json +{ + "cars": [ { - "cars": [{ - "make": "Tesla", - "model": "Model S", - "owners": [{ - "name": "Bart Simpson" - }] - }, { - "make": "Lamborghini", - "model": "Aventador", - "owners": [{ - "name": "Peter Griffin" - }] - }] + "make": "Tesla", + "model": "Model S", + "owners": [ + { + "name": "Bart Simpson" + } + ] + }, + { + "make": "Lamborghini", + "model": "Aventador", + "owners": [ + { + "name": "Peter Griffin" + } + ] } + ] +} +``` === - it 'should check all nested arrays for specified elements' do - get 'http://example.com/api/v1/array_with_nested' - expect_json_types('cars.*.owners.*', {name: :string}) - end - +```ruby +it 'should check all nested arrays for specified elements' do + get 'http://example.com/api/v1/array_with_nested' + expect_json_types('cars.*.owners.*', {name: :string}) +end +``` ##Configuration When setting up Airborne, you can call `configure` just like you would with `rspec`: - Airborne.configure.do |config| #config is the RSpec configuration and can be used just like it - config.include MyModule - end +```ruby +#config is the RSpec configuration and can be used just like it +Airborne.configure.do |config| + config.include MyModule +end +``` Additionally, you can specify a `base_url` and default `headers` to be used on every request (unless overriden in the actual request): - Airborne.configure.do |config| - config.base_url = 'http://example.com/api/v1' - config.headers = {'x-auth-token' => 'my_token'} - end - - describe 'spec' do - it 'now we no longer need the full url' do - get '/simple_get' - expect_json_types({name: :string}) - end - end +```ruby +Airborne.configure.do |config| + config.base_url = 'http://example.com/api/v1' + config.headers = {'x-auth-token' => 'my_token'} +end + +describe 'spec' do + it 'now we no longer need the full url' do + get '/simple_get' + expect_json_types({name: :string}) + end +end +``` ## License The MIT License