Loading file from model to spec - ruby-on-rails

I want to load my model file into spec. When i try to require 'project' in my spec it does not work. How can i load my model file inside spec.
require File.dirname(__FILE__) + '/project.rb'
RSpec.describe Project do
it 'finds an project' do
project = class_double("project")
end
end
The above statement tries to load model from spec directory... but i want to load model file which inside app directory.

You can try:
require Rails.root.join("app", "models", "project.rb")

Related

In a Rails engine Is it possible for Rspec to make use of Rspec support system helpers from another engine?

Given a Rails engine_one that has a spec support file engine_one/spec/support/system/order_functions.rb, containing functionality to support the testing of various order system tests such as simulating a logged in user, adding products to an order etc and contains methods such as log_visitor_in that get used extensively when testing order processing etc...
So now in engine_two that extends some ordering functionality from engine_one I wish to add a new system test that first has to log a visitor in. So how can I make use of that support method from from engine_one?
So far I have mounted the engines in the dummy app
I have required engine_one in engine_two/lib/engine.rb
I have required the support file in the relevant test but it can't be found and obviously I have added engine_one to engine_two.gemspec
engine_two/spec/rails_helper.rb
require 'engine_one' # and any other gems you need
engine_two/lib/engine_two/engine.rb
require 'engine_one'
in the relevant system test I have the following
engine_two/spec/system/new_payment_methods_spec.rb
require 'rails_helper'
include EngineOne::System
RSpec.describe "order_payment_feature", type: :system do
before do
driven_by(:rack_test)
end
it "has order payment options" do
log_visitor_in
end
end
This results in the following error
Failure/Error: include EngineOne::System
NameError:
uninitialized constant EngineOne::System
Did you mean? SystemExit
And the helper
module System
def log_visitor_in()
administrator = create(:visitor)
visit ccs_cms.login_url
fill_in 'login_name', with: visitor.login_name
fill_in 'Password', with: visitor.password
click_button 'Login'
end
end
I have tried with a require instead of an include but that results in a file not found error
Plus I have tried changing the include path to
include EngineOne::Spec::Support::System resulting in the same error
So I guess I'm looking for the correct path but I am stuck or missing some other way to include the helper.
These are Rails 7 engines.
When you require a file, ruby searches for it relative to paths in $LOAD_PATH; spec/ or test/ are not part of it.
app directory is a special one in rails, any subdirectory automatically becomes part of autoload_paths. Auto load paths can be seen here ActiveSupport::Dependencies.autoload_paths.
Any classes/modules defined inside app/* directories can be used without requiring corresponding files. Rails v7 uses zeitwerk to automatically load/reload files by relying on the 'file name' to 'constant name' relationship. That's why folders map to namespaces and files map to classes/modules.
To fix your issue put any shared code where it can be grabbed with require. Type $LOAD_PATH in the console:
>> $LOAD_PATH
=>
["/home/alex/code/stackoverflow/lib",
"/home/alex/code/stackoverflow/vendor",
"/home/alex/code/stackoverflow/app/channels",
"/home/alex/code/stackoverflow/app/controllers",
"/home/alex/code/stackoverflow/app/controllers/concerns",
"/home/alex/code/stackoverflow/app/helpers",
"/home/alex/code/stackoverflow/app/jobs",
"/home/alex/code/stackoverflow/app/mailers",
"/home/alex/code/stackoverflow/app/models",
"/home/alex/code/stackoverflow/app/models/concerns",
"/home/alex/code/stackoverflow/engines/question/lib", # <= engine's lib looks good
"/home/alex/code/stackoverflow/engines/question/app/components",
"/home/alex/code/stackoverflow/engines/question/app/controllers",
"/home/alex/code/stackoverflow/engines/question/app/controllers/concerns",
...
Put shared files in engines's lib directory. Since we're outside of app directory, rails is not the boss anymore, any path and filename combination will work.
# question/lib/testing_support/blah.rb # <= note the filename
module System
def log_visitor_in
administrator = create(:visitor)
visit ccs_cms.login_url
fill_in 'login_name', with: visitor.login_name
fill_in 'Password', with: visitor.password
click_button 'Login'
end
end
Now that file can be required
# test/test_helper.rb or spec/rails_helper.rb
# after environment and rails requires
require "testing_support/blah" # => loads System module
# ...
That's it, use it in your spec
require 'rails_helper'
RSpec.describe "order_payment_feature", type: :system do
include System # include is for modules; now we have its functions in this spec
before { log_visitor_in }
it 'should accept this answer' do
visit 'questions/71362333'
expect(page).to have_content('accepted')
end
end
Additionally you can require your files any way you wish with an absolute path, regardless of $LOAD_PATH.
require EngineOne::Engine.root + 'spec/support/system/order_functions.rb'
# or something else
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }

why does my rails generator template method results in 'file_clash'

So I'm writing a rails generator to do the most simple of things: copy some model files from a gem's lib/generators/pathways/templates directory into a project in the app/models directory. My possibly mistaken understanding is that the template method is basically a file copy with source/target.
(note that "pathways" is the name of my gem that installs this generator)
Here's the guts of the copy code in the generator:
def copy_models
project_models_location = "#{Rails.root}/app/models/"
[
"pathways_experiment.rb",
...
].each do |filename|
puts "copying #{filename} to #{project_models_location}"
template filename, "#{project_models_location}"
end
end
The puts displays what I expected:
copying pathways_experiment.rb to
/Users/meuser/Projects/testing_gem/exp_gem_test/app/models/
however, the call to the templates method dumps this output:
file_clash app/models
I checked the target directory and there are no files in it, so it doesn't seem to be because the code is trying to overwrite the file.
here's the source of the entire generator in case I simply haven't included or extended the correct classes/modules:
require 'rails/generators'
require 'rails/generators/active_record'
module Pathways
class InstallGenerator < ActiveRecord::Generators::Base
include Rails::Generators::Migration
source_root File.expand_path("../templates", __FILE__)
def code_that_runs
puts "PATHWAYS: installing models"
copy_models
end
private
def copy_models
project_models_location = "#{Rails.root}/app/models/"
[
"pathways_experiment.rb",
...
].each do |filename|
puts "copying #{filename} to #{project_models_location}"
template filename, "#{project_models_location}"
end
end
end
end

Rspec not loading support files

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.

Correct way to test lib folder with rspec?

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

Ruby on Rails docsplit file path

I have a pdftotext.rb file in /lib and the code is
module Pdftotext
require 'rubygems'
require 'docsplit'
class << self
def convert
Docsplit.extract_text("hello.pdf")
end
end
end
I have the hello.pdf file in the /assets folder and I tried "assets/hello.pdf" but it keeps telling me Error: Couldn't open file '/assets/hello.pdf': No such file or directory.
How can I get the right path to get the file to be converted?
By the way I am using rails 3.2.1, thanks.
Do you mean it is in RAILS_ROOT/assets/hello.pdf?
You should use File.join to get at the file. Like this:
module Pdftotext
require 'rubygems'
require 'docsplit'
class << self
def convert
Docsplit.extract_text(File.join(Rails.root, "assets", "hello.pdf"))
end
end
end
Using "/assets/hello.pdf" will try to get it from the file system root.

Resources