File: system_example_group.rb

package info (click to toggle)
ruby-rspec-rails 8.0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,804 kB
  • sloc: ruby: 10,881; sh: 198; makefile: 6
file content (177 lines) | stat: -rw-r--r-- 5,435 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
module RSpec
  module Rails
    # @api public
    # Container class for system tests
    module SystemExampleGroup
      extend ActiveSupport::Concern
      include RSpec::Rails::RailsExampleGroup
      include RSpec::Rails::Matchers::RedirectTo
      include RSpec::Rails::Matchers::RenderTemplate
      include ActionDispatch::Integration::Runner
      include ActionDispatch::Assertions
      include ActionController::TemplateAssertions

      # Special characters to translate into underscores for #method_name
      CHARS_TO_TRANSLATE = ['/', '.', ':', ',', "'", '"', " "].freeze

      # @private
      module BlowAwayTeardownHooks
        # @private
        def before_teardown
        end

        # @private
        def after_teardown
        end
      end

      # for the SystemTesting Screenshot situation
      def passed?
        return false if RSpec.current_example.exception
        return true unless defined?(::RSpec::Expectations::FailureAggregator)

        failure_notifier = ::RSpec::Support.failure_notifier
        return true unless failure_notifier.is_a?(::RSpec::Expectations::FailureAggregator)

        failure_notifier.failures.empty? && failure_notifier.other_errors.empty?
      end

      # @private
      def method_name
        @method_name ||= [
          self.class.name.underscore,
          RSpec.current_example.description.underscore
        ].join("_").tr(CHARS_TO_TRANSLATE.join, "_").byteslice(0...200).scrub("") + "_#{rand(1000)}"
      end

      # @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

      # Delegates to `Rails.application`.
      def app
        ::Rails.application
      end

      # Default driver to assign if none specified.
      DEFAULT_DRIVER = :selenium_chrome_headless

      included do |other|
        ActiveSupport.on_load(:action_dispatch_system_test_case) do
          ActionDispatch::SystemTesting::Server.silence_puma = true
        end

        require 'action_dispatch/system_test_case'

        begin
          require 'capybara'
        rescue LoadError => e
          abort """
            LoadError: #{e.message}
            System test integration has a hard
            dependency on a webserver and `capybara`, please add capybara to
            your Gemfile and configure a webserver (e.g. `Capybara.server =
            :puma`) before attempting to use system specs.
          """.gsub(/\s+/, ' ').strip
        end

        original_before_teardown =
          ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:before_teardown)

        original_after_teardown =
          ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:after_teardown)

        other.include ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown
        other.include ::ActionDispatch::SystemTesting::TestHelpers::ScreenshotHelper
        other.include BlowAwayTeardownHooks

        attr_reader :driver

        if ActionDispatch::SystemTesting::Server.respond_to?(:silence_puma=)
          ActionDispatch::SystemTesting::Server.silence_puma = true
        end

        def initialize(*args, &blk)
          super(*args, &blk)
          @driver = nil

          self.class.before do
            # A user may have already set the driver, so only default if driver
            # is not set
            driven_by(DEFAULT_DRIVER) unless @driver
          end
        end

        def driven_by(driver, **driver_options, &blk)
          @driver = ::ActionDispatch::SystemTestCase.driven_by(driver, **driver_options, &blk).tap(&:use)
        end

        def served_by(**options)
          ::ActionDispatch::SystemTestCase.served_by(**options)
        end

        before do
          @routes = ::Rails.application.routes
        end

        after do
          orig_stdout = $stdout
          $stdout = StringIO.new
          begin
            original_before_teardown.bind(self).call
          ensure
            myio = $stdout
            myio.rewind
            RSpec.current_example.metadata[:extra_failure_lines] = myio.readlines
            $stdout = orig_stdout
          end
        end

        around do |example|
          example.run
          original_after_teardown.bind(self).call
        end
      end
    end
  end
end