RSpec fails for no obvious reason - ruby-on-rails

So I'm using rspec to test my code as I'm going through the Rails Tutorial, and I keep getting this error when I test the code in listing 3.20. Everything checks out when I look at it with my eyeball, but RSpec doesn't seem to like it.
(Note that I just did one of the pages, not all three because they all give the same error)
james#tristan:~/rails_projects/sample_app$
rspec
spec/controllers/pages_controller_spec.rb
F...
Failures:
1) PagesController should have the
right title
Failure/Error: response.should have_selector("title",
expected following output to contain a | Home tag:
# ./spec/controllers/pages_controller_spec.rb:13:in
`block (2 levels) in '
Finished in 0.97999 seconds 4
examples, 1 failure
james#tristan:~/rails_projects/sample_app$

At the top of that spec file it says:
before(:each) do
#
# Define #base_title here.
#
end
Does your spec assign a value to #base_title?

Related

Wrong translation path in rspec view tests

Hey guys I am running into a bit of trouble with a simple view test written using Rspec. The case is pretty simple. I want to render a page that should display a message asking the customer if he/she is new.
The page contains several subsections that contain translations. The problem is that Rspec puts a "test" in this translation path, so the correct translation is not found.
Rspec test:
require "rails_helper"
RSpec.describe 'checkout/start/index' do
context "with no logged in customer" do
it "should render the #index page and display the registration and login form" do
render
expect(rendered).to match(/Sie sind neu bei uns?/)
end
end
end
Response:
Randomized with seed 40265
checkout/start/index
with no logged in customer
calls #index and displays the registration and login form (FAILED - 1)
Failures:
1) checkout/start/index with no logged in customer calls #index and displays the registration and login form
Failure/Error: <%= t(".checkout_#{controller_name}_sub_headline") %>
ActionView::Template::Error:
translation missing: de.checkout.shared.sub_headline.checkout_test_sub_headline
# /home/arthur/.rvm/gems/ruby-3.1.2/gems/i18n-1.12.0/lib/i18n.rb:394:in `handle_exception'
# /home/arthur/.rvm/gems/ruby-3.1.2/gems/i18n-1.12.0/lib/i18n.rb:367:in `translate_key'
# /home/arthur/.rvm/gems/ruby-3.1.2/gems/i18n-1.12.0/lib/i18n.rb:222:in `translate'
# ./app/views/checkout/shared/_sub_headline.html.erb:6:in `_app_views_checkout_shared__sub_headline_html_erb__648894094841044844_23060'
# ./app/views/checkout/start/index.html.erb:8:in `_app_views_checkout_start_index_html_erb__2185710400981636407_23000'
# ./spec/views/checkout/start_spec.rb:10:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# I18n::MissingTranslationData:
# translation missing: de.checkout.shared.sub_headline.checkout_test_sub_headline
# /home/arthur/.rvm/gems/ruby-3.1.2/gems/i18n-1.12.0/lib/i18n.rb:394:in `handle_exception'
Top 1 slowest examples (0.03185 seconds, 6.4% of total time):
checkout/start/index with no logged in customer calls #index and displays the registration and login form
0.03185 seconds ./spec/views/checkout/start_spec.rb:9
Finished in 0.49579 seconds (files took 1.69 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/views/checkout/start_spec.rb:9 # checkout/start/index with no logged in customer calls #index and displays the registration and login form
Randomized with seed 40265
Is there any way to override this path for the test, or any other way to tell Rspec where to look for the correct translation?
Many thanks in advance
You have created a translation that's dependent upon the controller_name, which as you're seeing is different in your test environment because of the way Rails view tests work. If you need that in your code, then in your test I would stub it out so you're providing what your code expects. I'm not sure, but that's probably something like allow(helper).to receive(:controller_name) { 'your_controller_name' }

How to create classes in specs without polluting global namespace?

What's the best way to define a class within the context of a spec, and not have it pollute the global namespace? How does the other file even get access to that constant?
bowling_spec.rb
require "spec_helper"
describe Bowling do
context "when validate is defined" do
let(:dummy_class) {
Class.new(described_class) do
METRICS_NAMESPACE = "ExtendedClass.Metrics.namespace"
end
}
it "does nothing" do
dummy_class
end
end
end
Spec - batting_spec.rb
require "spec_helper"
describe Batting do
context do
it "does weird thing" do
expect { self.class.const_get(:METRICS_NAMESPACE) }.to raise_error(NameError)
end
end
end
If you run the individual spec file
rspec spec/batting_spec.rb
.
Finished in 0.00285 seconds (files took 0.12198 seconds to load)
1 example, 0 failures
If you run the spec which defines the dummy class
rspec spec/bowling_spec.rb spec/batting_spec.rb
.F
Failures:
1) Batting does weird thing
Failure/Error: expect { self.class.const_get(:METRICS_NAMESPACE) }.to raise_error(NameError)
expected NameError but nothing was raised
# ./spec/batting_spec.rb:6:in `block (3 levels) in <top (required)>'
Finished in 0.01445 seconds (files took 0.12715 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/batting_spec.rb:5 # Batting does weird thing
To reproduce the error: I created a repo: https://github.com/pratik60/rspec-pollution with updated Readme
Running rspec spec/batting_spec.rb spec/bowling_spec.rb
2 examples, 0 failures
Running rspec spec/bowling_spec.rb spec/batting_spec.rb
Gives the error you mention.
Using binding.pry:
describe Batting do
context do
it "does weird thing" do
require 'pry'
binding.pry
expect { self.class.const_get(:METRICS_NAMESPACE) }.to raise_error(NameError)
end
end
end
self.class.ancestors
[RSpec::ExampleGroups::Batting::Anonymous,
RSpec::ExampleGroups::Batting::Anonymous::LetDefinitions,
RSpec::ExampleGroups::Batting::Anonymous::NamedSubjectPreventSuper,
RSpec::ExampleGroups::Batting,
RSpec::ExampleGroups::Batting::LetDefinitions,
RSpec::ExampleGroups::Batting::NamedSubjectPreventSuper,
RSpec::Core::ExampleGroup,
Going down the inheritance tree
RSpec::Core::ExampleGroup::METRICS_NAMESPACE
(pry):4: warning: toplevel constant METRICS_NAMESPACE referenced by RSpec::Core::ExampleGroup::METRICS_NAMESPACE
=> "ExtendedClass.Metrics.namespace"
Checking the first object on the chain
Object::METRICS_NAMESPACE
=>"ExtendedClass.Metrics.namespace"
Even further
Class::METRICS_NAMESPACE
(pry):2: warning: toplevel constant METRICS_NAMESPACE referenced by Class::METRICS_NAMESPACE
=> "ExtendedClass.Metrics.namespace"
TL ; DR
As you said, when you did METRICS_NAMESPACE = "ExtendedClass.Metrics.namespace", you created a global namespace constant. (That is, a constant inside the uppermost ruby constant, Class)
Simply do this instead
Class.new(described_class) do
self.const_set('METRICS_NAMESPACE', "ExtendedClass.Metrics.namespace")
end
rspec spec/bowling_spec.rb spec/batting_spec.rb
Finished in 1.55 seconds (files took 0.08012 seconds to load)
2 examples, 0 failures

Run basic rspec file

I'm new to Ruby and RSpec. I want to create very simple RSpec test:
# test_spec.rb
require 'spec_helper'
describe TestController do
puts(Time.now)
end
But when I run the code this way rspec test_spec.rb I get error:
`<top (required)>': uninitialized constant TestController (NameError)
Can you give me some idea where I'm wrong?
If you pass a class to describe, RSpec attempts to create an instance of that class. If the specified class does not exist, you get an error.
You can pass a string instead:
describe "my first test" do
it "does something" do
expect(1).to be_odd
end
end
Running the above:
$ rspec -fd test_spec.rb
my first test
does something
Finished in 0.00178 seconds (files took 0.10381 seconds to load)
1 example, 0 failures
This error is because after the describe you need a string with the description and you are leaving it without quotes.
describe '3pController' do
puts(Time.now)
end
But the tests should be structured as follows
a (describe) can have many (it) inside (a (it) is where the tests are)
one (decribe) can have more (describe) inside or can have (context), that these at the same time has many (it).
inside this link I will leave the documentation Basic structure
Here you can see a basic example of a test
describe 'sum 2 + 2 equal 4' do
   it { expect(2 + 2).to eq(4)}
end

capybara have_title NoMethodError

At the moment, this is a simple project - just a couple of static pages. I'm developing a generic test framework but am struggling to differentiate between the different test options. I have added Rspec, Capybara, Faker, Factory Girl, Spring, and shoulda (though I'm not using the shoulda matchers at the moment).
I have this controller test file:
require 'rails_helper'
RSpec.describe StaticPagesController, type: :controller do
describe "GET #a_page" do
before(:each) { get :a_page }
it "returns http success" do
expect(response).to have_http_status(:success)
end
it "has a page title Static Site" do
expect(response).to have_title('Static Site')
end
end
end
When this runs through guard, it throws an error stack:
23:13:39 - INFO - Run all
23:13:39 - INFO - Running all specs
Running via Spring preloader in process 4498
Running via Spring preloader in process 4506
/home/steve/workspaces/static_site/db/schema.rb doesn't exist yet. Run `rake db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /home/steve/workspaces/static_site/config/application.rb to limit the frameworks that will be loaded.
.F
Failures:
1) StaticPagesController GET #a_page has a page title Static Site
Failure/Error: expect(response).to have_title('Static Site')
NoMethodError:
undefined method `match' for nil:NilClass
Did you mean? catch
# /home/steve/.rvm/gems/ruby-2.3.1/gems/capybara-2.7.1/lib/capybara/queries/title_query.rb:18:in `resolves_for?'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/capybara-2.7.1/lib/capybara/node/document_matchers.rb:20:in `block in assert_title'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/capybara-2.7.1/lib/capybara/node/simple.rb:144:in `synchronize'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/capybara-2.7.1/lib/capybara/node/document_matchers.rb:19:in `assert_title'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/capybara-2.7.1/lib/capybara/rspec/matchers.rb:105:in `matches?'
# ./spec/controllers/static_pages_controller_spec.rb:34:in `block (3 levels) in <top (required)>'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/command_wrapper.rb:38:in `call'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:191:in `block in serve'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:161:in `fork'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:161:in `serve'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:131:in `block in run'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:125:in `loop'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:125:in `run'
# /home/steve/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application/boot.rb:19:in `<top (required)>'
# -e:1:in `<main>'
Finished in 0.029 seconds (files took 2.54 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/controllers/static_pages_controller_spec.rb:33 # StaticPagesController GET #a_page has a page title Static Site
The first test runs OK and, without the second, I get a clean result. I've spent a lot of time going over my config and it looks OK. I have also looked at the docs and some support sites.
Can anybody help out?
Capybara matchers need to be called against a html/xml document element (or a string that parses into a document), not against a response object. By default Capybaras matchers are normally only available in feature and view specs (not controller) was there a particular reason you included them into controller specs? Verifying a pages title really should lean more towards being a view spec than controller (by default views aren't rendered in controller specs - https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs).
As #Thomas Walpole pointed out, Capybara is not enabled in controller specs by default. One option is to change the type of the test to feature (type: :feature).
To make Capybara's built-in matcher have_title work, you need to use visit from Capybara's API, not get from ActionDispatch::IntegrationTest.

Rails Engine with RSpec and FactoryGirl

I followed a few tutorials and docs of FactoryGirl to use with RSpec. Currently I get one error when trying to use FactoryGirl.create:
describe "GenericRecipesController" do
describe "GET 'index'" do
it "displays list of generic recipes" do
generic_recipe = FactoryGirl.create(:generic_recipe)
visit '/recipe'
response.should be_success
end
end
end
And the error:
GenericRecipesController GET 'index' displays list of generic recipes
Failure/Error: generic_recipe = FactoryGirl.create(:generic_recipe)
NameError:
uninitialized constant GenericRecipe
# ./spec/integration/generic_recipes_spec.rb:8:in `block (3 levels) in <top (required)>'
The rest of code is there.
You can try this:
factory :generic_recipe, class: EdibleRecipe::GenericRecipe do
# ...
end
I think problem in a nesting model in module
Upd: delete file /spec/factories.rb, in file /spec/support/factories.rb make
factory :generic_recipe, class: EdibleRecipe::GenericRecipe do
When you will run tests, probably will see 'can not load table'. Make
rake db:migrate RAILS_ENV=test
and try again.
You don't seem to have a GenericRecipe model in your app. Factory Girl is looking for a Model called GenericReciper and can't find it.

Resources