How do I reuse Rspec let expressions across spec files? - ruby-on-rails

I'd like to dry up some of my spec files that share some of the same let expressions by shoving them into a module (or by doing something else you might suggest). When I do that I'm getting an error when I run the spec:
undefined method `let' for SpecShared:Module (NoMethodError)
I'm requiring the module in rails_helper.rb
I'm requiring rails_helper.rb in my module
It seems like the module is either not requiring rails_helper.rb properly, or needs to require something else. What else/instead would I need to do to make this work?

You will want to create a shared context:
https://www.relishapp.com/rspec/rspec-core/v/3-5/docs/example-groups/shared-context

Related

How import a helper file that isn't a controller helper?

Suppose I have a random file in a rails app: myapp/app/random_folder/random_helper.rb.
How can I load / require this file in the rails console?
Example
I have the file myapp/spec/spec_helper.rb and I want to require/load those helpers in the rails console.
What I've tried
I tried
require 'spec_helper'
require_relative 'spec/spec_helper.rb'
require_relative 'spec/spec_helper'
require_relative 'spec_helper'
but none of these approaches work.
It was a bug between the keyboard and chair. This does work:
require_relative 'path/to/some_helper'
Read the error message carefully because after loading the helper, an error may be produced, which is very different to a failure to load the helper file at all.
In my case, I saw NoMethodError: undefined method 'configure' for RSpec:Module and mistook it for an inability to load the helper file, but it was in fact loading the helper file but an error resulted from something in the helper file.
I will not accept this answer because it may not be the best way to load a random helper file, but hopefully it may be useful to someone else.

Correct use of ActiveModel with spec_helper

A new project with the RSpec 3.2 and Rails 4.2.
As a good citizen I'm trying to do the "right" thing with the new RSpec (disable monkey patching, do not infer the type of examples etc).
The problem I have is that I want to test this little class:
# app/models/session.rb
class Session # NOTE: This is a simple transient class, almost plain Ruby class
include ActiveModel::Model
attr_accessor :email, :password
end
with something like:
# spec/models/session_spec.rb
require 'spec_helper'
RSpec.describe Session, type: :model do
it { should validate_presence_of :email }
it { should validate_presence_of :password }
end
Obviously, when I run the spec I'm getting the uninitialized constant Session (NameError) which makes sense as the 'spec_helper' does not do anything to load that particular class.
I could have user the rails_helper instead but that is simply too much for that little class since it has nothing to do with rails at all.
Willing to do "the right" I'm puzzled with the following questions
Does the Session spec even need to be marked with type: :model?
Should I modify the spec_helper to change the $LOAD_PATH?
If not, is there a way to autoload session.rb file but without loading up the whole Rails?
Should the transient Session class be under app/models? I treat it as a model, it's just not persistent.
The easiest thing to do is of course to just use rails_helper, but for what I need to do that is unnecessary and I'd love to keep the spec file fast.
The point of distinguishing between rails_helper and spec_helper is that you want just a minimal setup with spec_helper, so I would recommend against modifying $LOAD_PATH there. The only advantage you get is that specs run quicker if you run only specs that use only spec_helper, for example when you run just the single spec file with rspec spec/models/session_spec.rb. If you run the entire suite and require rails_helper in any spec, it will generally not run any faster.
Basically, you have two options:
If you don't bother about the single spec file running a bit slower than it could, and you don't want to require the Session model manually, I would say it's perfectly fine to use rails_helper for the sake of simplicity.
If you actually do care about the single spec file running a bit faster, you can require_relative '../app/models/session' manually at the top of the spec file. Autoloading is Rails magic, and you don't want Rails for speed reasons; therefore, you need to do it manually.
You don't need to mark the spec as type: :model unless you have specific spec helpers that are only included for type: :model and you intend to use them. However, it makes sense to mark them that way when you treat it like a regular model and use rails_helper.

Streamline Rspec Test of Rails Helper

I am currently testing a Rails(4.2) helper with Rspec(3) successfully. However, the test file setup is a bit cumbersome. How can I streamline the require and/or include lines?
# spec/helpers/nav_helper_spec.rb
require 'spec_helper'
require_relative '../../app/helpers/nav_helper' # this seems bulky
describe NavHelper do
include NavHelper # this seems repetitive
...
end
Thanks in advance!
If you have a "default" setup you probably have a rails_helper in addition to your spec_helper. If you don't mind loading all of the Rails directories in this one spec (a bit of a performance hit) you can require that instead of the spec_helper (cleaning up the requires). But there's nothing wrong with including only what you need, it will run faster.
Rspec will also mix in the helper for you if it knows the spec type. You can either include config.infer_spec_type_from_file_location! in your spec helper, or include the type in the describe declaration:
describe NavHelper, type: :helper do
Either way you'll be able to use something like expect(helper.method_name).to eq(result) without explicitly including the module.

rspec for helper class expects module even though there is no module

I added a helper class to my rails project, Foo, at app/helpers/foo.rb. It looks like this.
class Foo
#....stuff
end
I use it in some models, and everything works fine. However, in spec/helpers/foo_helper_spec.rb, I have
require 'spec_helper'
describe Foo do
end
This causes rspec to crash (not report any failed tests, but actually crash), saying
/actionpack-3.2.12/lib/abstract_controller/helpers.rb:153:in `include': wrong argument type Class (expected Module) (TypeError)
If i remove the describe line and just have the file empty, everything works, but I'd like to add some tests soon.
Anyone know how I can fix this?
Thanks.
rails follows the paradigm of convention over configuration. one of those conventions is, that you put modules into the helpers folder, because they get included into your controllers and views.
that's why rspec fails when it tries to include your module, which is actually a class.
if you need to have a real class in there, i think you should put it in a different directory to make it obvious, that this is not a usual rails helper!
for example, if you are implementing some kind of decorator for your views, put it in a decorators folder. if you are implementing some kind of adapter for your model, put it in the models folder or some model subfolder.

