I am creating a little API with Rails 5.0 following this tutorial http://apionrails.icalialabs.com/book/frontmatter
I am trying to run a test located in app/config/lib but RSpec won't find the test.
I have tried adding config.autoload_paths << Rails.root.join('lib') or
config.autoload_paths += %W(#{config.root}/lib) to app/config/application.rb.
This is my code:
$ /app/config/application.rb
#required files go here, deleted for clarity.
Bundler.require(*Rails.groups)
module MarketPlaceApi
class Application < Rails::Application
# don't generate RSpec tests for views and helpers
config.generators do |g|
g.test_framework :rspec, fixture: true
g.fixture_replacement :factory_girl, dir: 'spec/factories'
g.view_specs false
g.helper_specs false
g.stylesheets = false
g.javascripts = false
g.helper = false
end
config.autoload_paths += %W(#{config.root}/lib)
end
end
Test
$ app/config/lib/spec/test_spec.rb
require 'spec_helper'
describe ApiConstraints do
#test goes here
end
How can I add the lib folder so RSpec runs the tests located in it?
Thanks in advance.
RSpec doesn't look for tests in autoload_paths. If you run rspec or rake spec without arguments, RSpec looks in the spec directory by default. If you want to run specs in a different directory, give that directory to rspec as an argument:
rspec app/config/lib/spec
However, it's the universal convention to keep your specs in the spec directory, separate from your code in app and lib, so I'd move your specs to spec/lib. RSpec will then find them without any extra effort.
Related
I'm writing a Rails extension. To test it, I use RSpec. In order to make models to test the plugin on, I use a pregenerated dummy app:
rails plugin new yaffle --dummy-path=spec/dummy --skip-test --full
I have a few tests. When I call them, they run twice.
> # I have 4 tests in app total
> rspec
> 8 examples, 0 failures
> rspec spec/yaffle/active_record/acts_as_yaffle_spec.rb
> 4 examples, 0 failures
> rspec spec/yaffle/active_record/acts_as_yaffle_spec.rb:4
> 2 examples, 0 failures
This is how my files look like:
# lib/yaffle.rb
Gem.find_files('yaffle/**/*.rb').each { |path| require path }
module Yaffle
# Your code goes here...
end
# spec/spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../dummy/config/environment", __FILE__)
RSpec.configure do |config|
config.example_status_persistence_file_path = '.rspec_status'
config.disable_monkey_patching!
end
# spec/dummy/config/environment.rb
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
# spec/yaffle/active_record/acts_as_yaffle_spec.rb
require "spec_helper"
RSpec.describe "Acts as yaffle" do
def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
assert_equal "last_squawk", Hickwall.yaffle_text_field
end
def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
assert_equal "last_tweet", Wickwall.yaffle_text_field
end
end
# spec/dummy/config/application.rb
require_relative 'boot'
require "rails/all"
Bundler.require(*Rails.groups)
require "yaffle"
module Dummy
class Application < Rails::Application
config.load_defaults 6.0
end
end
Also, I noticed that only files with require "spec_helper" are duplicated
So, what am I doing wrong? And, if it's a bug, how to work around it?
The cause
It was caused by this line:
Gem.find_files('yaffle/**/*.rb').each { |path| require path }
Apparently, Gem.find_files gets all files in gem directory that match that pattern - not only the files relative to gem root. So, yaffle/**/*.rb means both files in <GEM_ROOT>/lib/yaffle/... and <GEM_ROOT>/spec/lib/yaffle/....
https://apidock.com/ruby/v1_9_3_392/Gem/find_files/class
Fix
I fixed it by requiring all files explicitly:
require 'lib/yaffle/active_record/acts_as_yaffle'
require 'lib/yaffle/active_record/has_fleas'
It's also possible to just require all files from that directory:
Dir["lib/yaffle/active_record/**/*.rb"].each {|file| require file }
When I generate a model using:
$ rails g model example
Rails generates a factory for the model. Currently it adds the factory to test/factories however I need it to add the factory to spec/factories.
I'm using RSpec and everything else is generated to spec/….
Normally, the place where these files end up, is determined by a directive in the file config/application.rb:
class Application < Rails::Application
config.generators do |g|
...
g.fixture_replacement :factory_girl, dir: 'spec/factories'
...
end
...
I have an admin engine with rspec inside my host application. Here is the my application structure:
Here is the my admin engine's config:
module Admin
class Engine < ::Rails::Engine
isolate_namespace Admin
engine_name 'admin'
config.generators do |g|
g.test_framework :rspec, fixture: false, view_specs: false
g.fixture_replacement :fabrication
g.fixture_replacement :factory_girl, dir: 'spec/factories'
g.integration_tool :rspec
g.assets false
g.helper false
end
end
end
When I create new controller inside the admin engine. I want to generate controller tests on host application's spec/admin/controllers/welcome_controller_spec.rb. I guess I need change admin engine's rspec's config. Any idea?
In your admin project, in config/initializers directory you can create a monkey patch to overwrite the path where the controller spec file is generated:
file /config/initializers/scaffold_generator.rb
require 'generators/rspec/scaffold/scaffold_generator'
module Rspec
module Generators
class ScaffoldGenerator
def generate_controller_spec
return unless options[:controller_specs]
template 'controller_spec.rb',
File.join('/path/to/host/project', 'spec/admin/controllers', controller_class_path, "#{controller_file_name}_controller_spec.rb")
end
end
end
end
It would be clever to replace the hard-coded path '/path/to/host/project' by something more dynamic, so it won't break when you move your workspace files in another location. I can't help you for that because it depends on your project file structure, and it should be easy to do.
To invoke:
bundle exec rails generate scaffold_controller my_controller
Will generate the controller, helper, views, rspec/helper, and rspec/views files in your admin project, and the rspec/controller file in your host project
Does anyone know of a rake task or RSpec call that will generate a bunch of empty files relative to the existing controllers, models, helper files and views that already exist within your application?
You can generate an empty scaffold set of rspec tests against an existing controller using something like this:
rails generate rspec:scaffold recipe
You can improve on this by passing the attributes of the model you want to generate against, like this:
rails generate rspec:scaffold recipe title: string slug: string description: text
You'll still need to do some manual editing, but this should get you most of the way there.
The best solution for this is to add hooks in place within environment.rb to create the spec.rb files within the rails application each time a model or controller is created.
Here's the code for that (using RSpec and FactoryGirl):
module RailsApp
class Application < Rails::Application
config.generators do |g|
g.test_framework :rspec, :fixture_replacement => :factory_girl, :views => true, :helper => false
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
g.stylesheets false
g.javascripts false
g.helper false
end
end
end
This should work:
Install the rspec-rails gem by adding it to your development and test groups in your gemfile gem 'rspec-rails'
Run the rspec generator from inside your app rails generate rspec:install
Read over this doc quickly to see how it integrates with your rails app RSpec-rails doc
Is there any command available for generating all missing spec files for existing models / controllers? I have a project that has several models that have been generated with out spec files.
In rspec-rails-2 which is intended for Rails 3 all of the rspec generators have been removed.
You can solve this problem by running the rails model generator. You can add -s to skip any existing files and --migration=false to skip creating the migration file.
Like so:
rails generate model example -s --migration=false
You could just run the generator and ignore the models/migrations/fixtures.
ruby script/generate rspec_model User --skip-migration --skip-fixture --skip
I've been looking into writing something to do this but there hasn't been any interest from others.
If the number of missing specs is rather small, you could simply run the rails generate commands for each components with missing specs.
When a conflict arises, simply opt not to overwrite the original file. The generator will ignore the existing files and generate the missing ones.
https://gist.github.com/omenking/7774140
require 'fileutils'
namespace :spec do
def progress name, x, y
print "\r #{name}: #{x}/#{y} %6.2f%%" % [x.to_f/y * 100]
end
def generate_files name
kind = name.to_s.singularize
collection = Dir.glob Rails.root.join('app',name.to_s,'**','*').to_s
root = Rails.root.join('app',name.to_s).to_s<<'/'
ext = case name
when :controllers then '_controller.rb'
when :models then '.rb'
end
count = collection.count
collection.each_with_index do |i,index|
`rails g #{kind} #{$1} -s` if i =~ /#{root}(.+)#{ext}/
progress name, index, count
end
end
task generate_missing: :environment do
generate_files :controllers
generate_files :models
end
end
# if you dont want certian things generated than
# configure your generators in your application.rb eg.
#
# config.generators do |g|
# g.orm :active_record
# g.template_engine :haml
# g.stylesheets false
# g.javascripts false
# g.test_framework :rspec,
# fixture: false,
# fixture_replacement: nil
# end
#