zipmark / rspec_api_documentation

Automatically generate API documentation from RSpec
MIT License
1.45k stars 362 forks source link

Conflicts with built-in RSpec matchers #277

Open reidab opened 8 years ago

reidab commented 8 years ago

Over time, I've run into several situations where I'll declare a parameter, not set a value for it, and end up with a 500 error as my app attempts to parse #<RSpec::Matchers::BuiltIn::Cover:0x007fc442e99d38> or another built-in matcher as JSON.

For example:

  resource 'Widgets' do
    parameter :cover, "url of the widget's cover image"

    put "/api/widgets" do
      example_request "Create a widget" do
        expect(status).to eq 201
      end
    end
  end

The params sent to the server in this case look like:

{"cover"=>#<RSpec::Matchers::BuiltIn::Cover:0x007f9c2e83b608}`

Adding let(:cover) { nil } solves the problem, but it might be good to provide a nicer experience around this. Would it make sense to either blacklist the RSpec::Matchers::BuiltIn classes from being used as param values or warn the user when one makes it through to param serialization?

outsmartin commented 8 years ago

I'm currently experiencing the same issue with

parameter :include

Is there some way to disable the automatic method generation?

oestrich commented 8 years ago

The problem isn't automatic method generation, it's RAD seeing a method that matches the parameter name and calling it: dsl/endpoint.rb.

I don't have a good solution for this outside of let(:include) { nil } which isn't good. If you find a nice way around this I'll be happy to look at a PR.

soberstadt commented 7 years ago

I ran into this today too. This is what I did to fix the problem:

in my acceptance_helper.rb:

module RspecApiDocumentation::DSL
  module Endpoint
    private

    def set_param(hash, param)
      key = param[:name]

      keys = [param[:scope], key].flatten.compact
      method_name = keys.join('_')

      return hash if in_path?(method_name)

      unless respond_to?(method_name)
        method_name = key
        return hash unless respond_to?(method_name)
      end

      # throw away any values that are set to built matchers.
      current_resp = send(method_name)
      return hash if current_resp.class.name.start_with? 'RSpec::Matchers::BuiltIn::'

      hash.deep_merge(build_param_hash(keys, method_name))
    end
  end
end

This revealed that I had some messiness where I was sending something as the param and that I was defining let(:include) {...} and then trying to use the matcher later, which does not work.

jwg2s commented 6 years ago

I think I'm running into this with a parameter named :subject. Using let(:subject) { nil } doesn't seem to work either, and I'm getting a Segementation fault: 11. Anyone else run into this? Banging my head against the wall...

I actually defined let!(:subject) { nil } and got stack-level too deep. Might just be skipping this parameter...

oestrich commented 6 years ago

subject is a build in rspec function, so my guess is something deep in rspec isn't happy with a let for it.

@jwg2s Can you try:

parameter :subject, "Description", method: :custom_subject

let(:custom_subject) { "hello" }