rspec_pretty_html_reporter 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/LICENSE.txt +22 -0
 - data/README.md +46 -0
 - data/lib/rspec_pretty_html_reporter/example.rb +78 -0
 - data/lib/rspec_pretty_html_reporter/oopsy.rb +79 -0
 - data/lib/rspec_pretty_html_reporter.rb +165 -0
 - data/resources/bootstrap-4.0.0-dist/css/bootstrap.min.css +6 -0
 - data/resources/bootstrap-4.0.0-dist/js/bootstrap.js +3535 -0
 - data/resources/bootstrap-4.0.0-dist/js/bootstrap.min.js +7 -0
 - data/resources/bootstrap-4.0.0-dist/themes/bootstrap-theme-cerulean.min.css +12 -0
 - data/resources/bootstrap-4.0.0-dist/themes/bootstrap-theme-darkly.min.css +12 -0
 - data/resources/bootstrap-4.0.0-dist/themes/bootstrap-theme-materia.min.css +12 -0
 - data/resources/bootstrap-4.0.0-dist/themes/bootstrap-theme-spacelab.min.css +12 -0
 - data/resources/bootstrap-4.0.0-dist/themes/bootstrap-theme-yeti.min.css +12 -0
 - data/resources/js/chart-3.7.1.js +13269 -0
 - data/resources/js/jquery-1.11.1.min.js +4 -0
 - data/resources/tether-1.3.3-dist/js/tether.min.js +1 -0
 - data/templates/overview.erb +122 -0
 - data/templates/report.erb +247 -0
 - metadata +165 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: fb778b6e59fc1d897dd91626bdc82f763f32010ec6e618d10536a24fa7137260
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 28be25ab79d74a6f363700dde7a7af73953d79ce3289a4dc9a3795267b28c86b
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: c65d6d8a1f5fbe9086aa2b028b108e69503c813d8f827fc5646ef668d66e700c28a38b03e1720b2d5c18ca37eed9afec7243ac485f38e4b68be900f091a5e8b6
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: bc1ffcc7489649cab6466b0403059e258c0bb43114faa9b5e3cb9a4dff7bcb41b363f92547db592579ed8b8ce19712867e4bc6ca148f8dc68f705cde7bb5c019
         
     | 
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2022 Carlos Gutierrez
         
     | 
