From f8fbbc0dfafe82281ec7bcd01c287c63845dfeab Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Tue, 14 Nov 2023 17:01:07 +0000 Subject: [PATCH] Merge pull request #2704 from rspec/fix-screenshot-meta-access Fix failure screenshots on Rails 7.1 --- .../rails/example/system_example_group.rb | 46 ++++++++++++++++++ .../example/system_example_group_spec.rb | 47 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/lib/rspec/rails/example/system_example_group.rb b/lib/rspec/rails/example/system_example_group.rb index 8e0bb5ffe..530c8976e 100644 --- a/lib/rspec/rails/example/system_example_group.rb +++ b/lib/rspec/rails/example/system_example_group.rb @@ -44,6 +44,52 @@ def method_name ].join("_").tr(CHARS_TO_TRANSLATE.join, "_").byteslice(0...200).scrub("") + "_#{rand(1000)}" end + if ::Rails::VERSION::STRING.to_f >= 7.1 + # @private + # Allows failure screenshot to work whilst not exposing metadata + 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 from within an example " \ + "(e.g. an `it` block) or from constructs that run in the " \ + "scope of an example (e.g. `before`, `let`, etc). It is " \ + "only available on an example group (e.g. a `describe` or "\ + "`context` block)" + end + end + + # @private + 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 = []