Adding rspec test for library module doesn't seem to pickup Expectations and Matchers

I'm adding more rspec testing to my app and would like to test a ScoringMethods module, which is in /lib/scoring_methods.rb. So I added a /spec/lib directory and added scoring_methods_spec.rb there. I required spec_helper and set up the describe block as so:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ScoringMethods do
describe "should have scorePublicContest method" do
methods = ScoringMethods.instance_methods
methods[0].should match(/scorePublicContest/)
end
end
Now methods[0] is a String and there is no problem matching the public method name with the regular expression. And the relative path to "spec_helper" is correct.
The problem is that the entire setup doesn't seem to use the rspec library.
Running the example yields:
./spec/lib/scoring_methods_spec.rb:7: undefined method `match' for Spec::Rails::Example::RailsExampleGroup::Subclass_1::Subclass_1:Class (NoMethodError)
...
The entire Expectation and Matcher support seems to be missing. To test my supposition, I changed a working helper spec by replacing "is_instance_of" to "is_foobar_of". That test simply fails and says "is_foobar_of" is not a method of the targeted object; that it, this entire Spec::Rails::Example... hierarchy isn't present.
I've tried using other matchers as well. I've tried "be_instance_of" and some others. It seems that I'm not including the rspec library properly.
Finally, ScoringMethods is a module, just the same way Helpers are modules. So I thought that it would be possible to test a module (as opposed to classes, such as Controllers and Models).
I'd greatly appreciate your thoughts on what I've done wrong. Perhaps there is a more effective way of testing library modules? Thanks!
You should include your test block in an "it" block. For example:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ScoringMethods do
describe "should have scorePublicContest method" do
it "should have a scorePublicContest method" do
methods = ScoringMethods.instance_methods
methods[0].should match(/scorePublicContest/)
end
end
end
You will find that the methods names returned aren't guaranteed to be in the order they exist in the file.
A model we often use when testing Modules is to include the module in either a class created for the test (inside the spec file) or included inside the spec itself.

Resources