Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test content type #26

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
aaa5041
Test for content type
pezholio Dec 10, 2013
f8f9254
Attempt to test the test
pezholio Dec 10, 2013
1e5f70d
Update README.md
Spone Sep 29, 2014
de55ef8
Merge pull request #30 from Spone/patch-1
jayzes Sep 29, 2014
e522861
Fix link to Cucumber
Spone Oct 19, 2014
0cc7047
Merge pull request #31 from Spone/patch-1
kalys Oct 19, 2014
27efce1
update rspec should syntax to v3 expect syntax
daleki Jul 13, 2015
69a5e73
Merge pull request #34 from daleki/master
kalys Aug 1, 2015
1b53fcf
Pass StringIO instead of String when docstring is given as parameters
kalys Aug 3, 2015
49872d6
Add support for PATCH requests
Jun 8, 2015
d395192
Revert version
kalys Aug 5, 2015
9b5d393
Update to the latest classes
edenvicary Aug 28, 2015
a0f1269
Update Cucumber and Rspec
edenvicary Aug 28, 2015
99e7e9d
Merge pull request #37 from cvcnetwork/update-rspec
jayzes Aug 31, 2015
0a27007
Merge pull request #36 from cvcnetwork/clean-warnings
jayzes Aug 31, 2015
194f57a
Highlight Ruby and Gherkin syntax in README.md.
Sep 24, 2015
190d093
Merge pull request #39 from kirillzhukov-cc/patch-1
jayzes Sep 25, 2015
794c8c1
Bump version to 0.2.0
Oct 25, 2017
eb119a6
Remove stub RVM configuration
Oct 25, 2017
854a4ba
Bump version to 0.14.0
Oct 25, 2017
431da77
Modernize the list of Ruby versions to test against
Oct 25, 2017
f40aef7
Add LICENSE file
Oct 25, 2017
05113bb
fix "the JSON response should be"
glaszig Apr 18, 2018
6bf71c5
Merge pull request #49 from glaszig/patch-1
jayzes Apr 18, 2018
3cad2a1
fix assertion argument order
glaszig Apr 19, 2018
da0c270
use Base64.strict_encode64 which does not
glaszig Apr 19, 2018
85a6801
test against ruby 2.5 and ruby-head as well
glaszig Apr 19, 2018
5c55410
Merge pull request #50 from glaszig/patch-2
jayzes Apr 19, 2018
82cba14
Merge pull request #51 from glaszig/fix-tests
jayzes Apr 19, 2018
61d621f
Merge pull request #52 from glaszig/test-rubies
jayzes Apr 19, 2018
0e4f586
Fixed a wrong example
rrooding Oct 16, 2018
1891eb9
Merge pull request #54 from rrooding/patch-1
kalys Oct 16, 2018
e425f34
Test for content type
pezholio Dec 10, 2013
0e5a4e9
Attempt to test the test
pezholio Dec 10, 2013
de7cf3a
Merge branch 'feature-test-content-type' of github.com:Data-Liberatio…
Floppy May 20, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion .rvmrc

This file was deleted.

