Giter Club home page Giter Club logo

rspec_rabl's Introduction

Build Status Code Climate Dependency Status

⚠️ No Longer Supported

I haven't needed to use this library in a long time and I'm no longer maintaining it to keep it up-to-date with the ruby community. I'm keeping it here as an archive for future reference.

RspecRabl

A collection of convenient helpers for writing view specs with rabl templates.

Update Notes

If you were previously using the rspec_rabl gem please note that you will need to fix a few things in order to upgrade to the latest version:

  • change your Gemfile to require rspec-rabl (a hyphen instead of an underscore see #8 for more details)
  • in spec_helper.rb you need to require rspec/rabl instead of rspec_rabl
  • if you are using rails and you want the default configuration you will need to require rspec/rabl/rails instead of rspec/rails_rabl

Usage

First make sure you configure rspec-rabl in your spec_helper.rb file (see Configuration below).

Now your templates can be rendered with whatever data you like for testing:

describe "budgets/show/rabl" do                            # this tells us what template you want to test
  let(:budget) { Budget.new }
  rabl_data(:root => 'budget') { budget }                  # this tells us what data to use when rendering and what structure you expect the template to have (use root and object_root just like rabl)

  it "renders valid json" do
    expect {
      JSON.parse(rendered_template)                        # rendered_template is the rendered string
    }.not_to raise_error
  end

  it "renders the data in some specific way" do
    expect(parsed_json['budget']['date']).to eq("1984")    # parsed_json is the parsed out version of the rendered string
  end
end

But most of the time you want to check some pretty common things like:

describe "budgets/show.rabl" do
  let(:budget) { Budget.new }
  rabl_data(:root => 'budget') { budget }

  it { expect(subject).to render_attribute(:amount) }                        # parsed_json['budget']['amount'] == budget.amount
  it { expect(subject).to render_attribute(:amount).with(:friendly_amount) } # parsed_json['budget']['amount'] == budget.friendly_amount
  it { expect(subject).to render_attribute(:amount).with_value("45.00") }    # parsed_json['budget']['amount'] == "45.00"
end

describe "budgets/index.rabl" do
  let(:budgets) { [ Budget.new ] }
  rabl_data(:root => 'budgets', :object_root => 'budget') { budgets }

  it { expect(subject).to render_attribute(:amount) }                       # parsed_json['budgets'].first['budget']['amount'] == budgets.first.amount
end

If you don't want to specify the template you are testing via the describe/context string you can specify the template like this:

describe "Users are rendered with the humorous attribute" do
  rabl_template { "users/show.rabl" }
  rabl_data(:root => 'user') { user }

  specify { expect(subject).to render_attribute(:humorous).with_value("not really") }
end

Configuration

The easiest way to configure this is simple

require 'rspec/rabl/rails'

For more detailed configuration just look at that file to see what configurations it is making.

Additionally, there are two config attributes which can be specified using rabl_config:

scope is the rendering context which is passed to create the underlying Rabl::Renderer instance for an example group. If your rabl template is using, for example, view helpers in Rails but your spec is raising a NoMethodError, then you probably want to pass in a scope which includes that helper.

describe "Users which use a Helper to transform data for presentation" do
  class ScopeWithUsersHelper
    include Singleton
    include UsersHelper # could have a method which formats an email address for use below
  end

  rabl_config(:scope => ScopeWithUsersHelper.instance)
  rabl_template { "users/show.rabl" }
  rabl_data(:root => 'user') { user }

  specify { expect(subject).to render_attribute(:formatted_email).with_value('"Kung Fury" <[email protected]>') }
end

view_paths instructs the Rabl::Renderer where to look for its rabl templates for the purpose of an example group.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

rspec_rabl's People

Contributors

film42 avatar mikejarema avatar mmmries avatar ryanjonesmx avatar

Stargazers

 avatar

Watchers

 avatar  avatar

rspec_rabl's Issues

Support for shared examples

Currently, I don't believe RSpec RABL supports shared examples (or, at least I don't know how to use it with shared examples):

166) Accounts Views v1/accounts/account.rabl behaves like an account view
   Failure/Error: it { should render_attribute(:feed_last_payment_at).with_value(account.feed_last_payment_at.to_s) }
   RuntimeError:
     Cannot find rabl template 'behaves like an account view' within registered (["app/views"]) view paths!
   Shared Example Group: "an account view" called from ./spec/views/v1/account_views_spec.rb:189
   # ./spec/views/v1/account_views_spec.rb:148:in `block (3 levels) in <top (required)>'

Is there a way to manually specify the template that should be used for a spec?

README.md update

The README is just the stock bundler gem README right now. It should be updated to include some information about how to configure the gem in a spec_helper.rb file, how to access the rendered template and parsed template and how to use the custom matchers.

default :root and/or default :object_root for specs

By default rabl will set a root key for collections. But rspec_rabl currently assumes that no root key will be used unless one is specified via:

rabl_data(:root => 'alerts') { [data] }

Some defaults should be added to make an attempt to correctly guess what the default root node should be.

error messages

Right now if you specify root and/or object_root incorrectly you will get bad errors like:

NoMethodError has_key? on nil:NilClass

or

can't convert String into Integer

As we reference through the parsed data we should check that the structure looks right and give better feedback.

RSpec 3 compatibility

It appears that RSpec is changing the way example groups work in RSpec 3, which will break Rspec::Rabl:

