How to give multiple strings to the Rspec stdout matcher?

Viewed 1736

I have some rspec tests to check the output of a command.

Previously, I was mocking the entire $stdout.string and I could do this:

  expect($stdout.string).to include 'DEBUG -- : Request Headers:'
  expect($stdout.string).to include 'Bearer foo'
  expect($stdout.string).to include 'Some other thing'

I'm refactoring this to switch to the rspec output(arg).to_stdout method.

However, looking at the docs, it only seems to allow giving a string or a regex:

RSpec.describe "output.to_stdout matcher" do
  specify { expect { print('foo') }.to output.to_stdout }
  specify { expect { print('foo') }.to output('foo').to_stdout }
  specify { expect { print('foo') }.to output(/foo/).to_stdout }

I tried chaining expectations and it didn't work:

expect { print 'foo bar baz' }.to output(/foo/).to_stdout.and output(/bar/).to_stdout.and output(/baz/).to_stdout

Gives result:

 Failure/Error: expect { print 'foo bar baz' }.to output(/foo/).to_stdout.and output(/bar/).to_stdout.and output(/baz/).to_stdout

      expected block to output /bar/ to stdout, but output nothing

   ...and:

      expected block to output /baz/ to stdout, but output nothing

Is there a way to give an array of expected strings?

2 Answers

As you seem to have found out already, output doesn't allow you to chain or compose, but you can capture the expect block and run multiple tests on it.

it 'verifies hello world' do
  expectation = expect { puts 'hello'; puts 'world' }
  expectation.to output(/hello/).to_stdout
  expectation.to output(/world/).to_stdout
end

The matcher passed to output can be any matcher, this lets you move your chained .and composition inside using the match matcher:

expect { print 'foo bar baz' }.to output( match(/foo/).and match(/bar/).and match(/baz/) ).to_stdout 

Or closer to your original example include can take a list of strings:

expect { print 'foo bar baz' }.to output(include('foo', 'bar', 'baz')).to_stdout 
Related