rspec-rails: undefined local variable or method `tagged_logger' during perform_enqueued_jobs

What Ruby, Rails and RSpec versions are you using?

Ruby version: 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-darwin21] Rails version: 7.0.0 RSpec 3.10

  • rspec-core 3.10.1
  • rspec-expectations 3.10.1
  • rspec-mocks 3.10.2
  • rspec-rails 5.0.2
  • rspec-support 3.10.3

Observed behaviour

Inside an rspec support module, my app is calling perform_enqueued_jobs. The spec in question that is using this support module is expecting this call to raise an exception.

When I attempt to run this spec, the following is raised:

got #<NameError: undefined local variable or method `tagged_logger'

When I debug into perform_enqueued_jobs, I am taken into _assert_nothing_raised_or_warn inside activesupport-7.0.0/lib/active_support/testing/assertions.rb, When debugging the block below, it shows e as having the expected exception.

        rescue Minitest::UnexpectedError => e
          if tagged_logger && tagged_logger.warn?
            warning = <<~MSG
              #{self.class} - #{name}: #{e.error.class} raised.
              If you expected this exception, use `assert_raises` as near to the code that raises as possible.
              Other block based assertions (e.g. `#{assertion}`) can be used, as long as `assert_raises` is inside their block.
            MSG
            tagged_logger.warn warning
          end

          raise
        end

Debugging further reveals that the if tagged_logger check above is causing the undefined error.

I reported this on Rails forum here and a member of the core team suggested the following:

“This seems to be a bug in RSpec that doesn’t implement the tagged_logger. Please report the issue in the RSpec issue tracker.”

Expected behaviour

The spec should finish and allow to raise_error to check for the expected exception. This spec is working as expected in Rails 6.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 9
  • Comments: 22 (10 by maintainers)

Commits related to this issue

Most upvoted comments

I’m using the following crappy patch, as including the module into RSpec::Rails::RailsExampleGroup did not do anything.

Also defined a dummy name method (sigh), to resolve the subsequent issue that @jkwuc89 raises just above (which this also runs into)

if Rails::VERSION::MAJOR >= 7
  require 'rspec/rails/version'

  RSpec::Core::ExampleGroup.module_eval do
    include ActiveSupport::Testing::TaggedLogging

    def name
      'foobar'
    end
  end
end

PRs would be accepted to solve this, RailsExampleGroup should conditionally (as in, if on Rails 7) include this module, and ideally we’d want a snippet testing it.

@pirj I just saw this error in 6.0.1, and the monkey patch above https://github.com/rspec/rspec-rails/issues/2545#issuecomment-1029539971 can fix the issue.

However, I find I missed type: :job in my spec. If I add it, everything works fine. I think it’s because the error is raised by RSpec::Core::ExampleGroup if I don’t add type: :job, so the monkey patch works. When running a spec with type: :job, RSpec::Rails::RailsExampleGroup is included, so the fix works. Does it make sense?

It feels like they are checking for a tagged logger by assuming it exists, they could easily fix this by checking its defined

I also see the same error with 6.0.1, my code looks similar

      specify do
        expect { perform_enqueued_jobs { dispatch } }
          .to not_change(ActionMailer::Base.deliveries, :size)
          .and not_raise_error

Ruby 3.2.1, rails 7.0.4

@JonRowe the problem still persists, version 6.0.1

Here is a quick monkey patch using @pirj suggested solution

# spec/rspec_helper.rb

if Rails::VERSION::MAJOR >= 7
  require 'rspec/rails/version'
  
  if Gem::Version.create(RSpec::Rails::Version::STRING) < Gem::Version.create("5.1.0")
    RSpec::Rails::RailsExampleGroup.module_eval do
      include ActiveSupport::Testing::TaggedLogging
    end
  end
end

I think rspec-rails should be responsible for making sure the features of ActiveSupport::TestCase it uses works with RSpec, nor Rails that should check if its own API is existent.

I’ll take a deeper dive into this and report what I find.