RSpec::Core::ExampleGroup#example is deprecated and will be removed
in RSpec 3. There are a few options for what you can use instead:

  - rspec-core's DSL methods (`it`, `before`, `after`, `let`, `subject`, etc)
    now yield the example as a block argument, and that is the recommended
    way to access the current example from those contexts.
  - The current example is now exposed via `RSpec.current_example`,
    which is accessible from any context.
  - If you can't update the code at this call site (e.g. because it is in
    an extension gem), you can use this snippet to continue making this
    method available in RSpec 2.99 and RSpec 3:

      RSpec.configure do |c|
        c.expose_current_running_example_as :example
      end

(Called from /Users/ah/.rvm/gems/ruby-2.1.2@alfred/gems/rspec_rabl-0.0.3/lib/rspec/rabl/example_group.rb:38:in `_rabl_template')

Railtie to automatically setup some common defaults

There are a few defaults that will probably always be adheared to for rails applications using this gem.

RSpec.configure do |config|
  config.include ::RSpec::Rabl::Matchers, :example_group => ->(group,metadata){ group[:file_path].start_with?("./spec/views") }
  config.include ::RSpec::Rabl::ExampleGroup, :example_group => ->(group,metadata){ group[:file_path].start_with?("./spec/views") }
  config.rabl_configuration = {:view_paths => ['app/views']}
end

include RSpec::Rabl::Helpers

It would be very convenient to have a railtie which automatically loaded these defaults for rails applications.

RSpec 3 compatibility

Specs fail spectacularly under RSpec 3. I'm guessing we're using a deprecated API:

Failure/Error: it { should render_attribute(:amount) }
NoMethodError:
  undefined method `object' for "v1/budgets/budget.rabl":String
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec_rabl-0.0.4/lib/rspec/rabl/attribute_matcher.rb:48:in `rendered_object'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec_rabl-0.0.4/lib/rspec/rabl/attribute_matcher.rb:64:in `collection?'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec_rabl-0.0.4/lib/rspec/rabl/attribute_matcher.rb:68:in `parsed_object'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec_rabl-0.0.4/lib/rspec/rabl/attribute_matcher.rb:52:in `attribute_rendered?'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec_rabl-0.0.4/lib/rspec/rabl/attribute_matcher.rb:19:in `matches?'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-expectations-3.0.4/lib/rspec/expectations/handler.rb:48:in `handle_matcher'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/memoized_helpers.rb:81:in `should'
# ./spec/views/v1/budget_views_spec.rb:24:in `block (3 levels) in <top (required)>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:148:in `instance_exec'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:148:in `block in run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `call'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `block (2 levels) in <class:Procsy>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-rails-3.0.2/lib/rspec/rails/adapters.rb:72:in `block (2 levels) in <module:MinitestLifecycleAdapter>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:294:in `instance_exec'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:294:in `instance_exec'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:430:in `block (2 levels) in run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `call'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `block (2 levels) in <class:Procsy>'
# ./spec/spec_helper.rb:60:in `block (2 levels) in <top (required)>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:294:in `instance_exec'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:294:in `instance_exec'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:430:in `block (2 levels) in run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `call'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:210:in `block (2 levels) in <class:Procsy>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:432:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/hooks.rb:485:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:303:in `with_around_example_hooks'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example.rb:145:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:494:in `block in run_examples'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:490:in `map'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:490:in `run_examples'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:457:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:458:in `block in run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:458:in `map'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/example_group.rb:458:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:112:in `block (2 levels) in run_specs'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:112:in `map'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:112:in `block in run_specs'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/reporter.rb:54:in `report'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:108:in `run_specs'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:86:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:70:in `run'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/lib/rspec/core/runner.rb:38:in `invoke'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/gems/rspec-core-3.0.4/exe/rspec:4:in `<top (required)>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/bin/rspec:23:in `load'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/bin/rspec:23:in `<main>'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/bin/ruby_executable_hooks:15:in `eval'
# /Users/ah/.rvm/gems/ruby-2.2.0@alfred/bin/ruby_executable_hooks:15:in `<main>'

Probably should get this figured out soon.

Use a better mechanism for conditionals includes

There was a Rails 4 project that wasn't loading the RSpec::Rabl::ExampleGroup correctly. Apparently RSpec 3 prefers a new syntax.

config.include ::RSpec::Rabl::Matchers, :file_path => %r(spec/views)
config.include ::RSpec::Rabl::ExampleGroup, :file_path => %r(spec/views)

Will changing this break RSpec 2.X use cases? Was this specific to a single Rails instance or does the current mechanism break for all Rails 4 + RSpec 3 cases?

Better failure reporting

Currently, render_attribute prints the entire rendered object when an expectation is not met:

Failure/Error: it { should render_attribute(:last_payment_at_set_by_name) }
       expected {"accounts"=>[
         {
           "account_subtype_name"=>"IRA", 
           "account_subtype_set_by_name"=>"FEED", 
           "account_type_name"=>"INVESTMENT",
           "account_type_set_by_name"=>"SYSTEM",
           "apr_set_by_name"=>"FEED",
           "apy_set_by_name"=>"FEED",
           "available_balance_set_by_name"=>"FEED",
           // ...
         }
      ]} to render last_payment_at_set_by_name = FEED

It would be very helpful if it instead showed the rendered value along with the expected value.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.