-
-
Save bosskovic/aaa88907bfe3b1bfb599 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/step_definitions/api_steps.rb | |
# These steps are very deeply inspired in the Anthony Eden (@aeden) API steps. | |
# See http://vimeo.com/30586709 | |
# Given | |
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.shopping-list+json; version=#{version}" | |
header 'Content-Type', "application/json" | |
end | |
Given /^I send and accept XML$/ do | |
header 'Accept', 'text/xml' | |
header 'Content-Type', 'text/xml' | |
end | |
# When | |
When /^I send a (\w+) request to "(.*?)"$/ do |method, path| | |
send(method.downcase, path) | |
end | |
When /^I send a POST request to "([^\"]*)" with the following:$/ do |path, body| | |
post path, body | |
end | |
# Then | |
Then /^the response status should be "([^"]*)"$/ do |status| | |
begin | |
last_response.status.should eq(status.to_i) | |
rescue RSpec::Expectations::ExpectationNotMetError => e | |
puts "Response body:" | |
puts last_response.body | |
raise e | |
end | |
end | |
Then /^the response body should be a JSON representation of the (\w+)$/ do |model| | |
last_response.body.should eq(model.constantize.last.to_json) | |
end | |
Then /^the response body should be a JSON representation of the (\w+) list$/ do |model| | |
last_response.body.should eq(model.constantize.all.to_json) | |
end | |
Then /^the response body should be a XML representation of the (\w+)$/ do |model| | |
last_response.body.should eq(model.constantize.last.to_xml) | |
end | |
Then /^the response body should be a XML representation of the (\w+) list$/ do |model| | |
last_response.body.should eq(model.constantize.all.to_xml) | |
end | |
Then /^the response body should have (\d+) (?:\w)$/ do |count| | |
JSON.parse(last_response.body).length.should eq(count.to_i) | |
end | |
Then /^the XML response body should have (\d+) (.*)$/ do |count, model| | |
Nokogiri::XML(last_response.body).search("/#{model.downcase.tr(" ", "-")}/#{model.downcase.tr(" ", "-").singularize}").size.should eq(count.to_i) | |
end | |
Then /^show me the (unparsed)?\s?response$/ do |unparsed| | |
if unparsed == 'unparsed' | |
puts last_response.body | |
elsif last_response.headers['Content-Type'] =~ /json/ | |
json_response = JSON.parse(last_response.body) | |
puts JSON.pretty_generate(json_response) | |
elsif last_response.headers['Content-Type'] =~ /xml/ | |
puts Nokogiri::XML(last_response.body) | |
else | |
puts last_response.headers | |
puts last_response.body | |
end | |
end | |
Then /^the (\w+) in the JSON representation of the (\w+) should be "([^"]*)"$/ do |attribute_name, model, attribute_value| | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".#{attribute_name}").match(json) | |
match.should eq(attribute_value) | |
end | |
Then /^the response body should be a JSON v(\d+) representation of the (\w+)$/ do |version, model| | |
last_response.body.should eq(model.capitalize.constantize.last.send("to_json_v#{version}")) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/step_definitions/authentication_steps.rb | |
Given(/^I have a valid authentication token$/) do | |
@current_user ||= User.find_by(email: "[email protected]") | |
@current_user ||= FactoryGirl.create(:me) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/products/create_product.feature | |
Feature: create a product | |
As a ... | |
In order to ... | |
I want to create a product | |
Scenario: create a product with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
When I send a POST request to "/[email protected]&user_token=ExaMpLeTokEn" with the following: | |
""" | |
{ | |
"product": { | |
"name":"Carrots" | |
} | |
} | |
""" | |
Then the response status should be "200" | |
And the response body should be a JSON representation of the created Product (Ember Data conventions) | |
And show me the response | |
Scenario: create a product as somebody else with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
When I send a POST request to "/[email protected]&user_token=ExaMpLeTokEn" with the following: | |
""" | |
{ | |
"product": { | |
"name":"Carrots", | |
"owner_id": 1 | |
} | |
} | |
""" | |
Then the response status should be "200" | |
And the response body should be a JSON representation of the created Product (Ember Data conventions) | |
And show me the response | |
Scenario: create a product with XML | |
Given I send and accept XML | |
And I have a valid authentication token | |
When I send a POST request to "/[email protected]&user_token=ExaMpLeTokEn" with the following: | |
""" | |
<?xml version="1.0"?> | |
<product> | |
<name>Carrots</name> | |
</product> | |
""" | |
Then the response status should be "201" | |
And the response body should be a XML representation of the Product | |
And show me the response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/products/destroy_product.feature | |
Feature: destroy a product | |
As an API client | |
In order to remove a buying option | |
I can destroy a product | |
Scenario: destroy a product with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And I have created 1 Product | |
When I send a DELETE request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" (Product) | |
Then the response status should be "204" | |
Scenario: destroy a product owned by somebody else with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And somebody else has created 1 Product | |
When I send a DELETE request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" (Product) | |
Then the response status should be "404" | |
Scenario: destroy a product with XML | |
Given I send and accept XML | |
And I have a valid authentication token | |
And I have created 1 Product | |
When I send a DELETE request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" (Product) | |
Then the response status should be "204" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/step_definitions/ember_data_compliance_steps.rb | |
Then /^the response body should fulfill the Ember Data expectations for (\w+)( list)?$/ do |model, multiple| | |
json = JSON.parse(last_response.body) | |
# The JSON response should be wrapped with it's model name, | |
# see http://emberjs.com/guides/models/the-rest-adapter/#toc_json-root | |
# Example: | |
# { | |
# "product": { | |
# "id": 1, | |
# "name": "carrots" | |
# } | |
# } | |
# | |
JSONSelect(".#{multiple ? model.underscore.pluralize : model.underscore}").test(json).should be_true | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/products/list_products.feature | |
Feature: list products | |
As an API client | |
In order to get all of items I can buy | |
I can list products | |
Scenario: list products with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And I have created 2 Products | |
When I send a GET request to "/[email protected]&user_token=ExaMpLeTokEn" | |
Then the response status should be "200" | |
And the response body should be a JSON representation of the Products list (Ember Data conventions) | |
And the JSON response body should list all Products (Ember Data conventions) | |
And show me the response | |
Scenario: list products created by others with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And I have created 3 Products | |
And somebody else has created 2 Products | |
When I send a GET request to "/[email protected]&user_token=ExaMpLeTokEn" | |
Then the response status should be "200" | |
And the JSON response body should list 3 Products (Ember Data conventions) | |
And show me the response | |
Scenario: list products with XML | |
Given I send and accept XML | |
And I have a valid authentication token | |
And I have created 2 Products | |
When I send a GET request to "/[email protected]&user_token=ExaMpLeTokEn" | |
Then the response status should be "200" | |
And the response body should be a XML representation of the Product list | |
And the XML response body should have 2 products | |
And show me the response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spec/factories/products.rb | |
FactoryGirl.define do | |
factory :product do | |
name "Apples" | |
owner | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# If you want to DRY your step definitions and forget about resources_steps.rb file, | |
# you can include (once and for all!) scaffolded_resources_steps.rb in your step definitions. | |
# features/step_definitions/products_steps.rb | |
# Given | |
Given /^I have created (\d+) Product(?:s)?$/ do |n| | |
@products ||= [] | |
n.to_i.times do | |
@products << FactoryGirl.create(:product, owner_id: @current_user.id) | |
end | |
end | |
Given /^somebody else has created (\d+) Product(?:s)?$/ do |n| | |
# @user doesn't need to be stable and can be generated often. | |
# On the contrary, @current_user must be stable. | |
# see `Given I have a valid authentication token` | |
@user ||= FactoryGirl.create(:user) | |
@products ||= [] | |
n.to_i.times do | |
@products << FactoryGirl.create(:product, owner_id: @user.id) | |
end | |
end | |
# When | |
When /^I send a (\w+) request to "(.*?)" \(Product\)$/ do |method, path| | |
path = Mustache.render(path, {product_id: @products.last.id}) | |
send(method.downcase, path) | |
end | |
When /^I send a (\w+) request to "(.*?)" with the following \(Product\):$/ do |method, path, body| | |
path = Mustache.render(path, {product_id: @products.last.id}) | |
send(method.downcase, path, body) | |
end | |
# Then | |
Then /^the response body should be a JSON representation of the( created)? Product \(Ember Data conventions\)$/ do |product_was_created| | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for Product | |
} | |
if product_was_created | |
puts "Internal index was updated after Product creation." | |
@products ||= [] | |
@products << Product.last | |
end | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".product").match(json) | |
ActiveSupport::JSON.encode(match).should eq(@products.last.to_json) | |
end | |
Then /^the response body should be a JSON representation of the Products list \(Ember Data conventions\)$/ do | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for Product list | |
} | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".products").match(json) | |
ActiveSupport::JSON.encode(match).should eq(@products.to_json) | |
end | |
Then /^the JSON response body should list all Products \(Ember Data conventions\)$/ do | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for Product list | |
} | |
json = JSON.parse(last_response.body) | |
JSONSelect(".products").match(json).length.should eq(@products.count) | |
end | |
Then /^the JSON response body should list (\d+) Products \(Ember Data conventions\)$/ do |n_products| | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for Product list | |
} | |
json = JSON.parse(last_response.body) | |
JSONSelect(".products").match(json).length.should eq(n_products.to_i) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/step_definitions/scaffolded_resources_steps.rb | |
# This file replaces all features/step_definitions/<resources>_steps.rb at once. | |
# Steps are a bit less easy to read, that's why I commented them a lot. | |
# | |
# It's up to you to keep creating the scaffold steps for each resource, however | |
# once I get more than six or seven models in an application, I personally prefer this version. | |
# Given | |
# Params: | |
# n - number of instances to create | |
# model - the resource model name | |
# | |
# Example: | |
# Given I have created 5 Products | |
# Given I have created 1 ShoppingList | |
# | |
Given /^I have created (\d+) (\w+)$/ do |n, model| | |
# Caution: model can be either a singluar or a pluralized model name. | |
# Set an instance variable to reference the Model instances | |
# @models | |
# | |
# See http://apidock.com/ruby/Object/instance_variable_set | |
instance_variable_name = ('@' + model.underscore.pluralize).to_sym | |
instance_variable_value = instance_variable_get(instance_variable_name) || [] | |
instance_variable_set(instance_variable_name, instance_variable_value) | |
# Create instances of Model | |
n.to_i.times do | |
# Remember model can be either a singluar or a pluralized model name. | |
factory_name = model.underscore.singularize.to_sym # :model | |
instance_variable_get(instance_variable_name) << FactoryGirl.create(factory_name) | |
end | |
end | |
# When | |
# Params: | |
# method - HTTP verb | |
# path - URI with Mustache inclusion for ID (see conventions) | |
# model - the resource model name | |
# | |
# Conventions: | |
# - The URI Mustache segments are ID placeholders. | |
# - Each segment follws the pattern: {{model_id}} | |
# - The model name corresponding to each segment is explicitely listed: (Model) | |
# | |
# Example: | |
# When I send a GET request to "/users/{{user_id}}/books" (User) | |
# | |
When /^I send a (\w+) request to "(.*?)" \((\w+)\)$/ do |method, path, model| | |
# Set an instance variable to reference the Model instances | |
# @models | |
# | |
# See http://apidock.com/ruby/Object/instance_variable_set | |
instance_variable_name = ('@' + model.underscore.pluralize).to_sym | |
instance_variable_value = instance_variable_get(instance_variable_name) || [] | |
instance_variable_set(instance_variable_name, instance_variable_value) | |
# URL placeholder for the Model instance ID | |
# :model_id | |
instance_id_symbol = (model.underscore.singularize + '_id').to_sym | |
path = Mustache.render(path, {instance_id_symbol => instance_variable_get(instance_variable_name).last.id}) | |
send(method.downcase, path) | |
end | |
# Params: | |
# method - HTTP verb | |
# path - URI with Mustache inclusion for ID (see conventions) | |
# model - the resource model name | |
# body - the request body | |
# | |
# Conventions: | |
# - The URI Mustache segments are ID placeholders. | |
# - Each segment follws the pattern: {{model_id}} | |
# - The model name corresponding to each segment is explicitely listed: (Model) | |
# - The request body is written with triple quotes. | |
# | |
# Example: | |
# When I send a POST request to "/users/{{user_id}}/books" with the following (User): | |
# """ | |
# { | |
# "book": { | |
# "title": "The RSpec Book", | |
# "author": "Chelimsky, David" | |
# } | |
# } | |
# """ | |
# | |
When /^I send a (\w+) request to "(.*?)" with the following \((\w+)\):$/ do |method, path, model, body| | |
# Set an instance variable to reference the Model instances | |
# @models | |
# | |
# See http://apidock.com/ruby/Object/instance_variable_set | |
instance_variable_name = ('@' + model.underscore.pluralize).to_sym | |
instance_variable_value = instance_variable_get(instance_variable_name) || [] | |
instance_variable_set(instance_variable_name, instance_variable_value) | |
# URL placeholder for the Model instance ID | |
# :model_id | |
instance_id_symbol = (model.underscore.singularize + '_id').to_sym | |
path = Mustache.render(path, {instance_id_symbol => instance_variable_get(instance_variable_name).last.id}) | |
send(method.downcase, path, body) | |
end | |
# Then | |
# Params: | |
# instance_was_created_flag - when not blank triggers the instances index update (use it for creation sceanrii) | |
# model - the resource model name | |
# | |
# Example: | |
# Then the JSON response body should be a JSON representation of the Product (Ember Data conventions) | |
# Then the JSON response body should be a JSON representation of the created Product (Ember Data conventions) | |
# | |
Then /^the response body should be a JSON representation of the( created)? (\w+) \(Ember Data conventions\)$/ do |instance_was_created_flag, model| | |
# Caution: model shouldn't but could be either a singluar or a pluralized model name. | |
steps %Q{ | |
Then the response body should fulfill the Ember Data expectations for #{model.camelize.singularize} | |
} | |
# Set an instance variable to reference the Model instances | |
# @models | |
# | |
# See http://apidock.com/ruby/Object/instance_variable_set | |
instance_variable_name = ('@' + model.underscore.pluralize).to_sym | |
instance_variable_value = instance_variable_get(instance_variable_name) || [] | |
instance_variable_set(instance_variable_name, instance_variable_value) | |
if instance_was_created_flag.presence | |
# Reference the last created instance | |
instance_variable_get(instance_variable_name) << model.camelize.singularize.constantize.last | |
Kernel.puts "Internal index was updated after #{model.camelize.singularize} creation." | |
end | |
# If you don't want to folllow the Ember Data conventions, adapt this to yours. | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".#{model.underscore.singularize}").match(json) | |
ActiveSupport::JSON.encode(match).should eq(instance_variable_get(instance_variable_name).last.to_json) | |
end | |
# Params: | |
# model - the resource model name | |
# | |
# Example: | |
# Then the response body should be a JSON representation of the Shoes list (Ember Data conventions) | |
# Then the response body should be a JSON representation of the Shoe list (Ember Data conventions) | |
# | |
Then /^the response body should be a JSON representation of the (\w+) list \(Ember Data conventions\)$/ do |model| | |
# Caution: model shouldn't but could be either a singluar or a pluralized model name. | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for #{model.camelize.singularize} list | |
} | |
# An instance variable that references the Model instances | |
# should have been set in a previous 'Given' step. | |
# @models | |
# Wee acced it with: instance_variable_get(instance_variable_name) | |
instance_variable_name = ('@' + model.underscore.pluralize).to_sym | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".#{model.underscore.pluralize}").match(json) | |
ActiveSupport::JSON.encode(match).should eq(instance_variable_get(instance_variable_name).to_json) | |
end | |
# Params: | |
# model - the resource model name | |
# | |
# Example: | |
# Then the JSON response body should list all Products (Ember Data conventions) | |
# Then the JSON response body should list all Product (Ember Data conventions) | |
# | |
Then /^the JSON response body should list all (\w+) \(Ember Data conventions\)$/ do |model| | |
# Caution: model shouldn't but could be either a singluar or a pluralized model name. | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for #{model.camelize.singularize} list | |
} | |
# An instance variable that references the Model instances | |
# should have been set in a previous 'Given' step. | |
# @models | |
# We acceed it with: instance_variable_get(instance_variable_name) | |
instance_variable_name = ('@' + model.underscore.pluralize).to_sym | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".#{model.underscore.pluralize}").match(json) | |
match.length.should eq(instance_variable_get(instance_variable_name).count) | |
end | |
# Params: | |
# model - the resource model name | |
# | |
# Example: | |
# Then the JSON response body should list 5 Products (Ember Data conventions) | |
# Then the JSON response body should list 1 Product (Ember Data conventions) | |
# | |
Then /^the JSON response body should list (\d+) (\w+) \(Ember Data conventions\)$/ do |n, model| | |
# Caution: model can be either a singluar or a pluralized model name. | |
steps %{ | |
Then the response body should fulfill the Ember Data expectations for #{model.camelize.singularize} list | |
} | |
json = JSON.parse(last_response.body) | |
match = JSONSelect(".#{model.underscore.pluralize}").match(json) | |
match.length.should eq(n.to_i) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/products/show_product.feature | |
Feature: show a product | |
As an API client | |
In order to see a single buying option | |
I can show a product | |
Scenario: show a product with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And I have created 1 Product | |
When I send a GET request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" (Product) | |
Then the response status should be "200" | |
And the response body should be a JSON representation of the Product (Ember Data conventions) | |
And show me the response | |
Scenario: show a product owned by somebody else with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And somebody else has created 1 Product | |
When I send a GET request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" (Product) | |
Then the response status should be "404" | |
And show me the response | |
Scenario: show a product with XML | |
Given I send and accept XML | |
And I have a valid authentication token | |
And I have created 1 Product | |
When I send a GET request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" (Product) | |
Then the response status should be "200" | |
And the response body should be a XML representation of the Product | |
And show me the response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/products/update_product.feature | |
Feature: update a product | |
As an API client | |
In order to update a buying option | |
I can update a product | |
Scenario: update a product with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And I have created 1 Product | |
When I send a PUT request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" with the following (Product): | |
""" | |
{ | |
"product": { | |
"name": "Salad" | |
} | |
} | |
""" | |
Then the response status should be "204" | |
And show me the response | |
Scenario: update a product owned by somebody else with JSON | |
Given I send and accept JSON | |
And I have a valid authentication token | |
And somebody else has created 1 Product | |
When I send a PUT request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" with the following (Product): | |
""" | |
{ | |
"product": { | |
"name": "Salad" | |
} | |
} | |
""" | |
Then the response status should be "404" | |
And show me the response | |
Scenario: update a product with XML | |
Given I send and accept XML | |
And I have a valid authentication token | |
And I have created 1 Product | |
When I send a PUT request to "/products/{{product_id}}[email protected]&user_token=ExaMpLeTokEn" with the following (Product): | |
""" | |
<?xml version="1.0"?> | |
<product> | |
<name>Carrots</name> | |
</product> | |
""" | |
Then the response status should be "204" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spec/factories/users.rb | |
FactoryGirl.define do | |
sequence :email do |n| | |
"user#{n}@factory.com" | |
end | |
factory :user do | |
name "test_user" | |
provider "open_id" | |
uid 1 | |
end | |
factory :owner, parent: :user | |
factory :me, parent: :user do | |
email "[email protected]" | |
authentication_token "ExaMpLeTokEn" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment