I'm writing some specs that test the template files in a gem that has generators for Rails. I'd love to access to "admin_layout.html.erb" in the rspec spec below:
require 'spec_helper'
describe "admin_layout.html.erb" do
it "has page title Admin" do
HERES WHERE I WOULD LOVE TO HAVE ACCESS TO "admin_layout.html.erb" AS A VARIABLE
end
end
You can use self.class.description to get this info:
it "has page title Admin" do
layout = self.class.description
# => "admin_layout.html.erb"
end
However, keep in mind this will only put out the first parent's description. So if you have contexts in your describe block, then the examples within the contexts would give the context name for self.class instead of the describe block's name. In that case, you could use metadata:
describe "admin_layout.html.erb", :layout => "admin_layout.html.erb"
context "foo" do
it "has page title Admin" do
layout = example.metadata[:layout]
end
end
end
In case you want the top-level description, you can use self.class.top_level_description:
RSpec.describe "Foo", type: :model do
context "bar" do
it "is part of Foo" do
self.class.top_level_description
# => "Foo"
end
end
end
Related
I am using shared contexts to DRY my spec files.
However, I have one single context block where I would like to disable the shared context. Is this possible?
describe MyClass do
include_context 'my shared context'
describe '#some_method' do
# Specs using the shared context...
context 'with some special context' do
# Turn off 'my shared context' here
# ...
end
end
end
I think by slightly modifying how you include the context and using RSpec metadata, you should be able to get this working.
RSpec.shared_context "my shared context" do
# code
end
# spec/support/shared_context_load.rb
RSpec.configure do |config|
config.before do |example|
unless example.metadata[:load_shared_context] == false
config.include_context "my shared context"
end
end
end
describe MyClass do
# NOTE the shared_contxet is removed from here
describe '#some_method' do
# Specs using the shared context...
it "this spec using shared context"
# code
end
context 'with some special context' do
it "this spec is not using shared context", load_shared_context: false do
# Turn off 'my shared context' here
# ...
end
end
end
end
In RSpec, I am trying to convert the following view stub in my Rails view spec:
view.stub(:current_page?).with(root_url).and_return(true)
To use the new allow/expect syntax but the following does not work:
allow(view).to receive(:current_page?).with(root_url).and_return(true)
However, this gives me a NoMethodError:
NoMethodError:
undefined method `allow' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_1::Nested_2:0x007fc7ca971988>
The RDocs indicate that allow should accept a double or a real object. Is this a bug or am I doing something wrong? Thanks very much!
Here is the source code of the spec:
require "spec_helper"
describe 'Navigation Bar' do
# This needs to be kept synced up with the links in the navigation bar
KNOWN_LINKS = [:deal_gallery, :list, :login, :logout, :edit_account, :signup,
:categories]
shared_examples "Navigation Bar Link Context" do |params|
expected_links = params[:expected_links]
context 'Outside Deal Gallery' do
before(:each) { render partial: "layouts/navigation", formats: [:html] }
it_has_only_links_with_ids
it_has_only_known_links KNOWN_LINKS
it_has_links expected_links
it_does_not_have_links KNOWN_LINKS - expected_links
end
context 'On Deal Gallery' do
before(:each) do
# view.stub(:current_page?).with(root_url).and_return(true)
allow(view).to receive(:current_page?).with(root_url).and_return(true)
render partial: "layouts/navigation", formats: [:html]
end
it_has_only_links_with_ids
it_has_only_known_links KNOWN_LINKS
it_has_link :categories
it_does_not_have_link :deal_gallery
end
end
context 'For Anonymous User' do
it_behaves_like "Navigation Bar Link Context",
expected_links: [:deal_gallery, :login, :signup]
end
context 'For Authenticated User' do
login_user
it_behaves_like "Navigation Bar Link Context",
expected_links: [:deal_gallery, :list, :logout, :edit_account]
end
end
I want to reuse this shared_examples block across different spec files. I want to extract it into a separate file, and pass in the object so it's not always user. Both things I tried failed, is it possible?
describe User do
before { #user = build_stubbed(:user) }
subject { #user }
shared_examples 'a required value' do |key| # trivial example, I know
it "can't be nil" do
#user.send("#{key}=", nil)
#user.should_not be_valid
end
end
describe 'name'
it_behaves_like 'a required value', :name
end
end
Just require the other file. shared_examples work at the top level, so once defined they are always available; so be careful of naming conflicts.
A lot of RSpec users will put the shared example in spec/support/shared_examples/FILENAME.rb. Then in spec/spec_helper.rb have:
Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
Or on Rails projects
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
That is listed in the 'CONVENTIONS' section of the shared example docs.
I am running rspec tests on a catalog object from within a Ruby app, using Rspec::Core::Runner::run:
File.open('/tmp/catalog', 'w') do |out|
YAML.dump(catalog, out)
end
...
unless RSpec::Core::Runner::run(spec_dirs, $stderr, out) == 0
raise Puppet::Error, "Unit tests failed:\n#{out.string}"
end
(The full code can be found at https://github.com/camptocamp/puppet-spec/blob/master/lib/puppet/indirector/catalog/rest_spec.rb)
In order to pass the object I want to test, I dump it as YAML to a file (currently /tmp/catalog) and load it as subject in my tests:
describe 'notrun' do
subject { YAML.load_file('/tmp/catalog') }
it { should contain_package('ppet') }
end
Is there a way I could pass the catalog object as subject to my tests without dumping it to a file?
I am not very clear as to what exactly you are trying to achieve but from my understanding I feel that using a before(:each) hook might be of use to you. You can define variables in this block that are available to all the stories in that scope.
Here is an example:
require "rspec/expectations"
class Thing
def widgets
#widgets ||= []
end
end
describe Thing do
before(:each) do
#thing = Thing.new
end
describe "initialized in before(:each)" do
it "has 0 widgets" do
# #thing is available here
#thing.should have(0).widgets
end
it "can get accept new widgets" do
#thing.widgets << Object.new
end
it "does not share state across examples" do
#thing.should have(0).widgets
end
end
end
You can find more details at:
https://www.relishapp.com/rspec/rspec-core/v/2-2/docs/hooks/before-and-after-hooks#define-before(:each)-block
I'm trying to define a few let's and before hooks that will run globally for all my specs by including them in a separate file using the Rspec configuration block.
I tried something like:
module Helpers
def self.included(base)
base.let(:x){ "x" }
base.before(:all){ puts "x: #{x}" }
end
end
Rspec.configure{|c| c.include Helpers }
but this doesn't work as expected. The before(:all) doesn't just run before each main example group, but each nested one as well.
Then I found out about shared_context and it appears to be exactly what I want.
My open problem however is that I can't figure out how to share a context amongst ALL of my specs. The docs only reference include_context within a specific spec.
Can anyone tell me how I can achieve this behavior in a global manner? I'm aware that I can define global before hooks in my spec_helper but I can't seem to use let. I'd like a single place that I can define both of these things and not pollute my spec helper, but just include it instead.
I tried to reproduce your error, but failed.
# spec_helper.rb
require 'support/global_helpers'
RSpec.configure do |config|
config.include MyApp::GlobalHelpers
end
# support/global_helpers.rb
module MyApp
module GlobalHelpers
def self.included(base)
base.let(:beer) { :good }
base.before(:all) { #bottles = 10 }
end
end
end
# beer_spec.rb
require 'spec_helper'
describe "Brewery" do
it "makes good stuff" do
beer.should be :good
end
it "makes not too much bottles" do
#bottles.should == 10
end
context "when tasting beer" do
before(:all) do
#bottles -= 1
end
it "still produces good stuff" do
beer.should be :good
end
it "spends some beer on degusting" do
#bottles.should == 9
end
end
end
https://gist.github.com/2283634
When I wrote something like base.before(:all) { p 'global before'; #bottles = 10 }, I got exactly one line in spec output.
Notice that I didn't try to modify instance variables inside an example, because it wouldn't work anyway (well, actually you can modify instance variables, if it's a hash or array). Moreover, even if you change before(:all) in nested example group to before(:each), there will be still 9 bottles in each example.