From 15c9c2d1ecd633dd20eb09166cf22487ce232ea0 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Sat, 21 Oct 2023 17:52:42 +0200 Subject: [PATCH] Fix failure screenshots on Rails 7.1 --- .../rails/example/system_example_group.rb | 43 +++++++++++++++++ .../example/system_example_group_spec.rb | 47 +++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/lib/rspec/rails/example/system_example_group.rb b/lib/rspec/rails/example/system_example_group.rb index 8e0bb5ffe..64e638f65 100644 --- a/lib/rspec/rails/example/system_example_group.rb +++ b/lib/rspec/rails/example/system_example_group.rb @@ -44,6 +44,49 @@ def method_name ].join("_").tr(CHARS_TO_TRANSLATE.join, "_").byteslice(0...200).scrub("") + "_#{rand(1000)}" end + if ::Rails::VERSION::STRING.to_f >= 7.1 + class SuppressRailsScreenshotMetadata + def initialize + @example_data = {} + end + + def [](key) + if @example_data.key?(key) + @example_data[key] + else + raise_wrong_scope_error + end + end + + def []=(key, value) + if key == :failure_screenshot_path + @example_data[key] = value + else + raise_wrong_scope_error + end + end + + def method_missing(_name, *_args, &_block) + raise_wrong_scope_error + end + + private + + def raise_wrong_scope_error + raise RSpec::Core::ExampleGroup::WrongScopeError, + "`metadata` is not available on an example group (e.g. a " \ + "`describe` or `context` block). It is only available from " \ + "within individual examples (e.g. `it` blocks) or from " \ + "constructs that run in the scope of an example (e.g. " \ + "`before`, `let`, etc)." + end + end + + def metadata + @metadata ||= SuppressRailsScreenshotMetadata.new + end + end + # Delegates to `Rails.application`. def app ::Rails.application diff --git a/spec/rspec/rails/example/system_example_group_spec.rb b/spec/rspec/rails/example/system_example_group_spec.rb index 620fe13b7..9ec977384 100644 --- a/spec/rspec/rails/example/system_example_group_spec.rb +++ b/spec/rspec/rails/example/system_example_group_spec.rb @@ -92,6 +92,53 @@ def take_screenshot end end + describe '#take_screenshot', if: ::Rails::VERSION::STRING.to_f >= 7.1 do + it 'handles Rails calling metadata' do + allow(Capybara::Session).to receive(:instance_created?).and_return(true) + group = RSpec::Core::ExampleGroup.describe do + include SystemExampleGroup + + before do + driven_by(:selenium) + end + + def page + instance_double(Capybara::Session, save_screenshot: nil) + end + end + example = group.it('fails') { raise } + group.run + + expect(example.metadata[:execution_result].exception).to be_a RuntimeError + end + end + + describe '#metadata', if: ::Rails::VERSION::STRING.to_f >= 7.1 do + let(:group) do + RSpec::Core::ExampleGroup.describe do + include SystemExampleGroup + end + end + + it 'fakes out the rails expected method' do + example = group.it('does nothing') { + metadata[:failure_screenshot_path] = :value + expect(metadata[:failure_screenshot_path]).to eq(:value) + } + group.run + expect(example.execution_result.status).to eq :passed + end + + it 'still raises correctly if you use it for something else' do + examples = [] + examples << group.it('fails nothing') { metadata[:other] = :value } + examples << group.it('fails nothing') { metadata[:other] } + examples << group.it('fails nothing') { metadata.key?(:any) } + group.run + expect(examples.map(&:execution_result)).to all have_attributes status: :failed + end + end + describe "hook order" do it 'calls Capybara.reset_sessions (TestUnit after_teardown) after any after hooks' do calls_in_order = []