4
votes

This question tells me how to test logger statements from RSpec model and controller specs. Unfortunately, it doesn't seem to work from a feature spec. With this code:

# controller.rb
def action
  logger.info 'foobar'
end

# spec.rb
scenario 'logging should work' do
  expect(Rails.logger).to receive(:info).with('foobar')
  visit action_path
end

I get the error:

 Failure/Error: visit action_path
   #<ActiveSupport::Logger:0x007ff45b6e5ad0> received :info with unexpected arguments
     expected: ("foobar")
          got: (no args)

The test.log file does not contain foobar, so it seems the test is failing immediately, before the controller action has a chance to complete.

Is there some way to use this expect(Rails.logger) syntax in a feature spec?

1
Any answers here?mooreds
This answer may be of use: stackoverflow.com/questions/11770552/…mooreds

1 Answers

2
votes

The Rails.logger.info method can take a string or a block. If you're invoking the block form then it will give this "got: (no args)" output.

For example

logger.info 'foobar'

...all on one line will call .info with a string, but if you do

logger.info
  "foobar foobar longer message so I'll put it on its own line"

split across two lines without brackets, then you're actually passing a block. Add some brackets...

logger.info(
  "foobar foobar longer message so I'll put it on its own line"
)

...and you're back to a string.

He says knowingly after bashing his head on this problem for a few hours :-)

Before realising that, I started figuring out how to mock the Rails.logger class. That might be a useful approach for you or others. Maybe you're calling with a block for some other reason (something to do with feature vs controller specs?), or maybe you can't change the calling code, in which case... something like this might be a useful starting point:

class LoggerMock < Object
  def initialize; end

  def info(progname = nil, &block)
    mock_info(block.call)
  end
end

and

logger_mock = LoggerMock.new
allow(Rails).to receive(:logger).and_return(logger_mock)
expect(logger_mock).to receive(:mock_info).with('foobar')