Skip to content

Instantly share code, notes, and snippets.

@andrewsardone
Created October 26, 2013 18:22
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save andrewsardone/9e7f54206c575961de7d to your computer and use it in GitHub Desktop.
Save andrewsardone/9e7f54206c575961de7d to your computer and use it in GitHub Desktop.
# A Cucumber environment file that sets up a test target API to use Faraday
# for full HTTP communication
require 'rubygems'
require 'bundler/setup'
require 'rspec'
require 'faraday'
require 'json_spec/cucumber'
# A wrapper around HTTP communication and setup of our JSON API for
# the purposes of test requests.
class TargetAPI
# setup an HTTP connection object that can be used across tests
def conn
@c ||= Faraday.new base_url, :ssl => {:verify => false} do |f|
f.request :basic_auth, 'user@example.com', 'api-auth-token-for-tests'
f.adapter :net_http
end
end
def base_url
@base_url ||= "https://#{domain}/"
end
# Configures receiver to be a target API endpoint appropriate for the suite
# of API specification tests.
#
# Returns :ready if setup succeeded.
def setup
# Set up fixtures or any backend stuff needed for your target JSON API
:ready
end
def domain
ENV['API_SPEC_DOMAIN'] || "example.com"
end
end
# json_spec support
def last_json
@last_response.body
end
Feature: Give us a JSON API
Scenario: Basic JSON API compliance
Given a REST API accessible account
When the client requests GET /accounts/336
Then the response status should be 200
And the JSON at "accounts" should be an array
And the JSON at "accounts" should have 1 entry
Scenario: Account attributes
Given a REST API accessible account
When the client requests GET /accounts/336
Then the JSON should have the following:
| accounts/0/id | "336" |
| accounts/0/name | "Example account" |
| accounts/0/type | "accounts" |
| accounts/0/description | null |
And the JSON at "accounts/0/createdTime" should not be null
Scenario: Account email attributes
Given a REST API accessible account
When the client requests GET /accounts/336
Then the JSON at "accounts/0/emails" should be an array
And the JSON at "accounts/0/emails/0" should be:
"""
{
"isPrimary": true,
"name": "email",
"value": "foo@example.com"
}
"""
Scenario: tags relationship
Given a REST API accessible account
When the client requests GET /accounts/336
Then the JSON at "accounts/0/links/tags" should be [ "19", "24" ]
And the resource link at "links/accounts.tags/href" should have the path /tags/{accounts.tags}
And the JSON at "links/accounts.tags/type" should be "tags"
Scenario: Changing the name of an account
Given a REST API accessible account
When the client requests PATCH /accounts/336 with the body:
"""
[
{ "op": "replace", "path": "/accounts/0/name", "value": "Some other name" }
]
"""
Then the response status should be 204 No Content
When the client requests GET /accounts/336
Then the JSON at "accounts/0/name" should be "Some other name"
source "https://rubygems.org"
# tests
gem "rspec", "~> 2.13.0"
gem "cucumber", "~> 1.3.2"
# HTTP requests
gem "faraday", "~> 0.8.7"
# easier JSON testing
gem "json_spec", "~> 1.1.1"
gem "json"
# Example Cucumber HTTP step definitions
Given(/^a REST API/) do
@rest_api = TargetAPI.new
expect(@rest_api.setup).to eq(:ready)
end
When(/^the client requests GET \/(.*)$/) do |path|
@last_response = @rest_api.conn.get path
end
When(/^the client requests DELETE \/(.*)$/) do |path|
@last_response = @rest_api.conn.delete path
end
When /^the client requests PATCH \/(.*) with the body:$/ do |path, body|
@last_response = @rest_api.conn.patch do |req|
req.url path
req.headers['Content-Type'] = 'application/json-patch+json'
req.body = body
end
end
Then(/^the response status should be (\d+)(?:.*)$/) do |status_code|
expect(@last_response.status).to eq(status_code.to_i)
end
# Handy for asserting that a JSON API link is included in some response JSON
Then(/the resource link at "(.*)" should have the path \/?(.*)$/) do |path, relative_url|
expect(@last_response.body).to be_json_eql("\"#{@rest_api.base_url}#{relative_url}\"").at_path(path)
end
@jfinkhaeuser
Copy link

This is an approach that works well for us, too.

We've rolled more or less this Faraday setup into our https://github.com/spriteCloud/lapis-lazuli gem. Mind you, API testing with Faraday is barely necessary to simplify. Most of the code there makes watir usage a little less painful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment