File: screenshot_helper.rb

package info (click to toggle)
rails 2%3A7.2.2.1%2Bdfsg-7
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 43,352 kB
  • sloc: ruby: 349,799; javascript: 30,703; yacc: 46; sql: 43; sh: 29; makefile: 27
file content (164 lines) | stat: -rw-r--r-- 5,359 bytes parent folder | download | duplicates (2)
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
# frozen_string_literal: true

# :markup: markdown

module ActionDispatch
  module SystemTesting
    module TestHelpers
      # Screenshot helper for system testing.
      module ScreenshotHelper
        # Takes a screenshot of the current page in the browser.
        #
        # `take_screenshot` can be used at any point in your system tests to take a
        # screenshot of the current state. This can be useful for debugging or
        # automating visual testing. You can take multiple screenshots per test to
        # investigate changes at different points during your test. These will be named
        # with a sequential prefix (or 'failed' for failing tests)
        #
        # The default screenshots directory is `tmp/screenshots` but you can set a
        # different one with `Capybara.save_path`
        #
        # You can use the `html` argument or set the
        # `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` environment variable to save the HTML
        # from the page that is being screenshotted so you can investigate the elements
        # on the page at the time of the screenshot
        #
        # You can use the `screenshot` argument or set the
        # `RAILS_SYSTEM_TESTING_SCREENSHOT` environment variable to control the output.
        # Possible values are:
        #     `simple` (default)
        # :       Only displays the screenshot path. This is the default value.
        #
        #     `inline`
        # :       Display the screenshot in the terminal using the iTerm image protocol
        #         (https://iterm2.com/documentation-images.html).
        #
        #     `artifact`
        # :       Display the screenshot in the terminal, using the terminal artifact
        #         format (https://buildkite.github.io/terminal-to-html/inline-images/).
        #
        #
        def take_screenshot(html: false, screenshot: nil)
          showing_html = html || html_from_env?

          increment_unique
          save_html if showing_html
          save_image
          show display_image(html: showing_html, screenshot_output: screenshot)
        end

        # Takes a screenshot of the current page in the browser if the test failed.
        #
        # `take_failed_screenshot` is called during system test teardown.
        def take_failed_screenshot
          return unless failed? && supports_screenshot? && Capybara::Session.instance_created?

          take_screenshot
          metadata[:failure_screenshot_path] = relative_image_path if Minitest::Runnable.method_defined?(:metadata)
        end

        private
          attr_accessor :_screenshot_counter

          def html_from_env?
            ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] == "1"
          end

          def increment_unique
            @_screenshot_counter ||= 0
            @_screenshot_counter += 1
          end

          def unique
            failed? ? "failures" : (_screenshot_counter || 0).to_s
          end

          def image_name
            sanitized_method_name = method_name.gsub(/[^\w]+/, "-")
            name = "#{unique}_#{sanitized_method_name}"
            name[0...225]
          end

          def image_path
            absolute_image_path.to_s
          end

          def html_path
            absolute_html_path.to_s
          end

          def absolute_path
            Rails.root.join(screenshots_dir, image_name)
          end

          def screenshots_dir
            Capybara.save_path.presence || "tmp/screenshots"
          end

          def absolute_image_path
            "#{absolute_path}.png"
          end

          def relative_image_path
            "#{absolute_path.relative_path_from(Rails.root)}.png"
          end

          def absolute_html_path
            "#{absolute_path}.html"
          end

          # rubocop:disable Lint/Debugger
          def save_html
            page.save_page(absolute_html_path)
          end

          def save_image
            page.save_screenshot(absolute_image_path)
          end
          # rubocop:enable Lint/Debugger

          def output_type
            # Environment variables have priority
            output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"]

            # Default to outputting a path to the screenshot
            output_type ||= "simple"

            output_type
          end

          def show(img)
            puts img
          end

          def display_image(html:, screenshot_output:)
            message = +"[Screenshot Image]: #{image_path}\n"
            message << +"[Screenshot HTML]: #{html_path}\n" if html

            case screenshot_output || output_type
            when "artifact"
              message << "\e]1338;url=artifact://#{absolute_image_path}\a\n"
            when "inline"
              name = inline_base64(File.basename(absolute_image_path))
              image = inline_base64(File.read(absolute_image_path))
              message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n"
            end

            message
          end

          def inline_base64(path)
            Base64.strict_encode64(path)
          end

          def failed?
            !passed? && !skipped?
          end

          def supports_screenshot?
            Capybara.current_driver != :rack_test
          end
      end
    end
  end
end