Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rvm use ree@cucumber-api-steps
rvm use 1.9.3@cucumber-api-steps
9 changes: 8 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
source :rubygems
source :rubygems

gemspec

gem 'sinatra'
gem 'rack-test'
gem 'pry'
gem 'activesupport'
gem 'nokogiri'
48 changes: 45 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,54 @@ Add the following line to your Gemfile, preferably in the test or cucumber group
Then add the following line to your env.rb to make the step definitions available in your features:

require 'cucumber/api_steps'

# Usage

Still a work in progress. For now, read the api_steps.rb file or check out the [stashboard-rails](https://github.com/jayzes/stashboard-rails) project - its Cucumber features make extensive use of the steps in this gem.
Still a work in progress. For now, read the api_steps.rb file or check out the [stashboard-rails](https://github.com/jayzes/stashboard-rails) project - its Cucumber features make extensive use of the steps in this gem.

# Examples

Feature: API

Scenario: List tweets in JSON
When I send and accept JSON
And I send a GET request to "/api/tweets"
Then the response status should be "200"
And the JSON response should be:
"""
[{"tweet":"Hello World!"},{"tweet":"New Rails has been released"}]
"""
And the JSON response should have "$..tweet" with the text "Hello World!"
And the JSON response should have "$..tweet" with a length of 2

Scenario: List tweets in XML
When I send and accept XML
And I send a GET request to "/api/tweets"
Then the XML response should have "tweet" with text "Hello World!"

Scenario: Post tweet using POST-params
When I send a POST request to "/api/tweets" with the following:
| tweet | Hello World! |
| lat | 42.848282 |
| lng | 74.634933 |
Then the response status should be "201"

Scenario: Post tweet using json in POST body
When I send a POST request to "/api/tweets" with the following:
"""
{"tweet":"Hello World!","lat":"42.848282", "lng":"74.634933"}
"""
Then the response status should be "201"

Scenario: Basic authentication
When I authenticate as the user "joe" with the password "password123"
And I send a GET request to "/api/tweets"
Then the response status should be "200"

One major caveat is that the way the steps are currently built, the PUT and POST steps accept a heredoc-style string (demarcated with lines of three double quotes) as a body, instead of a hash as many people seem to expect. I found this way to be more natural/flexible for how I write API tests, but it seems like others do not, so I'll be changing the steps to accept either a hash or a string soon.
Scenario: Digest authentication
When I digest-authenticate as the user "joe" with the password "password123"
And I send a GET request to "/api/tweets"
Then the response status should be "200"

# Contributors
* Jay Zeschin
Expand Down
6 changes: 3 additions & 3 deletions cucumber-api-steps.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ Gem::Specification.new do |s|
s.homepage = "http://github.com/jayzes/cucumber-api-steps"
s.summary = %q{Cucumber steps to easily test REST-based XML and JSON APIs}
s.description = %q{Cucumber steps to easily test REST-based XML and JSON APIs}

s.add_dependency 'jsonpath', '>= 0.1.2'
s.add_dependency 'cucumber', '>= 0.8.3'
s.add_development_dependency 'capybara'
s.add_dependency 'cucumber', '>= 1.2.1'
s.add_dependency 'rspec', '>= 2.12.0'

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
Expand Down
21 changes: 21 additions & 0 deletions features/authentication.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Feature:
As cucumber tester
I want to test basic authentication

Scenario: Basic authentication
When I perform the following steps:
"""
I authenticate as the user "joe" with the password "god"
I send a GET request for "/"
"""
Then I should be authenticated


@digest-auth
Scenario: Successful digest authentication
When I perform the following steps:
"""
I digest-authenticate as the user "joe" with the password "god"
I send a GET request for "/"
"""
Then I should be digest authenticated
31 changes: 31 additions & 0 deletions features/fixtures/fake_app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require "rubygems"
require "sinatra/base"

module CucumberApiSteps
class FakeApp < Sinatra::Base

get '/' do end

get '/api/books' do
books = {books: [
{title: 'Pride and prejudice'},
{title: 'Metaprograming ruby'}
]}

if request.accept.include? 'application/xml'
books.to_xml
else
books.to_json
end
end

post '/api/books' do
status 201 if params.values == ["Metaprograming ruby", "Pragprog"]
end

post '/api/publishers' do
input_data = JSON.parse request.env["rack.input"].read, symbolize_names: true
status 201 if input_data == {publisher: 'Pragprog'}
end
end
end
32 changes: 32 additions & 0 deletions features/header.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Feature:
As cucumber tester
I should be able to set headers for request

Scenario: Set multiple headers
When I perform the following step with table:
"""
I set headers:
| Accept | application/vnd.myproject.v1 |
| User-Agent | Cucumber Api Steps Client |
"""
Then the request headers should be:
| HTTP_ACCEPT | application/vnd.myproject.v1 |
| HTTP_USER_AGENT | Cucumber Api Steps Client |

Scenario: Send and accept JSON
When I perform the following step:
"""
I send and accept JSON
"""
Then the request headers should be:
| HTTP_ACCEPT | application/json |
| CONTENT_TYPE | application/json |

Scenario: Send and accept HTML
When I perform the following step:
"""
I send and accept HTML
"""
Then the request headers should be:
| HTTP_ACCEPT | text/html |
| CONTENT_TYPE | application/x-www-form-urlencoded |
25 changes: 25 additions & 0 deletions features/request.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Feature:

Scenario: GET request
When I perform the following step:
"""
I send a GET request to "/api/books"
"""
Then the response status should be "200"

Scenario: POST request with params
When I perform the following step with table:
"""
I send a POST request to "/api/books" with the following:
| title | Metaprograming ruby |
| publisher | Pragprog |
"""
Then the response status should be "201"

Scenario: POST request with string
When I perform the following step with string:
"""
I send a POST request to "/api/publishers" with the following:
{"publisher": "Pragprog"}
"""
Then the response status should be "201"
50 changes: 50 additions & 0 deletions features/response.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Feature:
As cucumber tester
I want to test response

Scenario: Test response status
When I perform the following step:
"""
I send a GET request to "/"
"""

Then the response status should be "200"

Scenario: Test if JSON response contains text
When I perform the following step:
"""
I send a GET request to "/api/books"
"""
Then the JSON response should have "$..title" with the text "Metaprograming ruby"

Scenario: Test if JSON response doesn't contain text
When I perform the following step:
"""
I send a GET request to "/api/books"
"""
Then the JSON response should not have "$..publisher" with the text "Metaprograming ruby"

Scenario: Test if XML response contains text
When I send and accept XML
And I perform the following step:
"""
I send a GET request to "/api/books"
"""
Then the XML response should have "//title" with the text "Metaprograming ruby"

Scenario: Test JSON response
When I perform the following step:
"""
I send a GET request to "/api/books"
"""
Then the JSON response should be:
"""
{"books":[{"title":"Pride and prejudice"},{"title":"Metaprograming ruby"}]}
"""

Scenario: Test JSON with length of some element
When I perform the following step:
"""
I send a GET request to "/api/books"
"""
Then the JSON response should have "$..title" with a length of 2
44 changes: 44 additions & 0 deletions features/step_definitions/api_test_steps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'active_support/core_ext'

When /^I perform the following steps?:$/ do |step_strings|
steps = step_strings.split("\n")
steps.each {|step_string| step step_string }
end

Then /^the response should equal:$/ do |response_body|
last_response.body.should eq(response_body)
end

When /^I perform the following step with table:$/ do |step_definition|
lines = step_definition.split("\n")
step_string = lines.shift

raw = lines.map do |line|
line.squish.gsub(/^\|/, '').gsub(/\|$/, '').squish.split("|").map(&:squish)
end

step step_string, table(raw)
end

When /^I perform the following step with string:$/ do |step_definition|
lines = step_definition.split("\n")
step_string = lines.shift

param_string = lines.join("\n")

step step_string, param_string
end

Then /^the request headers should be:$/ do |headers|
headers_hash = headers.rows_hash
request '/'
last_request.env.slice(*headers_hash.keys).values.should eq(headers_hash.values)
end

Then /^I should be authenticated$/ do
last_request.env["HTTP_AUTHORIZATION"].should eq("Basic #{Base64.encode64("joe:god")}")
end

Then /^I should be digest authenticated$/ do
last_request.env["HTTP_AUTHORIZATION"].starts_with?("Digest ").should be_true
end
28 changes: 20 additions & 8 deletions features/support/env.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support
require 'capybara/cucumber'
require 'pry'

# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
# order to ease the transition to Capybara we set the default here. If you'd
# prefer to use XPath just remove this line and adjust any selectors in your
# steps to use the XPath syntax.
Capybara.default_selector = :css
Capybara.default_driver = :rack_test
require 'rack'
require 'rack/test'
require File.dirname(__FILE__) + "/../fixtures/fake_app"

require 'cucumber/api_steps'
require 'cucumber/api_steps'

def app
Rack::Lint.new(CucumberApiSteps::FakeApp.new)
end

Before("@digest-auth") do
def app
app = Rack::Auth::Digest::MD5.new(CucumberApiSteps::FakeApp.new) do |username|
{ 'joe' => 'god' }[username]
end
app.realm = 'TestApi'
app.opaque = 'this-should-be-secret'
app
end
end
Loading