9 changes: 5 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
language: ruby
rvm:
- "1.9.3"
- "2.0.0"
- "2.1.2"
- jruby-19mode # JRuby in 1.9 mode
- 2.2.8
- 2.3.5
- 2.4.2
- 2.5.1
- jruby-20mode # JRuby in 1.9 mode
- ruby-head
21 changes: 21 additions & 0 deletions LICENSE.TXT
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 Ello PBC

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
98 changes: 51 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
[![Build Status](https://travis-ci.org/jayzes/cucumber-api-steps.png)](https://travis-ci.org/jayzes/cucumber-api-steps)
[![Gem Version](https://badge.fury.io/rb/cucumber-api-steps.png)](http://badge.fury.io/rb/cucumber-api-steps)

A set of [Cucumber](https://github.com/aslakhellesoy/cucumber) step definitions utilizing
A set of [Cucumber](https://github.com/cucumber/cucumber) step definitions utilizing
[Rack-Test](https://github.com/brynary/rack-test) that ease basic
testing of REST-style APIs using either XML or JSON formats.

Adapted from [a blog post by Anthony Eden](http://www.anthonyeden.com/2010/11/testing-rest-apis-with-cucumber-and-rack-test/) with a few additions based on my own needs. I found myself copying these step definitions around to multiple projects, and decided that it would be worthwhile to gem them up to keep things nice and DRY.
Adapted from [a blog post by Anthony Eden](http://anthonyeden.com/2013/07/10/testing-rest-apis-with-cucumber-and-rack.html) with a few additions based on my own needs. I found myself copying these step definitions around to multiple projects, and decided that it would be worthwhile to gem them up to keep things nice and DRY.

## Dependencies

Expand All @@ -17,60 +17,64 @@ Requires [Cucumber](https://github.com/aslakhellesoy/cucumber) (obviously). Als

Add the following line to your Gemfile, preferably in the test or cucumber group:

gem 'cucumber-api-steps', :require => false
```ruby
gem 'cucumber-api-steps', :require => false
```

Then add the following line to your env.rb to make the step definitions available in your features:

require 'cucumber/api_steps'
```ruby
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.

# 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"

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"

```cucumber
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 the 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"

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
* Justin Smestad
Expand Down
6 changes: 3 additions & 3 deletions cucumber-api-steps.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ Gem::Specification.new do |s|
s.version = Cucumber::ApiSteps::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["Jay Zeschin"]
s.email = ["jay.zeschin@modeset.com"]
s.email = ["jay@zeschin.org"]
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.required_ruby_version = '>= 1.9.3'

s.add_dependency 'jsonpath', '>= 0.1.2'
s.add_dependency 'cucumber', '>= 1.2.1'
s.add_dependency 'cucumber', '>= 2.0.2'
s.add_development_dependency 'activesupport', '>= 3.0.0'
s.add_development_dependency 'rspec', '~> 2.12.0'
s.add_development_dependency 'rspec', '~> 3.3.0'
s.add_development_dependency 'sinatra', '~> 1.4.3'

s.files = `git ls-files`.split("\n")
Expand Down
6 changes: 5 additions & 1 deletion features/fixtures/fake_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class FakeApp < Sinatra::Base
if request.accept.empty? || request.accept?('application/json')
content_type :json
books.to_json
elsif request.accept?('application/xml')
elsif request.accept?('application/xml')
content_type :xml
books.to_xml
end
Expand All @@ -25,6 +25,10 @@ class FakeApp < Sinatra::Base
status 201 if params.values == ["Metaprograming ruby", "Pragprog"]
end

patch '/api/books' do
status 200 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'}
Expand Down
9 changes: 9 additions & 0 deletions features/request.feature
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ Feature:
"""
Then the response status should be "201"

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

Scenario: POST request with string
When I perform the following step with string:
"""
Expand Down
9 changes: 9 additions & 0 deletions features/response.feature
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ Feature:
"""

Then the response status should be "200"

Scenario: Test response content type
And I perform the following step:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And => When

"""
I send and accept XML
I send a GET request to "/api/books"
"""

Then the response content type should be XML

Scenario: Test that JSON response contains a node
When I perform the following step:
Expand Down
8 changes: 4 additions & 4 deletions features/step_definitions/api_test_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
end

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

When /^I perform the following step with table:$/ do |step_definition|
Expand All @@ -33,13 +33,13 @@
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)
expect(last_request.env.slice(*headers_hash.keys).values).to eq(headers_hash.values)
end

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

Then /^I should be digest authenticated$/ do
last_request.env["HTTP_AUTHORIZATION"].starts_with?("Digest ").should be_true
expect(last_request.env["HTTP_AUTHORIZATION"].starts_with?("Digest ")).to be true
end
52 changes: 30 additions & 22 deletions lib/cucumber/api_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,18 @@ def to_str
digest_authorize user, pass
end

When /^I send a (GET|POST|PUT|DELETE) request (?:for|to) "([^"]*)"(?: with the following:)?$/ do |*args|
When /^I send a (GET|PATCH|POST|PUT|DELETE) request (?:for|to) "([^"]*)"(?: with the following:)?$/ do |*args|
request_type = args.shift
path = args.shift
input = args.shift

request_opts = {method: request_type.downcase.to_sym}

unless input.nil?
if input.class == Cucumber::Ast::Table
if input.class == Cucumber::MultilineArgument::DataTable
request_opts[:params] = input.rows_hash
else
request_opts[:input] = input
request_opts[:input] = StringIO.new input
end
end

Expand All @@ -69,21 +69,29 @@ def to_str
end

Then /^the response status should be "([^"]*)"$/ do |status|
if self.respond_to? :should
last_response.status.should == status.to_i
if self.respond_to?(:expect)
expect(last_response.status).to eq(status.to_i)
else
assert_equal status.to_i, last_response.status
end
end

Then(/^the response content type should be (XML|JSON)$/) do |type|
if self.respond_to? :should
last_response.content_type.should include("application/#{type.downcase}")
else
assert last_response.content_type.include?("application/#{type.downcase}")
end
end

Then /^the JSON response should (not)?\s?have "([^"]*)"$/ do |negative, json_path|
json = JSON.parse(last_response.body)
results = JsonPath.new(json_path).on(json).to_a.map(&:to_s)
if self.respond_to?(:should)
if self.respond_to?(:expect)
if negative.present?
results.should be_empty
expect(results).to be_empty
else
results.should_not be_empty
expect(results).not_to be_empty
end
else
if negative.present?
Expand All @@ -98,11 +106,11 @@ def to_str
Then /^the JSON response should (not)?\s?have "([^"]*)" with the text "([^"]*)"$/ do |negative, json_path, text|
json = JSON.parse(last_response.body)
results = JsonPath.new(json_path).on(json).to_a.map(&:to_s)
if self.respond_to?(:should)
if self.respond_to?(:expect)
if negative.present?
results.should_not include(text)
expect(results).not_to include(text)
else
results.should include(text)
expect(results).to include(text)
end
else
if negative.present?
Expand All @@ -116,11 +124,11 @@ def to_str
Then /^the XML response should (not)?\s?have "([^"]*)"$/ do |negative, xpath|
parsed_response = Nokogiri::XML(last_response.body)
elements = parsed_response.xpath(xpath)
if self.respond_to?(:should)
if self.respond_to?(:expect)
if negative.present?
elements.should be_empty
expect(elements).to be_empty
else
elements.should_not be_empty
expect(elements).not_to be_empty
end
else
if negative.present?
Expand All @@ -134,9 +142,9 @@ def to_str
Then /^the XML response should have "([^"]*)" with the text "([^"]*)"$/ do |xpath, text|
parsed_response = Nokogiri::XML(last_response.body)
elements = parsed_response.xpath(xpath)
if self.respond_to?(:should)
elements.should_not be_empty, "could not find #{xpath} in:\n#{last_response.body}"
elements.find { |e| e.text == text }.should_not be_nil, "found elements but could not find #{text} in:\n#{elements.inspect}"
if self.respond_to?(:expect)
expect(elements).not_to be_empty, "could not find #{xpath} in:\n#{last_response.body}"
expect(elements.find { |e| e.text == text }).not_to be_nil, "found elements but could not find #{text} in:\n#{elements.inspect}"
else
assert !elements.empty?, "could not find #{xpath} in:\n#{last_response.body}"
assert elements.find { |e| e.text == text }, "found elements but could not find #{text} in:\n#{elements.inspect}"
Expand All @@ -147,18 +155,18 @@ def to_str
expected = JSON.parse(json)
actual = JSON.parse(last_response.body)

if self.respond_to?(:should)
actual.should == expected
if self.respond_to?(:expect)
expect(actual).to eq(expected)
else
assert_equal actual, response
assert_equal expected, actual
end
end

Then /^the JSON response should have "([^"]*)" with a length of (\d+)$/ do |json_path, length|
json = JSON.parse(last_response.body)
results = JsonPath.new(json_path).on(json)
if self.respond_to?(:should)
results.length.should == length.to_i
if self.respond_to?(:expect)
expect(results.length).to eq(length.to_i)
else
assert_equal length.to_i, results.length
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cucumber/api_steps/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Cucumber
module ApiSteps
VERSION = "0.13"
VERSION = "0.14.0"
end
end