| 
      
 2 
     | 
    
         
            +
            Copyright (c) 2017 Vishal Banthia
         
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2014 Kingsley Hendrickse
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            [](https://badge.fury.io/rb/rspec_pretty_html_reporter)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            # RSpec Pretty HTML Reporter
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Produce pretty [RSpec](http://rspec.info/) reports.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            This is a custom reporter for RSpec which generates pretty HTML reports showing the results of rspec tests. It has
         
     | 
| 
      
 9 
     | 
    
         
            +
            features to embed images and videos into the report providing better debugging information when a test fails.
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            <img src="https://github.com/TheSpartan1980/rspec_pretty_html_reporter/blob/master/images/group_overview_report.png" width="80%"/>
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            ## Setup
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Add this to your Gemfile:
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            ```rb
         
     | 
| 
      
 18 
     | 
    
         
            +
            gem 'rspec-pretty-html-reporter'
         
     | 
| 
      
 19 
     | 
    
         
            +
            ```
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ## Generating the report
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            Either add the below into your `.rspec` file
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ```rb
         
     | 
| 
      
 26 
     | 
    
         
            +
            --format RspecPrettyHtmlReporter
         
     | 
| 
      
 27 
     | 
    
         
            +
            ```
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            or run RSpec with `--format RspecPrettyHtmlReporter` like below:
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 32 
     | 
    
         
            +
            REPORT_PATH=reports/$(date +%s) bundle exec rspec --format RspecPrettyHtmlReporter spec
         
     | 
| 
      
 33 
     | 
    
         
            +
            ```
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            This will create the reports in the `reports` directory.
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            Images and videos can be embed by adding their path into example's metadata. For an example of how to do this, please
         
     | 
| 
      
 40 
     | 
    
         
            +
            check out this [Sample Test](./spec/embed_graphics_spec.rb).
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ## Credits
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            This library is forked from [vbanthia/rspec_html_reporter](https://github.com/vbanthia/rspec_html_reporter). The
         
     | 
| 
      
 45 
     | 
    
         
            +
            original credit goes to *[kingsleyh](https://github.com/kingsleyh)*
         
     | 
| 
      
 46 
     | 
    
         
            +
            for [kingsleyh/rspec_reports_formatter](https://github.com/kingsleyh/rspec_reports_formatter)
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rspec_pretty_html_reporter/oopsy'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class Example
         
     | 
| 
      
 4 
     | 
    
         
            +
              def self.load_spec_comments!(examples)
         
     | 
| 
      
 5 
     | 
    
         
            +
                examples.group_by(&:file_path).each do |file_path, file_examples|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  lines = File.readlines(file_path)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  file_examples.zip(file_examples.rotate).each do |ex, next_ex|
         
     | 
| 
      
 9 
     | 
    
         
            +
                    lexically_next = next_ex &&
         
     | 
| 
      
 10 
     | 
    
         
            +
                      next_ex.file_path == ex.file_path &&
         
     | 
| 
      
 11 
     | 
    
         
            +
                      next_ex.metadata[:line_number] > ex.metadata[:line_number]
         
     | 
| 
      
 12 
     | 
    
         
            +
                    start_line_idx = ex.metadata[:line_number] - 1
         
     | 
| 
      
 13 
     | 
    
         
            +
                    next_start_idx = (lexically_next ? next_ex.metadata[:line_number] : lines.size) - 1
         
     | 
| 
      
 14 
     | 
    
         
            +
                    spec_lines = lines[start_line_idx...next_start_idx].select { |l| l.match(/#->/) }
         
     | 
| 
      
 15 
     | 
    
         
            +
                    ex.set_spec(spec_lines.join) unless spec_lines.empty?
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              attr_reader :example_group, :description, :full_description, :run_time, :duration, :status, :exception, :file_path,
         
     | 
| 
      
 21 
     | 
    
         
            +
                          :metadata, :spec, :screenshots, :screenrecord, :failed_screenshot
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              def initialize(example)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                @example_group = example.example_group.to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
                @description = example.description
         
     | 
| 
      
 27 
     | 
    
         
            +
                @full_description = example.full_description
         
     | 
| 
      
 28 
     | 
    
         
            +
                @execution_result = example.execution_result
         
     | 
| 
      
 29 
     | 
    
         
            +
                @run_time = (@execution_result.run_time).round(5)
         
     | 
| 
      
 30 
     | 
    
         
            +
                @duration = @execution_result.run_time.to_fs(:rounded, precision: 5)
         
     | 
| 
      
 31 
     | 
    
         
            +
                @status = @execution_result.status.to_s
         
     | 
| 
      
 32 
     | 
    
         
            +
                @metadata = example.metadata
         
     | 
| 
      
 33 
     | 
    
         
            +
                @file_path = @metadata[:file_path]
         
     | 
| 
      
 34 
     | 
    
         
            +
                @exception = Oopsy.new(example, @file_path)
         
     | 
| 
      
 35 
     | 
    
         
            +
                @spec = nil
         
     | 
| 
      
 36 
     | 
    
         
            +
                @screenshots = @metadata[:screenshots]
         
     | 
| 
      
 37 
     | 
    
         
            +
                @screenrecord = @metadata[:screenrecord]
         
     | 
| 
      
 38 
     | 
    
         
            +
                @failed_screenshot = @metadata[:failed_screenshot]
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def example_title
         
     | 
| 
      
 42 
     | 
    
         
            +
                title_arr = @example_group.to_s.split('::') - %w[RSpec ExampleGroups]
         
     | 
| 
      
 43 
     | 
    
         
            +
                title_arr.push @description
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                title_arr.join(' → ')
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              def has_exception?
         
     | 
| 
      
 49 
     | 
    
         
            +
                !@exception.klass.nil?
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              def has_spec?
         
     | 
| 
      
 53 
     | 
    
         
            +
                !@spec.nil?
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              def has_screenshots?
         
     | 
| 
      
 57 
     | 
    
         
            +
                !@screenshots.nil? && !@screenshots.empty?
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              def has_screenrecord?
         
     | 
| 
      
 61 
     | 
    
         
            +
                !@screenrecord.nil?
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              def has_failed_screenshot?
         
     | 
| 
      
 65 
     | 
    
         
            +
                !@failed_screenshot.nil?
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              def set_spec(spec_text)
         
     | 
| 
      
 69 
     | 
    
         
            +
                formatter = Rouge::Formatters::HTMLLegacy.new(css_class: 'highlight')
         
     | 
| 
      
 70 
     | 
    
         
            +
                lexer = Rouge::Lexers::Gherkin.new
         
     | 
| 
      
 71 
     | 
    
         
            +
                @spec = formatter.format(lexer.lex(spec_text.gsub('#->', '')))
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def klass(prefix = 'badge-')
         
     | 
| 
      
 75 
     | 
    
         
            +
                class_map = { passed: "#{prefix}success", failed: "#{prefix}danger", pending: "#{prefix}warning" }
         
     | 
| 
      
 76 
     | 
    
         
            +
                class_map[@status.to_sym]
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,79 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rbconfig'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rspec/core/formatters/base_formatter'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rouge'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            class Oopsy
         
     | 
| 
      
 6 
     | 
    
         
            +
              attr_reader :klass, :message, :backtrace, :highlighted_source, :explanation, :backtrace_message
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              def initialize(example, file_path)
         
     | 
| 
      
 9 
     | 
    
         
            +
                @example = example
         
     | 
| 
      
 10 
     | 
    
         
            +
                @exception = @example.exception
         
     | 
| 
      
 11 
     | 
    
         
            +
                @file_path = file_path
         
     | 
| 
      
 12 
     | 
    
         
            +
                unless @exception.nil?
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @klass = @exception.class
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @message = @exception.message.encode('utf-8')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @backtrace = @exception.backtrace
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @backtrace_message = formatted_backtrace(@example, @exception)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @highlighted_source = process_source
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @explanation = process_message
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              private
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def os
         
     | 
| 
      
 25 
     | 
    
         
            +
                @os ||= begin
         
     | 
| 
      
 26 
     | 
    
         
            +
                          host_os = RbConfig::CONFIG['host_os']
         
     | 
| 
      
 27 
     | 
    
         
            +
                          case host_os
         
     | 
| 
      
 28 
     | 
    
         
            +
                          when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
         
     | 
| 
      
 29 
     | 
    
         
            +
                            :windows
         
     | 
| 
      
 30 
     | 
    
         
            +
                          when /darwin|mac os/
         
     | 
| 
      
 31 
     | 
    
         
            +
                            :macosx
         
     | 
| 
      
 32 
     | 
    
         
            +
                          when /linux/
         
     | 
| 
      
 33 
     | 
    
         
            +
                            :linux
         
     | 
| 
      
 34 
     | 
    
         
            +
                          when /solaris|bsd/
         
     | 
| 
      
 35 
     | 
    
         
            +
                            :unix
         
     | 
| 
      
 36 
     | 
    
         
            +
                          else
         
     | 
| 
      
 37 
     | 
    
         
            +
                            raise StandardError, "unknown os: #{host_os.inspect}"
         
     | 
| 
      
 38 
     | 
    
         
            +
                          end
         
     | 
| 
      
 39 
     | 
    
         
            +
                        end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              def formatted_backtrace(example, exception)
         
     | 
| 
      
 43 
     | 
    
         
            +
                # To avoid an error in format_backtrace. RSpec's version below v3.5 will throw exception.
         
     | 
| 
      
 44 
     | 
    
         
            +
                return [] unless example
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                formatter = RSpec.configuration.backtrace_formatter
         
     | 
| 
      
 47 
     | 
    
         
            +
                formatter.format_backtrace(exception.backtrace, example.metadata)
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def process_source
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                return '' if @backtrace_message.empty?
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                data = @backtrace_message.first.split(':')
         
     | 
| 
      
 55 
     | 
    
         
            +
                unless data.empty?
         
     | 
| 
      
 56 
     | 
    
         
            +
                  if os == :windows
         
     | 
| 
      
 57 
     | 
    
         
            +
                    file_path = "#{data[0]}:#{data[1]}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                    line_number = data[2].to_i
         
     | 
| 
      
 59 
     | 
    
         
            +
                  else
         
     | 
| 
      
 60 
     | 
    
         
            +
                    file_path = data.first
         
     | 
| 
      
 61 
     | 
    
         
            +
                    line_number = data[1].to_i
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  lines = File.readlines(file_path)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  start_line = line_number - 2
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end_line = line_number + 3
         
     | 
| 
      
 66 
     | 
    
         
            +
                  source = lines[start_line..end_line].join('').sub(lines[line_number - 1].chomp, "--->#{lines[line_number - 1].chomp}")
         
     | 
| 
      
 67 
     | 
    
         
            +
                  formatter = Rouge::Formatters::HTMLLegacy.new(css_class: 'highlight', line_numbers: true, start_line: start_line + 1)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  lexer = Rouge::Lexers::Ruby.new
         
     | 
| 
      
 69 
     | 
    
         
            +
                  original_format = formatter.format(lexer.lex(source.encode('utf-8')))
         
     | 
| 
      
 70 
     | 
    
         
            +
                  original_format.gsub!(/<table class="rouge-table">/, '<table class="rouge-table" style="width:100%">')
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def process_message
         
     | 
| 
      
 75 
     | 
    
         
            +
                formatter = Rouge::Formatters::HTMLLegacy.new(css_class: 'highlight pl-3')
         
     | 
| 
      
 76 
     | 
    
         
            +
                lexer = Rouge::Lexers::Ruby.new
         
     | 
| 
      
 77 
     | 
    
         
            +
                formatter.format(lexer.lex(@message))
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,165 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'active_support/core_ext/numeric'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'active_support/inflector'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'erb'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'rspec_pretty_html_reporter/example'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            I18n.enforce_available_locales = false
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            class RspecPrettyHtmlReporter < RSpec::Core::Formatters::BaseFormatter
         
     | 
| 
      
 13 
     | 
    
         
            +
              DEFAULT_REPORT_PATH = File.join(Bundler.root, 'reports', Time.now.strftime('%Y%m%d-%H%M%S'))
         
     | 
| 
      
 14 
     | 
    
         
            +
              REPORT_PATH = ENV['REPORT_PATH'] || DEFAULT_REPORT_PATH
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              SCREENRECORD_DIR = File.join(REPORT_PATH, 'screenrecords')
         
     | 
| 
      
 17 
     | 
    
         
            +
              SCREENSHOT_DIR = File.join(REPORT_PATH, 'screenshots')
         
     | 
| 
      
 18 
     | 
    
         
            +
              RESOURCE_DIR = File.join(REPORT_PATH, 'resources')
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_pending,
         
     | 
| 
      
 21 
     | 
    
         
            +
                                               :example_group_finished
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              def initialize(_io_standard_out)
         
     | 
| 
      
 24 
     | 
    
         
            +
                create_reports_dir
         
     | 
| 
      
 25 
     | 
    
         
            +
                create_screenshots_dir
         
     | 
| 
      
 26 
     | 
    
         
            +
                create_screenrecords_dir
         
     | 
| 
      
 27 
     | 
    
         
            +
                copy_resources
         
     | 
| 
      
 28 
     | 
    
         
            +
                @all_groups = {}
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                @group_level = 0
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def example_group_started(_notification)
         
     | 
| 
      
 34 
     | 
    
         
            +
                if @group_level.zero?
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @example_group = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @examples = []
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @group_example_count = 0
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @group_example_success_count = 0
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @group_example_failure_count = 0
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @group_example_pending_count = 0
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                @group_level += 1
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              def example_started(_notification)
         
     | 
| 
      
 47 
     | 
    
         
            +
                @group_example_count += 1
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def example_passed(notification)
         
     | 
| 
      
 51 
     | 
    
         
            +
                # require 'byebug'; byebug
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                @group_example_success_count += 1
         
     | 
| 
      
 54 
     | 
    
         
            +
                @examples << Example.new(notification.example)
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              def example_failed(notification)
         
     | 
| 
      
 58 
     | 
    
         
            +
                @group_example_failure_count += 1
         
     | 
| 
      
 59 
     | 
    
         
            +
                @examples << Example.new(notification.example)
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              def example_pending(notification)
         
     | 
| 
      
 63 
     | 
    
         
            +
                @group_example_pending_count += 1
         
     | 
| 
      
 64 
     | 
    
         
            +
                @examples << Example.new(notification.example)
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              def example_group_finished(notification)
         
     | 
| 
      
 68 
     | 
    
         
            +
                @group_level -= 1
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                if @group_level.zero?
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  File.open("#{REPORT_PATH}/#{notification.group.description.parameterize}.html", 'w') do |f|
         
     | 
| 
      
 73 
     | 
    
         
            +
                    @passed = @group_example_success_count
         
     | 
| 
      
 74 
     | 
    
         
            +
                    @failed = @group_example_failure_count
         
     | 
| 
      
 75 
     | 
    
         
            +
                    @pending = @group_example_pending_count
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    duration_values = @examples.map(&:run_time)
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    duration_keys = duration_values.size.times.to_a
         
     | 
| 
      
 80 
     | 
    
         
            +
                    if (duration_values.size < 2) && duration_values.size.positive?
         
     | 
| 
      
 81 
     | 
    
         
            +
                      duration_values.unshift(duration_values.first)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      duration_keys = duration_keys << 1
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    @title = notification.group.description
         
     | 
| 
      
 86 
     | 
    
         
            +
                    @durations = duration_keys.zip(duration_values)
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    @summary_duration = duration_values.inject(0) { |sum, i| sum + i }.to_fs(:rounded, precision: 5)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    Example.load_spec_comments!(@examples)
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    @total_group_examples = @passed + @failed + @pending
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    class_map = { passed: 'success', failed: 'danger', pending: 'warning' }
         
     | 
| 
      
 95 
     | 
    
         
            +
                    statuses = @examples.map(&:status)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    @status = if statuses.include?('failed')
         
     | 
| 
      
 97 
     | 
    
         
            +
                                'failed'
         
     | 
| 
      
 98 
     | 
    
         
            +
                              else
         
     | 
| 
      
 99 
     | 
    
         
            +
                                (statuses.include?('passed') ? 'passed' : 'pending')
         
     | 
| 
      
 100 
     | 
    
         
            +
                              end
         
     | 
| 
      
 101 
     | 
    
         
            +
                    @all_groups[notification.group.description.parameterize] = {
         
     | 
| 
      
 102 
     | 
    
         
            +
                      group: notification.group.description,
         
     | 
| 
      
 103 
     | 
    
         
            +
                      examples: @examples.size,
         
     | 
| 
      
 104 
     | 
    
         
            +
                      status: @status,
         
     | 
| 
      
 105 
     | 
    
         
            +
                      klass: class_map[@status.to_sym],
         
     | 
| 
      
 106 
     | 
    
         
            +
                      passed: statuses.select { |s| s == 'passed' },
         
     | 
| 
      
 107 
     | 
    
         
            +
                      failed: statuses.select { |s| s == 'failed' },
         
     | 
| 
      
 108 
     | 
    
         
            +
                      pending: statuses.select { |s| s == 'pending' },
         
     | 
| 
      
 109 
     | 
    
         
            +
                      duration: @summary_duration
         
     | 
| 
      
 110 
     | 
    
         
            +
                    }
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    @example_status = @all_groups[notification.group.description.parameterize][:klass]
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                    template_file = File.read("#{File.dirname(__FILE__)}/../templates/report.erb")
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    f.puts ERB.new(template_file).result(binding)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
              end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
              def close(notification)
         
     | 
| 
      
 122 
     | 
    
         
            +
                File.open("#{REPORT_PATH}/overview.html", 'w') do |f|
         
     | 
| 
      
 123 
     | 
    
         
            +
                  @overview = @all_groups
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  @passed = @overview.values.map { |g| g[:passed].size }.inject(0) { |sum, i| sum + i }
         
     | 
| 
      
 126 
     | 
    
         
            +
                  @failed = @overview.values.map { |g| g[:failed].size }.inject(0) { |sum, i| sum + i }
         
     | 
| 
      
 127 
     | 
    
         
            +
                  @pending = @overview.values.map { |g| g[:pending].size }.inject(0) { |sum, i| sum + i }
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  duration_values = @overview.values.map { |e| e[:duration] }
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  duration_keys = duration_values.size.times.to_a
         
     | 
| 
      
 132 
     | 
    
         
            +
                  if duration_values.size < 2
         
     | 
| 
      
 133 
     | 
    
         
            +
                    duration_values.unshift(duration_values.first)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    duration_keys = duration_keys << 1
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  @durations = duration_keys.zip(duration_values.map { |d| d.to_f.round(5) })
         
     | 
| 
      
 138 
     | 
    
         
            +
                  @summary_duration = duration_values.map do |d|
         
     | 
| 
      
 139 
     | 
    
         
            +
                    d.to_f.round(5)
         
     | 
| 
      
 140 
     | 
    
         
            +
                  end.inject(0) { |sum, i| sum + i }.to_fs(:rounded, precision: 5)
         
     | 
| 
      
 141 
     | 
    
         
            +
                  @total_examples = @passed + @failed + @pending
         
     | 
| 
      
 142 
     | 
    
         
            +
                  template_file = File.read("#{File.dirname(__FILE__)}/../templates/overview.erb")
         
     | 
| 
      
 143 
     | 
    
         
            +
                  f.puts ERB.new(template_file).result(binding)
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
              end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
              private
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
              def create_reports_dir
         
     | 
| 
      
 150 
     | 
    
         
            +
                FileUtils.rm_rf(REPORT_PATH) if File.exist?(REPORT_PATH)
         
     | 
| 
      
 151 
     | 
    
         
            +
                FileUtils.mkpath(REPORT_PATH)
         
     | 
| 
      
 152 
     | 
    
         
            +
              end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
              def create_screenshots_dir
         
     | 
| 
      
 155 
     | 
    
         
            +
                FileUtils.mkdir_p SCREENSHOT_DIR unless File.exist?(SCREENSHOT_DIR)
         
     | 
| 
      
 156 
     | 
    
         
            +
              end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
              def create_screenrecords_dir
         
     | 
| 
      
 159 
     | 
    
         
            +
                FileUtils.mkdir_p SCREENRECORD_DIR unless File.exist?(SCREENRECORD_DIR)
         
     | 
| 
      
 160 
     | 
    
         
            +
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
              def copy_resources
         
     | 
| 
      
 163 
     | 
    
         
            +
                FileUtils.cp_r("#{File.dirname(__FILE__)}/../resources", REPORT_PATH)
         
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
            end
         
     |