Rails Fixtures / Uncountable model name results in NoMethodError - ruby-on-rails

I have a model named EventSeries, which is the same singular as it is plural. I have added this in every way I can imagine to the inflector:
inflect.uncountable %w( fish sheep EventSeries event_series Series series )
I have an event_series.yml fixtures file within spec/fixtures. I have even tried adding:
_fixture:
model_class: EventSeries
at the top of the yml file, but it does not help.
I have also tried changing change the filename to event_serieses.yml and call event_serieses(:d30_short_series), and I get NoMethodError undefined method event_serieses.
I use RSpec for testing. In a system spec, I have the following declaration:
let(:subject_series) { event_series(:d30_short_series) }
When I run the spec, I get this error:
NoMethodError: undefined method `event_series' for <RSpec::MySpecFile>
I have many other models and this pattern works for every other model (using the plural version, like users or events), so I assume this is a pluralization issue. I've searched for answers and found this issue, which indicates the problem can be solved by adding the model name to the inflector, but that has not helped in my case.
I've managed to get all the other inherent problems with uncountable names working; for example, my path helpers are all working properly and Rails find my view files as expected. But I haven't been able to solve this fixture problem.
Is there a way to point RSpec to the correct method to access my fixtures?
Using Rails 5.2, Ruby 2.6.0, and RSpec 3.8.

Thanks for sharing your open source project, it was simpler to investigate and solve the issue.
The problem with this specific spec is that the needed fixtures were not being loaded.
You have two options to solve this problem.
Option 1: Add :event_series to config.global_fixtures in your rails_helper.rb.
RSpec.configure do |config|
config.global_fixtures = :a, :event_series, ..., :n
Option 2: Load the fixture just on that spec visit_event_series_spec.rb
RSpec.describe 'visit an event series page' do
fixtures :event_series
let(:user) { users(:third_user) }
Then the spec will now fail but for different reasons:
Failures:
1) visit an event series page when the user is a visitor when all categories are populated Visit the page
Failure/Error: expect(page).to have_link(resource.send(attr), href: path)
expected to find visible link "Dirty 30 Running" but there were no matches. Also found "Dirty 30 Running", which matched the selector but not all filters.
Which I believe you have a better understanding than me of why the following event link is not being displayed on the page.

Related

Rspec controller spec on namespaced controller finds the global controller with same name

I have a weird issue when creating a controller spec for a namespaced controller when there also is a global controller with the same name.
The controller names are HomeController and Backend::HomeController.
Note that I have not yet created the file app/controllers/backend/home_controller.rb, only the global controller exists app/controllers/home_controller.rb
Therefore I expect the test to explode with errors, but it does not. It passes, all green and happy.
My spec looks like this
#spec/controllers/backend/home_controller_spec.rb
require 'rails_helper'
RSpec.describe Backend::HomeController, type: :controller do
before do
user = FactoryGirl.create(:user)
allow(controller).to receive(:authenticate_user!).and_return(true)
allow(controller).to receive(:current_user).and_return(user)
end
describe "GET #index" do
it "returns http success" do
get :index
expect(response).to have_http_status(:success)
end
end
end
However if I change the name in my global HomeController to something else, e.g NotMyHomeController the test fails with errors saying
Unable to autoload constant HomeController, expected app/controllers/home_controller.rb to define it
Which makes me suspect that Rspec doesn't bother with the "Backend" part in the Rspec.describe function.
Am I doing something wrong or am I missing some other vital part? IMHO, this spec shouldn't pass (to paraphrase Gandalf).
I'm using Rails 4.2.6, Rspec-Rails 3.4.2
Update
As Max pointed out, this is probably not at Rspec issue but instead something with Rails autoloading.
However i tried just typing
Backend::HomeController
In the Rails console, but there I get the expected error
NameError: uninitialized constant Backend::HomeController
And according to the Rails guide, both the console and the test suite autoloads. However I think I'm on the right track here.
I had this same problem before - you can read about the whole issue here:
Object.const_get and Rails - cutting off parent module names
but the meat of the answer comes from this answer from user Apneadiving:
Be aware that there are vicious cases in Rails development mode. In order to gain speed, the strict minimum is loaded. Then Rails looks for classes definitions when needed.
But this sometimes fails big time example, when you have say ::User already loaded, and then look for ::Admin::User. Rails would not look for it, it will think ::User does the trick.
This can be solved using require_dependency statements in your code.

Testing searchkick with RSpec

I would like to create feature specs for searching Patients in my Practice Management app.
So far, I have searched the net and have followed suggested solutions from:
http://bitsandbit.es/post/11295134047/unit-testing-with-tire-and-elastic-search#disqus_thread
and
https://github.com/karmi/tire/wiki/Integration-Testing-Rails-Models-with-Tire
Both of these articles suggested configurations to spec_helper.rb for ElasticSearch and Tire. Since Searchkick was based on Tire, I applied the solutions to the class Patient, which is the only model I am using Searchkick on.
However, I get a 'NoMEthodError' for each of the configurations.
For example, using the following code:
spec_helper.rb
RSpec.configure do |config| do
.
.
.
config.before :each do
Patient.index.delete
Patient.create_elasticsearch_index
end
config.before :all do
Patient.index_name('test' + Patient.model_name.plural)
end
end
I get the following error:
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `index_name'
The same happens to the methods 'index' and 'create_elasticsearch_index'
I am fairly new to RoR and am honestly not sure what I could be doing wrong here, except maybe for assuming I could use Tire solutions on Searchkick. So any help is very much appreciated!
Searchkick needs better testing documentation, but here's the gist of it:
Searchkick automatically uses a different index name in each environment, so no need to do any set up. Run Patient.searchkick_index.name in the console to confirm this.
Instead of deleting and recreating the index, you can just call reindex.
RSpec.configure do |config| do
config.before :each do
Patient.reindex
end
end
Finally, after inserting data, call Patient.searchkick_index.refresh before calling Patient.search. This tells Elasticsearch to update the index immediately (rather than after the refresh interval, which defaults to 1 second).
Even if Searchkick was based on Tire, that doesn't mean that the Tire methods are available on your models. See https://github.com/ankane/searchkick for documentation on what methods are available. See the subsection https://github.com/ankane/searchkick#migrating-from-tire in particular for a contrast between using Searchkick and using Tire.

