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