I have this file:
# support/auth_macros.rb
module AuthMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#logged_in_user = FactoryGirl.create(:user, username: "logged_in")
sign_in #logged_in_user
end
end
def logout_user
before(:each) do
sign_out #logged_in_user
end
end
end
In my spec_helper file, I have this line:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Yet when I run rspec, I get errors like:
undefined local variable or method `login_user' for RSpec::ExampleGroups::PostsController::POSTCreate::WhenSignedIn:Class
The relevant function is located in support/auth_macros, which I assume would be picked up by the require statement in my spec_helper.
Any idea what might be going on?
You have required the file, but the method is wrapped inside a module. You need to either remove the wrapping module or include it within your group test.
Update:
To be 100% specific: require loads the file and do nothing else. After file is required, the module has been created, but it is not included. You need to include it with: include AuthMacros
If your file relative path like support/auth_macros.rb and you wanna load it on selenium_helper.rb file, you need to do both step bellow:
Call require to load the file: require 'support/auth_macros'
And include it using: include AuthMacros
Hope it help.
Related
I am trying to include a custom module into an RSpec test. However, I keep getting errors telling me it can't find my module, it says NameError: uninitialized constant AuthHelper.
I have been trying to follow this https://stackoverflow.com/a/68669816/5568244
I didn't know where to put the the module so I created a folder called specs/support/ and a file called auth_helper.rb in it and put module AuthHelper ...etc... end in that
I have tried simply including it in the test
spec/requests/topics_specs.rb
require 'rails_helper'
include AuthHelper
which i expected to be able to just automatically find the module in the support folder but it didn't. Should it? Does RSpec look in specific places?
I also tried to set up the rails_helper.rb file to include it
RSpec.configure do |config|
config.include(AuthHelper, :type => :request)
end
This still didn't work.
What am i missing? How should this work?
I have a test that tries to test a class located in lib folder.
Right now I do this in my parser_spec.rb
require 'spec_helper'
require 'parser' --> Because my class is /lib/parser.rb
describe "parser" do
it "needs a url to initialize" do
expect { Parser.new }.to raise_error(ArgumentError)
end
end
What would be the correct way to include all the lib files, so that they are in the scope of the rspec tests?
The way you've done it -- require 'parser' is the recommended way. RSpec puts lib on the $LOAD_PATH so that you can require files relative to it, just like you've done.
Try this
require_relative "../../lib/parser.rb"
or
require 'lib/parser.rb'
rspec automatically loads 'spec/spec_helper.rb' when it runs, and it also automatically adds the 'lib' folder to it's LOAD_PATH, so that your requires in 'lib/parser.rb' are seen and required properly.
Just put the 'lib' folder to autoload_path. For example, in application.rb
config.autoload_paths += "#{Rails.root}/lib/"
Then you can do it normally
require 'spec_helper'
describe Parser do
...
end
In order to avoid lib autoload as Ryan Bigg said, you can autoload a custom directory placed in the app root:
Into /your/config/application.rb you can add:
config.autoload_paths += %W(#{config.root}/my_stuff)
Then, you can do:
require 'spec_helper'
describe Parser do
#your code...
end
Maybe, you can put your class inside a module in order to avoid collisions:
class MyStuff::Parser
#your code...
end
Then, you can do:
require 'spec_helper'
describe MyStuff::Parser do
#your code...
end
In my Rails app I've added the following files:
app/models/baz.rb
lib/presenters/foo_presenter.rb
lib/presenters/foo_presenter/bar.rb
spec/models/baz_spec.rb
spec/lib/presenters/foo_presenter/bar_spec.rb
The contents of lib/presenters/foo_presenter.rb is something like:
module Presenters
module FooPresenter
def self.render
# do stuff
end
end
end
The contents of lib/presenters/foo_presenter/bar.rb is like:
module Presenters
class FooPresenter::Bar
def baz
# do stuff
end
end
end
The contents of spec/lib/presenters/foo_presenter/bar_spec.rb is like:
require 'spec_helper'
module Presenters::FooPresenter
describe Bar do
# some tests
end
end
Then I have a spec file in spec/models/baz_spec.rb:
require 'spec_helper'
describe Baz do
it 'works' do
Presenters::FooPresenter.render
end
end
(The contents of app/models/baz.rb is not relevant to this issue)
The problem is when I run rspec spec/models/baz_spec.rb it works fine without spork, but when spork is running, I get an error like:
NameError: undefined method `render' for Presenters::FooPresenter:Module
I traced through the code a bit and noticed that when rspec loads spec/lib/presenters/foo_presenter/bar_spec.rb it causes Rails to autoload lib/presenters/foo_presenter/bar.rb and so at that point Presenters::FooPresenter::Bar is loaded, but then when baz_spec.rb runs, lib/presenters/foo_presenter.rb has never been loaded and thus the exception. But this only happens if spork is running. The quick fix was to require 'foo_presenter' in a file in config/initializers, but is there a cleaner solution that doesn't need the explicit require? My guess is the issue here is that Rails doesn't autoload lib/presenters/foo_presenter.rb because Presenters::FooPresenter has already been defined by bar_spec.rb.
A co-worker and I were faced with this problem today and we eventually found we needed Spork to reload the classes on every run. We used the each_run() method to do this:
Spork.each_run do
Dir[Rails.root.join("app/classes/**/*.rb")].each {|f| require f}
end
I have multiple ruby test cases for selenium-webdriver and all the files are sharing the same functions. is there any way to create a global file and include the file to these test cases instead of typing them over and over again
for example - I create a file setup.rb
def setup
#driver = Selenium::WebDriver.for :firefox
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
end
then in my test_file.rb I start
require setup
setup
#driver.find_element(:xpath => '//span[text()="войти"]').click
There is an error
NoMethodError:
undefined method `find_element' for nil:NilClass
Change it to a global variable from an instance variable. Make it $driver instead of #driver and you shouldn't have a problem. Change it to something like..
def self_setup
$driver = Selenium::WebDriver.for :firefox
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
end
and then
require "./setup.rb"
setup.setup
$driver.find_element(:xpath => '//span[text()="войти"]').click
That should work. You'd probably want to go to a page first before you look for that xpath though. setup will only open up a new instance of firefox webdriver. Also I would suggest changing the name of setup.rb so it can be foo.setup insead of setup.setup. I use Lib.rb for the methods I want to be able to call regularly so for instance one would be Lib.signin_admin
Hope this works for you.
In response to your example, I think you forgot to include the setup module (you did put your method definition inside a module, right?). Also, the comment that mentions assigning the driver as a global variable (by naming it with a starting dollar sign) is a good idea. So things would look like this...
setup.rb
module Setup
def setup
$driver = Selenium::WebDriver.for :firefox
$wait = Selenium::WebDriver::Wait.new(:timeout => 10)
end
end
test_file.rb
require 'setup'
class SeleniumTest < Test::Unit::TestCase
include Setup # Modules need to be included (mixed-in) in order to be used inside classes
# Setup is automagically called when using TestUnit
$driver.get "http://www.yoururl.com"
$driver.find_element(:xpath => '//span[text()="войти"]').click
end
The downside is that for each new module and file you create, you have to require and include all of the new files and modules you want to use.
The method that I have found to work for me is to create a 'test_helper.rb', and to use a gem called 'require_all' that requires and includes all of the files from the directories you specify.
My test_helper.rb looks something like this:
require "rubygems"
require "require_all"
require "selenium-webdriver"
require "test-unit"
require_all relative_path("../lib/selenium/")
module TestHelpers
include Selenium
def setup
$driver = Selenium::WebDriver.for :firefox
...
end
def teardown
$driver.quit
end
end
And the test_page.rb only requires two lines:
# Line 1: Ensures the test_helper.rb gets loaded from the same directory the test_page.rb resides in
require File.join(File.dirname(__FILE__), 'test_helper')
class TestPage < Test::Unit::TestCase
# Line 2: Module needs mixed in to use its methods
include TestHelpers
def test_page
$driver.get "http://www.mysite.com"
assert $driver.find_element(:css => "div#my_site_logo")
end
end
My _spec file includes the code below, but my test fails with:
NameError in 'MembershipsController should allow you to save updates to the notes'
undefined local variable or method `activate_authlogic' for #<Spec::Rails::Example::ControllerExampleGroup::Subclass_1:0x107cee930>
I don't understand why activate_authlogic is undefined in this case. I've used this line in TestUnit many times, and the RSpec examples I've read all seem to say that this should work. NOTE: I've also tried adding require 'authlogic' to the top of the _spec file, but it produces an identical error message.
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require 'ruby-debug'
describe MembershipsController do
before(:each) do
activate_authlogic
#admin = Factory(:admin, :email => "admin#example.com")
UserSession.create(#admin)
end
...
end
Apparently a misunderstanding on my part. Instead of require 'authlogic'
I needed require 'authlogic/test_case'