Skip to content

Commit 387229d

Browse files
authored
Captures proc output instead of calling it (#17)
1 parent de59572 commit 387229d

5 files changed

Lines changed: 83 additions & 12 deletions

File tree

demo.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,8 @@ def initialize
414414
"Custom Messages" => ["custom failure message", "custom message with block"],
415415
"Complex Objects" => ["struct comparison", "custom class object comparison", "test with metadata", "custom object with many instance variables"],
416416
"Fuzzy Matchers" => ["a_string_matching", "a_hash_including", "a_collection_containing_exactly", "an_instance_of", "include with hash conditions"],
417-
"Yield Matchers" => ["yield_control", "yield_with_args"]
417+
"Yield Matchers" => ["yield_control", "yield_with_args"],
418+
"Output Matchers" => ["output to stdout", "output to stderr"]
418419
}
419420

420421
categories.each do |category, descriptions|

lib/rspec/enriched_json/expectation_helper_wrapper.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require "oj"
55
require "rspec/expectations"
66
require "rspec/support/differ"
7+
require "stringio"
78

89
module RSpec
910
module EnrichedJson
@@ -46,7 +47,15 @@ def serialize_value(value)
4647
if value.is_a?(Regexp)
4748
return Oj.dump(value.inspect, mode: :compat)
4849
elsif value.is_a?(Proc)
49-
return value.call
50+
original_stdout = $stdout
51+
$stdout = StringIO.new
52+
53+
value.call
54+
55+
output = $stdout.string
56+
$stdout = original_stdout
57+
58+
return output
5059
end
5160

5261
Oj.dump(value, OJ_OPTIONS)

lib/rspec/enriched_json/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module RSpec
44
module EnrichedJson
5-
VERSION = "0.8.2"
5+
VERSION = "0.8.3"
66
end
77
end

spec/oj_serialization_spec.rb

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,6 @@
4242
expect(result).to eq("/http:\\/\\/example\\.com/")
4343
end
4444
end
45-
46-
describe "serialization of Proc objects" do
47-
it "calls a simple Proc" do
48-
helloworld = proc { "Hello, world!" }
49-
result = serializer.serialize_value(helloworld)
50-
expect(result).to eq("Hello, world!")
51-
end
52-
end
53-
5445
describe "Fallback behavior for errors" do
5546
it "uses fallback format when Oj.dump fails" do
5647
# Create an object that we'll mock to fail

spec/stdout_matcher_spec.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
RSpec.describe "Stdout matcher value capture" do
6+
let(:formatter) { RSpec::EnrichedJson::Formatters::EnrichedJsonFormatter.new(StringIO.new) }
7+
8+
# Use the same Oj options for loading that we use for dumping
9+
let(:oj_load_options) do
10+
{
11+
mode: :object,
12+
symbol_keys: true,
13+
auto_define: false,
14+
create_additions: false
15+
}
16+
end
17+
18+
it "captures actual when spec passes" do
19+
test_file = "spec/support/stdout_passing_spec.rb"
20+
File.write(test_file, <<~RUBY)
21+
RSpec.describe "Test" do
22+
it "checks output" do
23+
expect { puts "Hello" }.to output("Hello\\n").to_stdout
24+
end
25+
end
26+
RUBY
27+
28+
output = run_rspec(test_file)
29+
json = Oj.load(output)
30+
example = json["examples"].first
31+
32+
expect(example["details"]["expected"]).to eq("\"Hello\\n\"")
33+
expect(example["details"]["actual"]).to eq("Hello\n")
34+
ensure
35+
File.delete(test_file) if File.exist?(test_file)
36+
end
37+
38+
it "captures actual when spec fails" do
39+
test_file = "spec/support/stdout_passing_spec.rb"
40+
File.write(test_file, <<~RUBY)
41+
RSpec.describe "Test" do
42+
it "checks output" do
43+
expect { puts "Hello" }.to output("Bye\\n").to_stdout
44+
end
45+
end
46+
RUBY
47+
48+
output = run_rspec(test_file)
49+
json = Oj.load(output)
50+
example = json["examples"].first
51+
52+
expect(example["details"]["expected"]).to eq("\"Bye\\n\"")
53+
expect(example["details"]["actual"]).to eq("\"Hello\\n\"")
54+
ensure
55+
File.delete(test_file) if File.exist?(test_file)
56+
end
57+
58+
private
59+
60+
def run_rspec(test_file)
61+
output = nil
62+
Dir.mktmpdir do |dir|
63+
output_file = File.join(dir, "output.json")
64+
cmd = "bundle exec rspec #{test_file} --format RSpec::EnrichedJson::Formatters::EnrichedJsonFormatter --out #{output_file} 2>&1"
65+
system(cmd, out: File::NULL)
66+
output = File.read(output_file)
67+
end
68+
output
69+
end
70+
end

0 commit comments

Comments
 (0)