Skip to content

Instantly share code, notes, and snippets.

@bosskovic
Last active November 30, 2018 19:19
Show Gist options
  • Save bosskovic/091a8dfbfa41d5e9a49a to your computer and use it in GitHub Desktop.
Save bosskovic/091a8dfbfa41d5e9a49a to your computer and use it in GitHub Desktop.
Developing rails REST API with Cucumber
Given /^I send and accept JSON$/ do
header 'Accept', 'application/json'
header 'Content-Type', 'application/json'
end
Given /^I send and accept JSON using version (\d+) of the (\w+) API$/ do |version, model|
header 'Accept', "application/vnd.#{model}+json; version=#{version}"
header 'Content-Type', 'application/json'
end
When(/^I authenticate via auth_token "([^"]*)" and email "([^"]*)" in header$/) do |auth_token, email|
header('X-User-Email', email)
header('X-User-Token', auth_token)
end
When (/^I authenticate as (user|admin)$/) do |user_type|
@authenticated_user = find_user_by_type(user_type)
token = @authenticated_user.authentication_token
email = @authenticated_user.email
steps %{
When I authenticate via auth_token "#{token}" and email "#{email}" in header
}
end
# features/support/custom_env.rb
require 'json_spec/cucumber'
def last_json
last_response.body
end
Feature: Fruit list
In order to make a great smoothie
I need some fruit.
Scenario: List fruit
Given the system knows about the following fruit: banana, strawberry
When the client requests GET /fruits
Then the response status should be "OK"
And the JSON response at "users" should have 2 fruits
And fruits array should include banana and strawberry with name and color
And the response should include last href
# source: http://media.pragprog.com/titles/hwcuc/code/rest_web_services/00/features/fruit_list.feature
Feature: Fruit list
In order to make a great smoothie
I need some fruit.
Scenario: List fruit
Given the system knows about the following fruit:
| name | color |
| banana | yellow |
| strawberry | red |
When the client requests GET /fruits
Then the response should be JSON:
"""
[
{"name": "banana", "color": "yellow"},
{"name": "strawberry", "color": "red"}
]
"""
CAPTURE_FRUIT_NAMES = Transformation /^(?:(?:apple|banana|pear|strawberry)(?:,\s|\sand\s)?)+$/ do |fruit_names|
fruit_names.gsub('and', ',').split(',').map { |e| e.strip.gsub(' ', '_').to_sym }
end
# using faker gem: https://github.com/stympy/faker
def create_fruit_by_name(name)
Fruit.create name: name, color: Faker::Commerce.color
end
Given(/^Given the system knows about the following fruit(?::)? (#{CAPTURE_FRUIT_NAMES})$/) do |user_types|
fruit_names.each { |name| create_fruit_by_name name }
end
When /^the client requests (GET|POST|PUT|DELETE) (.*?)$/ do |request_type, path|
request_opts = { method: request_type.downcase.to_sym }
@last_href = "http://example.org#{path}"
request(path, request_opts).inspect
end
CAPTURE_RECOGNIZED_STATUS = Transform /^OK|UNPROCESSABLE|FORBIDDEN|UNAUTHORIZED|CREATED$/ do |status|
status
end
Then /^the response status should be "(#{CAPTURE_RECOGNIZED_STATUS})"$/ do |status|
begin
case status
when 'OK'
expect(last_response.status).to eq 200
last_json.should be_json_eql(JsonSpec.remember(200)).at_path('status')
last_json.should be_json_eql(JsonSpec.remember(true)).at_path('success')
when 'UNPROCESSABLE'
expect(last_response.status).to eq 422
last_json.should be_json_eql(JsonSpec.remember(422)).at_path('status')
last_json.should be_json_eql(JsonSpec.remember(false)).at_path('success')
when 'FORBIDDEN'
expect(last_response.status).to eq 403
last_json.should be_json_eql(JsonSpec.remember(403)).at_path('status')
last_json.should be_json_eql(JsonSpec.remember(false)).at_path('success')
when 'UNAUTHORIZED'
expect(last_response.status).to eq 401
last_json.should be_json_eql(JsonSpec.remember(401)).at_path('status')
last_json.should be_json_eql(JsonSpec.remember(false)).at_path('success')
when 'CREATED'
expect(last_response.status).to eq 201
last_json.should be_json_eql(JsonSpec.remember(201)).at_path('status')
last_json.should be_json_eql(JsonSpec.remember(true)).at_path('success')
end
rescue RSpec::Expectations::ExpectationNotMetError => e
puts 'Response body:'
puts last_response.body
raise e
end
end
# this one is dealt with json_spec cucumber steps directly
# (https://github.com/collectiveidea/json_spec/blob/master/lib/json_spec/cucumber.rb)
# it checks if response is a JSON array and if it has specified size
# And /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? have (\d+)/ do |path, negative, size|
CAPTURE_FIELD_NAMES = Transformation /^(.*?)$/ do |fields|
fields.gsub('and', ',').split(',').map { |e| e.strip.to_sym }
end
def compare_json_with_record(json, record, fields)
field.each do |field|
expect(json).to be_json_eql(JsonSpec.remember(record[field])).at_path(field)
end
end
And(/^fruits array should include (#{CAPTURE_FRUIT_NAMES}) with (#{CAPTURE_FIELD_NAMES})$/) do |fruit_names, fields|
fruit_names.each do |fruit_name|
fruit = Fruit.where(name: fruit_name).pluck(fields).first
compare_json_with_record(last_json, fruit, fields)
end
end
And(/^the response should include last href$/) do
expect(last_json).to be_json_eql(JsonSpec.remember(@last_href.to_json)).at_path('href')
end
# this is how the response to GET /fruits would look like:
# { "href" : "http://example.org/fruits",
# "success" : true,
# "status" : 200,
# "count" : 2,
# "fruits" : [
# { "name" : "banana", "color" : "random color name" },
# { "name" : "strawberry", "color" : "random color name" } ]
. . .
group :test do
gem 'cucumber-rails', '1.4.1', :require => false
gem 'json_spec', '1.1.2'
. . .
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment