Skip to content

Instantly share code, notes, and snippets.

@guenter
Created June 24, 2010 17:55
Show Gist options
  • Select an option

  • Save guenter/451730 to your computer and use it in GitHub Desktop.

Select an option

Save guenter/451730 to your computer and use it in GitHub Desktop.

Revisions

  1. guenter created this gist Jun 24, 2010.
    42 changes: 42 additions & 0 deletions api.feature
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    Feature: API
    In order to use the service from third party apps
    As a user
    I want to be able to use an API

    Background:
    Given a user exists # Pickle
    And I login as the user using basic auth

    Scenario Outline: Get a ticket
    Given a ticket exists with title: "The network is down!", description: "Nothing works!" # Pickle
    When I GET "/tickets/{the ticket}" using <format>
    Then the response code should be 200
    And I should see the following ticket in <format> format
    | title | description |
    | The network is down! | Nothing works! |

    Examples:
    | format |
    | JSON |
    | XML |

    Scenario: Accept a ticket
    Given a ticket exists
    When I POST to "/tickets/{the ticket}/accept" using JSON
    Then the response code should be 200
    And the ticket should be accepted # Pickle
    And the user should be the ticket's engineer # Pickle

    Scenario: Requeue a ticket to an invalid technology
    Given a ticket exists
    When I POST to "/tickets/{the ticket}/requeue" using JSON
    """
    {"ticket":{"technology":"Wireless Power"}}
    """
    Then the response code should be 422
    And the ticket's status should not be "requeued" # Pickle
    And the response body should be
    """
    [["technology","is invalid"]]
    """

    74 changes: 74 additions & 0 deletions api_steps.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,74 @@
    def decode_api_response_as(model_name, format)
    if format == 'JSON'
    decoded = ActiveSupport::JSON.decode(response.body)
    if decoded.is_a?(Array)
    decoded.map { |inst| inst[model_name] }
    else
    decoded[model_name]
    end
    elsif format == 'XML'
    decoded = Hash.from_xml(response.body)
    decoded[model_name] || decoded[model_name.pluralize]
    else
    raise "Unsopported response format: #{format}"
    end
    end

    Given /^I login as #{capture_model} using basic auth$/ do |model_name|
    user_name = model(model_name).email
    password = 't35tp455w0rd'
    basic_auth(user_name, password)
    end

    When /^I (GET|POST|PUT|DELETE)(?: to)? "(.+)" using (JSON|XML)$/ do |method, path, format, *body|
    method = method.downcase.to_sym
    # Replace {the model} with the corresponding id
    path = path.gsub(/\{#{capture_model}\}/) { |match| model!($1).to_param }
    format = format.downcase
    # HAxx to make this arg. optional
    body = body.first

    header('Accept', "application/#{format}")
    header('Content-Type', "application/#{format}")
    visit(path, method, body)
    end

    Then /^the response code should be (\d+)$/ do |response_code|
    response.response_code.should == response_code.to_i
    end

    Then /^the response body should be$/ do |body|
    response.body.should == body
    end

    Then /^the "([^\"]*)" header should be "(.*)"$/ do |key, value|
    response.headers[key].should == value
    end

    Then /^I should see the following #{capture_plural_factory} in (JSON|XML) format$/ do |plural_factory, format, table|
    content_type = "application/#{format.downcase}"
    model_name = plural_factory.singularize.gsub(' ', '_')
    response_data = decode_api_response_as(model_name, format)

    # Check content type
    response.content_type.should == content_type

    attributes = table.headers
    expected = table.rows.sort
    actual = response_data.map { |row| row.values_at(*attributes).map(&:to_s) }.sort
    actual.should == expected
    end

    Then /^I should see the following #{capture_factory} in (JSON|XML) format$/ do |singular_factory, format, table|
    content_type = "application/#{format.downcase}"
    model_name = singular_factory.gsub(' ', '_')
    response_data = decode_api_response_as(model_name, format)

    # Check content type
    response.content_type.should == content_type

    attributes = table.headers
    expected = table.rows.first
    actual = response_data.values_at(*attributes).map(&:to_s)
    actual.should == expected
    end