Capybara features outside of /features directory

I have some large end-to-end integration tests that for CI purposes I don't want in my spec/features folder in Capybara. Instead I have them in a spec/integration folder. Knowing that Capybara loads differently based on the folder, I put the :type=>:feature option on my describe, like so:
describe 'Recurring Contract Orders', :type=>:feature, :js=>true, :focus=>true do
it "satisifies the use case" do
....
But no luck, I am still getting the:
NameError:
undefined local variable or method `page' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fd396bd2998>
error when I run the test. Is there something else I'm missing?
I don't know if it's something you are still trying to solve, but I was having the same problem. You are able to use the specific Capybara commands if you just include the DSL:
include Capybara::DSL
I haven't found out how to just have Capybara include my /integration folder yet, but this has worked for now.
For future ref, I think the right thing (according to https://github.com/jnicklas/capybara) is to tag the specs with :type => :feature, e.g.
describe "Some pages", :type => :feature do
specify "some behaviour"
end

Understanding RSpec testing

I've been searching around for a while, and did not find a clear explanation about testing structure in RoR. (I'm learning with Michael Hartl's book).
Since I'm using rspec for testing, do I need to keep the "test" folder anymore ?
Is the "spec" folder structure strictly assigned to specific test purposes ?
When "generating" a test script, does it do something else than creating the script file ? (i.e. could I create it by hand ?)
The 2nd question comes from this error:
undefined method `visit' for #<RSpec::Core::ExampleGroup: ...
which occurs as soon as my very simple test file is not in /spec/requests (but in /spec/views):
require 'spec_helper'
describe "Home page" do
subject { page }
###1
describe "title" do
before { visit root_path }
it { should have_selector('h1', text: 'Welcome') }
it { should have_selector('title', text: 'Home') }
end
end
1) No, you don't need the test folder. Only spec, unless you're using Test::Unit.
2) You can order spec however you want. The general suggested format is
spec/
controllers/
views/
models/
lib/ #Only if you have stuff in lib you need to test
spec_helper.rb
with names like spec/controllers/items_controller_spec.rb, and spec/models/item_spec.rb
3) I'm not sure what you mean. For RSpec, you just need to make a file that uses its syntax to test certain pieces of your Ruby code. It doesn't create a script -- you do.
For your last question about visit:
It seems like you're trying to use a Capybara method (visit). Capybara takes care of visiting your site in a browser, not RSpec.
No
See Below
No, only create the file
There is one specific folder structure you need to use in order to run Capybara acceptance tests. These are tests that have "visit" in them
Capybara 1.0
spec/requests
Capybara 2.0
spec/features
No, my understanding is that the test folder is generally used for Test::Unit stuff. You can delete or keep it; doesn't hurt to leave it.
There's a pretty specific way they want you to organize that stuff. If you have app/models/user.rb, for example, your spec should be in spec/models/user_spec.rb.
I don't know of anything else it does besides creating the test script. You can totally create those by hand, and I do all the time.

factory_girl + rspec doesn't seem to roll back changes after each example

Similar to the problem described here:
http://rpheath.com/posts/411-how-to-use-factory-girl-with-rspec
in Short (shorten'd code):
spec_helper:
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
factories.rb:
Factory.define :state do
f.name "NY"
end
in my spec
before(:each) do
#static_model = Factory(:state) # with validate uniqueness of state name
end
error:
duplicate entry name "NY" etc.
Question:
Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
Things i think off:
do you use rake spec to run your testsuite: that builds up the database from scratch (to make sure nothing is sticking)
do you use, anywhere, a before (:all) ? Because whatever you create inside a before :all should be deleted again in a after :all or it keeps on existing.
Question: Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
RSpec with DatabaseCleaner or RSpec Rails with use_transactional_fixtures will clear the DB as long as your created the data in the example itself. before :all do ... end is considered outside of the example, because the data remains untouched across multiple examples. Whatever you create in before :all you have to delete in after :all.
In order to delete whatever you create automatically use before :each do ... end. Be aware the same data will be created and removed 10 times if you have 10 examples. The difference between before :all and before :each is better explained here: rails rspec before all vs before each
Some more possible causes:
There's still a states.yml fixture sitting around
Someone played around on script/console test and forgot to clean up afterwards.
You might also find it's because you haven't wrapped the statement in:
describe "what it should do" do
#static_model = Factory(:state) # with validate uniqueness of state name
end
I discovered that was the change that solved this problem:
Why isn't factory_girl operating transactionally for me? - rows remain in database after tests
I have had similar questions about what sort of starting state one can expect when using FG and RSpec.
While I too wait for clarity, Database Cleaner could be a good fix: http://rubydoc.info/gems/database_cleaner/0.6.7/frames
hth -
Perry
When you use Factory(:state) wich is a shortcut to Factory.create(:state), factory_girl returns you a saved object.
Use Factory.build(:state) instead.
Dude maybe your yaml fixtures from regular unit tests get mixed into your rspec?

Resources