lib/rspec-api/dsl/request/body.rb in rspec-api-0.2.0 vs lib/rspec-api/dsl/request/body.rb in rspec-api-0.4.0
- old
+ new
@@ -1,89 +1,85 @@
+require 'active_support'
require 'rspec-api/matchers'
module DSL
module Request
extend ActiveSupport::Concern
module ClassMethods
- def should_match_body_expectations(status_code, &block)
- should_return_a_jsonp rspec_api[:callback] if rspec_api[:callback]
- should_return_a_json rspec_api[:array] if success? status_code
- should_include_attributes rspec_api.fetch(:attributes, {}) if success? status_code
- if rspec_api[:array]
- should_include_fixture_data unless rspec_api[:page]
- should_be_sorted_by(rspec_api[:sort]) if rspec_api[:sort]
- should_be_filtered_by(rspec_api[:filter]) if rspec_api[:filter]
+ # Creates an example group for expectations on the response body of the
+ # last API request and runs it to verify that it matches best practices:
+ # * if response is succesful and has a body
+ # - the body should be a JSON-marshalled Array or Hash
+ # - if request has a callback parameter, the body should be JSONP
+ # - if request has a sort parameter, the body should be sorted
+ # - if request has a filter parameter, the body should be filtered
+ # - if custom expectations are passed, they should pass
+ # - if some attributes are expected, the body should include them
+ def should_respond_with_expected_body(options = {})
+ context 'responds with a body that' do
+ it { should_be_valid_json options[:type] }
+ it { should_be_wrapped_by options[:callbacks] }
+ it { should_be_sorted_by options[:sorts] }
+ it { should_be_filtered_by options[:filters] }
+ it { should_have_attributes options[:attributes] }
end
- should_satisfy_expectations_in &block if block_given?
end
+ end
- private
+ def should_be_valid_json(type)
+ expect(response).to be_valid_json_if response_is_successful?, type
+ end
- def should_return_a_jsonp(callback_options)
- it {
- if callback_options[:value] == request_params[callback_options[:name].to_s]
- expect(response_body).to be_a_jsonp(callback_options[:value])
- else
- expect(response_body).to be_a_jsonp(nil)
- end
- }
- end
+ # If the request had a 'callback' query parameter, then the body should be
+ # JSONP, otherwise it should not. For instance if the request was
+ # `GET /?method=alert` and the request `accepts_callback :method`, then
+ # the body must be a JSON wrapped in the alert(...) callback
+ # The +callback+ param says how the request might have been made, e.g.
+ # name: 'method', value: 'alert'... however to make sure that it was
+ # really made, we need to check that request_params['method'] is present
+ # and that is actually 'alert'
+ def should_be_wrapped_by(callback_params_sets)
+ callback_params = response_is_successful? && get_request_param_for_list(callback_params_sets)
+ value = callback_params[:value] if callback_params
+ expect(response).to be_a_jsonp_if callback_params, value
+ end
- def should_return_a_json(is_array)
- it { expect(response_body).to be_a_json(is_array ? Array : Hash) }
- end
+ def should_be_sorted_by(sort_params_sets)
+ sort_params = response_is_successful? && get_request_param_for_list(sort_params_sets)
+ options = sort_params ? sort_params.slice(:by, :verse) : {}
+ expect(response).to be_sorted_if sort_params, options
+ end
- def should_include_fixture_data
- it { expect(response_body).to include_fixture_data }
+ def should_be_filtered_by(filter_params_sets)
+ # TODO: The following is just so the condition does not match if it's nil
+ # but this should be fixed in get_request_param_for_list
+ if filter_params_sets
+ filter_params_sets = filter_params_sets.dup
+ filter_params_sets.each{|x| x[:value] = request_params.fetch(x[:name].to_s, :something_nil)}
end
+ filter_params = response_is_successful? && get_request_param_for_list(filter_params_sets)
+ value = filter_params[:value] if filter_params
+ options = filter_params ? filter_params.slice(:by, :comparing_with) : {}
+ expect(response).to be_filtered_if filter_params, value, options
+ end
- def should_be_sorted_by(sort_options)
- it {
- if sort_options[:parameter].to_s == request_params['sort']
- expect(response_body).to be_sorted_by(sort_options[:attribute], verse: :asc)
- elsif "-#{sort_options[:parameter].to_s}" == request_params['sort']
- expect(response_body).to be_sorted_by(sort_options[:attribute], verse: :desc)
- else
- expect(response_body).to be_sorted_by(nil)
- end
- }
- end
+ def should_have_attributes(attributes)
+ expect(response).to have_attributes_if response_is_successful?, attributes
+ end
- def should_be_filtered_by(filter_options)
- it {
- if json_value = request_params[filter_options[:name].to_s]
- expect(response_body).to be_filtered_by(json_value, filter_options)
- else
- expect(response_body).to be_filtered_by(nil)
- end
- }
- end
-
- def should_satisfy_expectations_in(&block)
- it { instance_exec(response_body, @request_params, &block) }
- end
-
- ## Attributes... might clean them up
- def should_include_attributes(attributes, ancestors = [], can_be_nil=false)
- attributes.each do |name, options = {}|
- should_match_attributes name, options, ancestors, can_be_nil
- should_include_nested_attributes name, options, ancestors
+ def get_request_param_for_list(params_sets)
+ (params_sets || []).find do |params|
+ conditions = []
+ conditions << (request_params[params[:name].to_s] == params[:value])
+ params.fetch(:extra_fields, {}).each do |name, value|
+ conditions << (request_params[name.to_s] == value)
end
+ conditions.all?
end
+ end
- def should_match_attributes(name, options, ancestors, can_be_nil)
- it {
- parent = ancestors.inject(response_body) do |chain, ancestor|
- Array.wrap(chain).map{|item| item[ancestor.to_s]}.flatten
- end
- expect(parent).to have_attribute(name, options.merge(parent_can_be_nil: can_be_nil, parent_can_be_empty: true))
- }
- end
-
- def should_include_nested_attributes(name, options, ancestors)
- attributes = options.fetch :attributes, {}
- should_include_attributes attributes, ancestors + [name], options[:can_be_nil]
- end
+ def response_is_successful?
+ response.status < 400 && !Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(response.status)
end
end
end
\ No newline at end of file