FactoryBot doesn't see Doorkeeper classes
slim1979 opened this issue ยท 21 comments
good day for everyone
when using doorkeeper-4.3.0, a have a problem with FactoryBot. He refused to see doorkeeper classes:
NameError:
uninitialized constant Doorkeeper::AccessToken
NameError:
uninitialized constant Doorkeeper::Application
and other
rollback to 4.2.6 solve this problem
Doorkeeper 4.3 uses FactoryBot, and Doorkeeper 4.2.6 uses FactoryGirl. What gem do you have?
Also, could you please provide your Gemfile.lock
and spec_helper.rb
?
i'm now use 4.2.6 with FactoryBot.
Gemfile.lock
GIT
remote: https://github.com/thoughtbot/shoulda-matchers.git
revision: 4b160bd19ecca7f97d7ac22dccd5fde9b0da5a9f
branch: rails-5
specs:
shoulda-matchers (3.1.2)
activesupport (>= 4.2.0)
GEM
remote: https://rubygems.org/
specs:
actioncable (5.1.4)
actionpack (= 5.1.4)
nio4r (~> 2.0)
websocket-driver (~> 0.6.1)
actionmailer (5.1.4)
actionpack (= 5.1.4)
actionview (= 5.1.4)
activejob (= 5.1.4)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.1.4)
actionview (= 5.1.4)
activesupport (= 5.1.4)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.1.4)
activesupport (= 5.1.4)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.1.4)
activesupport (= 5.1.4)
globalid (>= 0.3.6)
activemodel (5.1.4)
activesupport (= 5.1.4)
activerecord (5.1.4)
activemodel (= 5.1.4)
activesupport (= 5.1.4)
arel (~> 8.0)
activesupport (5.1.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
arel (8.0.0)
bcrypt (3.1.11)
bindex (0.5.0)
builder (3.2.3)
byebug (9.1.0)
cancancan (2.1.3)
capybara (2.17.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (>= 2.0, < 4.0)
capybara-email (2.5.0)
capybara (~> 2.4)
mail
capybara-webkit (1.1.0)
capybara (~> 2.0, >= 2.0.2)
json
carrierwave (1.2.2)
activemodel (>= 4.0.0)
activesupport (>= 4.0.0)
mime-types (>= 1.16)
cliver (0.3.2)
coderay (1.1.2)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
commonjs (0.2.7)
concurrent-ruby (1.0.5)
crass (1.0.3)
database_cleaner (1.6.2)
devise (4.4.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.2)
responders
warden (~> 1.2.3)
diff-lcs (1.3)
doorkeeper (4.2.6)
railties (>= 4.2)
erubi (1.7.0)
execjs (2.7.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.18)
formatador (0.2.5)
globalid (0.4.1)
activesupport (>= 4.2.0)
gon (6.2.0)
actionpack (>= 3.0)
multi_json
request_store (>= 1.0)
guard (2.14.2)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (>= 1.0.12, < 2.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-rspec (4.7.3)
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
hashie (3.5.7)
i18n (0.9.1)
concurrent-ruby (~> 1.0)
jbuilder (2.7.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jquery-ui-rails (6.0.1)
railties (>= 3.2.16)
json (2.1.0)
jwt (1.5.6)
launchy (2.4.3)
addressable (~> 2.3)
less (2.6.0)
commonjs (~> 0.2.7)
less-rails (2.8.0)
actionpack (>= 4.0)
less (~> 2.6.0)
sprockets (> 2, < 4)
tilt
letter_opener (1.4.1)
launchy (~> 2.2)
libv8 (3.16.14.19)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.1.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.0.12)
mail (2.7.0)
mini_mime (>= 0.1.1)
method_source (0.9.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.11.1)
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
nenv (0.3.0)
nested_form (0.3.2)
nio4r (2.2.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
oauth (0.5.4)
oauth2 (1.4.0)
faraday (>= 0.8, < 0.13)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.5.0)
oauth2 (~> 1.1)
omniauth (~> 1.2)
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
orm_adapter (0.5.0)
pg (0.21.0)
poltergeist (1.17.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.5.1)
byebug (~> 9.1)
pry (~> 0.10)
pry-rails (0.3.6)
pry (>= 0.10.4)
public_suffix (3.0.1)
puma (3.11.0)
rack (2.0.3)
rack-test (0.8.2)
rack (>= 1.0, < 3)
rails (5.1.4)
actioncable (= 5.1.4)
actionmailer (= 5.1.4)
actionpack (= 5.1.4)
actionview (= 5.1.4)
activejob (= 5.1.4)
activemodel (= 5.1.4)
activerecord (= 5.1.4)
activesupport (= 5.1.4)
bundler (>= 1.3.0)
railties (= 5.1.4)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
actionview (~> 5.x, >= 5.0.1)
activesupport (~> 5.x)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (5.1.4)
actionpack (= 5.1.4)
activesupport (= 5.1.4)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.3.0)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
ref (2.0.0)
remotipart (1.3.1)
request_store (1.4.0)
rack (>= 1.4)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-rails (3.7.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.0)
ruby_dep (1.5.0)
sass (3.5.5)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.7)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
shellany (0.0.1)
skim (0.10.0)
coffee-script
coffee-script-source (>= 1.2.0)
slim (>= 3.0)
sprockets (>= 2, < 4)
slim (3.0.9)
temple (>= 0.7.6, < 0.9)
tilt (>= 1.3.3, < 2.1)
slim-rails (3.1.3)
actionpack (>= 3.1)
railties (>= 3.1)
slim (~> 3.0)
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.6.3)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
temple (0.8.0)
therubyracer (0.12.3)
libv8 (~> 3.16.14.15)
ref
thor (0.20.0)
thread_safe (0.3.6)
tilt (2.0.8)
turbolinks (5.1.0)
turbolinks-source (~> 5.1)
turbolinks-source (5.1.0)
twitter-bootstrap-rails (4.0.0)
actionpack (~> 5.0, >= 5.0.1)
execjs (~> 2.7)
less-rails (~> 2.8, >= 2.8.0)
railties (~> 5.0, >= 5.0.1)
tzinfo (1.2.4)
thread_safe (~> 0.1)
uglifier (4.1.3)
execjs (>= 0.3.0, < 3)
warden (1.2.7)
rack (>= 1.0)
web-console (3.5.1)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
xpath (3.0.0)
nokogiri (~> 1.8)
PLATFORMS
ruby
DEPENDENCIES
cancancan
capybara (~> 2.13)
capybara-email
capybara-webkit
carrierwave
coffee-rails (~> 4.2)
database_cleaner
devise
doorkeeper (= 4.2.6)
factory_bot_rails
gon
guard-rspec
jbuilder (~> 2.5)
jquery-rails
jquery-ui-rails
launchy
less-rails
letter_opener
listen (>= 3.0.5, < 3.2)
nested_form
omniauth
omniauth-facebook
omniauth-twitter
pg (~> 0.18)
poltergeist
pry-byebug
pry-rails
puma (~> 3.7)
rails (~> 5.1.4)
rails-controller-testing
remotipart
responders
rspec-rails
sass-rails (~> 5.0)
shoulda-matchers!
skim
slim-rails
spring
spring-commands-rspec
spring-watcher-listen (~> 2.0.0)
sprockets (= 3.6.3)
therubyracer
turbolinks (~> 5)
twitter-bootstrap-rails
tzinfo-data
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
BUNDLED WITH
1.16.0.pre.3
spec_helper.rb
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
# files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need
# it.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
# have no way to turn it off -- the option exists only for backwards
# compatibility in RSpec 3). It causes shared context metadata to be
# inherited by the metadata hash of host groups and examples, rather than
# triggering implicit auto-inclusion in groups with matching metadata.
config.shared_context_metadata_behavior = :apply_to_host_groups
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# This allows you to limit a spec run to individual examples or groups
# you care about by tagging them with `:focus` metadata. When nothing
# is tagged with `:focus`, all examples get run. RSpec also provides
# aliases for `it`, `describe`, and `context` that include `:focus`
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
config.filter_run_when_matching :focus
# Allows RSpec to persist some state between runs in order to support
# the `--only-failures` and `--next-failure` CLI options. We recommend
# you configure your source control system to ignore this file.
config.example_status_persistence_file_path = "spec/examples.txt"
# Limits the available syntax to the non-monkey patched syntax that is
# recommended. For more details, see:
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
config.disable_monkey_patching!
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = "doc"
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end
And what about yhe factories?
Do you have
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
FactoryBot.find_definitions
end
end
?
i got
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
in rails_helper.rb
I don't have that record:
config.before(:suite) do
FactoryBot.find_definitions
end
will this solve problem?
It loads factories for the gem and suggested by the official docs. I will try to reproduce the error a little bit later
must say, that doesnt work for me
It is a brandly new app or some legacy project?
Did you do rails generate doorkeeper:install
? Without Doorkeeper initializer it's models wouldn't be loaded.
I created a new project with next Gemfile:
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.3.1'
gem 'rails', '~> 5.2.0.beta2'
gem 'sqlite3'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'duktape'
gem 'doorkeeper', '~> 4.3'
group :development, :test do
gem 'factory_bot_rails'
gem 'rspec-rails', '~> 3.7'
end
group :development do
gem 'web-console', '>= 3.3.0'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
-
Default Doorkeeper initilizer.
-
Factory:
# spec/factories/access_token.rb
FactoryBot.define do
factory :access_token, class: Doorkeeper::AccessToken do
end
end
And spec:
# spec/models/token_spec.rb
require 'rails_helper'
RSpec.describe 'token' do
it 'test' do
expect(FactoryBot.build(:access_token)).to be_valid
end
end
Everything is OK.
It is a brandly new app or some legacy project?
educational app
Did you do rails generate doorkeeper:install?
yes, i did. i have config/initializers/doorkeeper.rb
Everything is OK.
lucky you)
i can provide link to branch, which contain broken code. maybe, this can help?
Yep, it would be great if you have this one public!
@slim1979 yes, I see the problem, but can't find the source of it. As I can see from the trace debugging, ActiveSupport lazy hooks are not invoked, so models didn't loaded. Can't find the reason why it is happens, maybe some initializer / configuration / gem side effects..
If you will add ActiveRecord::Base.inspect
as a first line of access_tokens factory, then it will work :\
Analyzed trace and it looks like in your case AS doesn't load dependencies or do it in other way https://gist.github.com/nbulaj/5ce408c58a6fde239b8e71653ce5d568
I was using Rails 5.2, and it uses ActiveStorage that depends on ActiveRecord. So it loads AR somehow and my tests were green. If I remove config.active_storage.service = :test
from the config/environments/test.rb
- then I got your error O_o
my mentor thinking, that this is about lazy_load helper, which will load all only if AS initialized, but factories loads earlier and this cause a problem
He is right about the helpers. Doorkeeper models must be loaded at the time when ActiveRecord are loaded using ActiveSupport lazy hooks (in this case we can configure some AR options before Doorkeeper models would be loaded). ActiveRecord::Base
has autoloading and would be initialized only on first call. When tests are invoked, factories run before the ActiveRecord loaded (because nobody touches ActiveRecord::Base
, so it is not loaded yet), so this is why we get this error (on this moment Doorkeeper::AccessToken
and other models still not require
d).
I'l try to investigate the problem and solve it for 4.3.1 release.
Hi @slim1979 . The problem is in factory_bot_rails
gem. It has an railtie
that tries to find factory definitions (and load them) after engine initialization, and this cause the error because models is not loaded yet, the same as ActiveRecord
.
To solve this problem you can replace factory_bot_rails
gem with just factory_bot
and everything will work (I tried for your branch).
Related issue exists on the factory_bot_rails
gem itself thoughtbot/factory_bot_rails#134 , but it is closed and nobody seems to fix it.
P.S. I recommend you to move require statements in your rails_helper.rb
(like 'capybara/rspec'
or 'shoulda/matchers'
) under require 'rspec/rails'
as it suggested by the official RSpec gem docs (you can even find the corresponding comment # Add additional requires below this line. Rails is not loaded until this point!
). And you don't need to require 'doorkeeper' as it would be loaded by your app (require File.expand_path('../../config/environment', __FILE__)
)
will try it later.... thanks a lot for your investigation)
@nbulaj, hi there. no, nothing new... i had an conversation with my mentor about this situation and he told me, what this will never been solved by any sides, because noone want to change its product, as saying. this is noone bug, just incompatibility. i willn't change my doorkeeper version right now, because it doesn't make sense for me. maybe, someone will see problem solvation in this issue... i will be glad
So because of it is not a bug in Doorkeeper itself I will close this issue now. The only solution I see (for Doorkeeper) is to manually trigger AR::Base (before factory bot rails initializer), but you are right - I don't think I would do this for some testing gem.
As factory_bot_rails
is just about 8 lines of code - I don't think it is a big problem to replace it with native factory_bot
. But if somebody will see this issue and want to propose some solution to fix it - feel free to send a PR :)
I tried this, will work for you until this issue is solved on factory_bot_rails
. Create the file lib/factory_bot_rails/railtie.rb
on your project - we're actually copying the current railtie contents and modifying one line:
require 'factory_bot'
require 'factory_bot_rails/generator'
require 'rails'
module FactoryBot
class Railtie < Rails::Railtie
initializer "factory_bot.set_fixture_replacement" do
FactoryBotRails::Generator.new(config).run
end
initializer "factory_bot.set_factory_paths" do
FactoryBot.definition_file_paths = [
Rails.root.join('factories'),
Rails.root.join('test', 'factories'),
Rails.root.join('spec', 'factories')
]
end
config.after_initialize do
# This line is the one that fixes it:
ActiveSupport.on_load(:active_record) { FactoryBot.find_definitions }
if defined?(Spring)
Spring.after_fork { FactoryBot.reload }
end
end
end
end
I'll post this as a PR on Factory Bot Rails repo
I was able to get around this issue by putting quotes around the class name when defining the factory:
factory :access_token, class: 'Doorkeeper::AccessToken' do
...
end
High five to @sman591 for this excellent commit message:
As described in doorkeeper-gem#1043,
factories defined by doorkeeper are unable to be loaded by host apps
using the `factory_bot_rails` gem (receiving errors such as
`uninitialized constant Doorkeeper::AccessGrant`)
Documentation for factory_bot was later added to explain an easy fix for
this: instead of defining the factory's `class: ` with a named constant,
wrap the constant in a string. By doing so, the constant isn't evaluated
until the factory actually runs, at which point the `Doorkeeper::` models
have all been loaded.