Rspec include_examples working but it_behaves_like not (with tags) - ruby

I have a set of shared examples like this:
shared_examples_for 'a shared behavior' do
it 'should pass number 1', :tag1 do
expect(1).to eq(1)
end
it 'should pass number 2', :tag1 do
expect(2).to eq(2)
end
end
In another file, I import this file and have:
describe 'my test' do
include_examples 'a shared behavior'
end
and when I run
rspec --tag tag1
My tests from my shared example run fine.
However if I simply change my 'include_examples' to 'it_behaves_like', rspec ignores those tests completely.
My hunch is that it has something to do with the tagging, but I cannot figure out why.

I may be wrong here, but I think you need to put your it_behaves_like inside contexts.

Related

How to fetch RSpec test name in before(:each) block without a spec_helper

So here's an example basic test suite:
describe "Main test suite" do
it "should run test #1" do
...
end
it "should run test #2" do
...
end
end
I want to add a before(:each) which does some special logic with the full test name (it'll be inserting the test name as a metadata header into all of the HTTP requests made by each test). I've found that using "#{self.class.description}" only captures the test suite name ("Main test suite" in this case), but I also need to capture the test name itself.
I've seen some other similar questions on StackOverflow such as Getting the full RSpec test name from within a before(:each) block, but the answers all involve adding Spec::Runner.configure or RSpec.configure options to the spec_helper.rb, but we're running these tests through a custom environment which doesn't use a spec_helper.rb, so I need a solution that doesn't depend on that.
I've also seen other examples such as How to get current context name of rspec where they are doing the logging in the test itself instead of in a before(:each) block, so they can just do something like: it "should Bar" do |example| puts "#{self.class.description} #{example.description}" end. But we have hundreds of these tests and I don't want to copy-paste the same logic in every test -- this seems like an ideal use case for a before(:each) block.
describe "Main test suite" do
before(:each) do |x|
puts "#{x.class.description} - #{x.example.description}"
end
it "should run test #1" do
...
end
it "should run test #2" do
...
end
end
I got it working by putting this at the top of my file:
RSpec.configure do |config|
config.before(:each) do |x|
do_stuff("#{x.class.description} - #{x.example.description}")
end
end

Tests, using Aruba with Rspec, failing with `run` is not available from within an example (e.g. an `it` block)

I need to test a console application and check printed output, using rspec script. Example:
RSpec.describe 'Test Suite', type: :aruba do
it "has aruba set up" do
command = run("echo 'hello world'")
stop_all_commands
expect(command.output).to eq("hello world\n")
end
It fails with:
Failure/Error: command = run("echo 'hello world'")
`run` is not available from within an example (e.g. an `it` block) or from constructs that run in the scope of an example (e.g. `before`, `let`, etc). It is only available on an example group (e.g. a `describe` or `context` block).
Aruba version 0.14.6, Rspec 3.7.0. Will appreciate any help. Thanks.
As the error implies, you cannot call run within the it block. Aruba's documentation can get a bit confusing here because of the various branches, but the run method is still available in the still branch, with documentation found here.
Following the documentation, instead of defining command within the it block, we can instead define it outside the block using let:
RSpec.describe 'Test Suite', type: :aruba do
context "aruba test" do
let(:command) { run("echo 'hello world'") }
it "has aruba set up" do
stop_all_commands
expect(command.output).to eq("hello world\n")
end
end
end

Show the complete description of an example

In RSpec, how can we generate a string from an example, representing the current meta description of the current example?
Example:
RSpec.describe Api::V1::Public::Signin::ByEmailController, type: :controller do
describe 'POST #create' do
context 'when the provider is "email"' do
context 'when there is a saved email' do
context 'when the password is good' do
it 'signs in' do
expect(current_metadata_description).to eq 'Api::V1::Public::Signin::ByEmailController POST #create when the provider is "email" when there is a saved email when the password is good signs in'
end
end
end
end
end
end
As we can see, the current meta description of the given example is:
Api::V1::Public::Signin::ByEmailController POST #create when the provider is "email" when there is a saved email when the password is good signs in
Thanks.
Edit:
The current_metadata_description is not provided by RSpec. I just invented it to give an example of what I would like to have.
While I am unsure what your overall intentions are for doing this.
Rspec::Core::ExampleGroup.it yields a RSpec::Core::Example to the block. As with all yielding methods one can capture the yielded Object in a block local variable. RSpec::Core::Example has a full_description method which appears to be what you are looking for. RSpec Source.
For Example (no pun intended):
describe String do
context 'Down' do
context 'Deeper' do
it 'can describe itself' do |ex|
# ex is the specific RSpec::Core::Example for this it block
expect(ex.full_description).to eq('String Down Deeper can describe itself')
end
end
end
end
running this will return
.
Finished in 0.003 seconds (files took 0.21998 seconds to load)
1 example, 0 failures
It is imperative that you capture the yielded value if you want the desired output as the block itself is executed in the context of an instance of RSpec::Core::ExampleGroup so calling self.class.metadata[:full_description] will contain the description of the RSpec::Core::ExampleGroup but not the RSpec::Core::Example itself (e.g. "String Down Deeper")
As described in the docs if this is for logging purposes (or something similar where you would like this information for each example) you can access the RSpec::Core::Example in Hooks excerpt:
# Useful for configuring logging and/or taking some action based
# on the state of an example's metadata.
#
# RSpec.configure do |config|
# config.before do |example|
# log example.description
# end
#
# config.after do |example|
# log example.description
# end
#
# config.around do |example|
# log example.description
# example.run
# end
# end
If you really wanted to patch this in (and I am not endorsing it) You could do the following
class RSpec::Core::ExampleGroup
def instance_exec(*args,&blk)
if args.first.is_a?(RSpec::Core::Example)
self.define_singleton_method(:current_metadata_description) do
args.first.full_description
end
end
super(*args,&blk)
end
end
Then your test would be exactly as you stated.
Try to run rspec with --format option:
bundle exec rspec --format documentation
Update:
I don't know any rspec method that would do that for you. One way I can think of is, write the spec description to a file while running the tests and then read the description from it in your custom current_metadata_description method. Here is a tutorial on Generating documentation from specs. Hope that helps!

rspec setup method in separate file

I am trying to create a setup file for rspec so that my '_spec.rb' test only have 'it' blocks like so:
setup.rb
require 'rspec'
module Setup
describe "setup" do
before(:each) do
#foo = 'hello'
'do something'
end
after(:each) do
'do something'
end
end
spec/test_spec.rb
require_relative '../setup.rb'
include Setup
it "test_sample" do
puts #foo
'do test'
end
This returns undefined variable. Can someone shine light onto my issue? I have multiple tests that I want to share the same setup for, and I don't want to repeat the setup for each test.
Use rspec's configure method for this:
# in spec_helper.rb (or setup.rb)
RSpec.configure do |config|
config.before(:each) do
...
end
config.after(:each) do
...
end
end
See here for more info on setting the configuration.

File.read empty for a non empty file when testing with rspec

New to rubby and rspec i am trying to test a class that opens and write to a file.
The class name is SimpleLogger
Here is the spec that generates an error:
describe SimpleLogger do
...
context 'when using a file' do
require 'fakefs/spec_helpers'
before(:all) do
#path = 'my_file'
logger = SimpleLogger.new #path
logger.write "Hello, world!"
logger.close
end
...
it 'we expect the file to have a valid content' do
expect(File.read(#path)).to eq "Hello, world!\n"
end
end
end
The error generated is:
Failure/Error: expect(File.read(#path)).to eq "Hello, world!\n"
expected: "Hello, world!\n"
got: ""
(compared using ==)
Diff:
## -1,2 +1 ##
-Hello, world!
The file exists on my file system, and when I'm testing a simple puts Find.read("my_file") on an independant ruby file i've got the expected result.
I've tested and have the same issue without the fakefs gem
Why is it when run in a spec it doesn't work?
And beside that i fail to understand the advantage of fakefs, as it creates the file juste the same. So why fakefs is used?
And as it creates the file should i erase it within the spec?
Thanks in advance ;)
From the documentation - it seems that you need to include the helpers to activate the FakeFS:
FakeFS::SpecHelpers provides a simple macro for RSpec example groups to turn FakeFS on and off.
To use it simply require 'fakefs/spec_helpers', then include FakeFS::SpecHelpers into any
example groups that you wish to use FakeFS in. For example:
require 'fakefs/spec_helpers'
describe "Some specs that deal with files" do
include FakeFS::SpecHelpers
...
end
By default, including FakeFS::SpecHelpers will run for each example inside a describe block.
If you want to turn on FakeFS one time only for all your examples, you will need to
include FakeFS::SpecHelpers::All.
Alternatively, you can include FakeFS::SpecHelpers in all your example groups using RSpec's
configuration block in your spec helper:
require 'fakefs/spec_helpers'
Spec::Runner.configure do |config|
config.include FakeFS::SpecHelpers
end
If you do the above then use_fakefs will be available in all of your example groups.
You will also need to use before(:each) instead of before(:all) - like many unit test helpers, FakeFS adheres to unit-test isolation principles, in which side-effects of one test should not affect another's. That is why after every test, the gem 'resets' the state of its container, and clears all files from it.

Resources