├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── assets └── sample_report.png ├── bin ├── console └── setup ├── lib ├── minitest │ ├── hyper.rb │ ├── hyper │ │ ├── report.rb │ │ └── reporter.rb │ └── hyper_plugin.rb └── templates │ ├── hyper.css │ └── index.html.erb ├── minitest-hyper.gemspec └── test ├── minitest ├── hyper │ ├── report_test.rb │ └── reporter_test.rb └── hyper_test.rb ├── support ├── fake_reporter.rb └── filesystem_helpers.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | # Editor temporary files 2 | # 3 | *~ 4 | \#*\# 5 | .\#* 6 | *.swp 7 | *.swo 8 | 9 | 10 | # Other common temporary files 11 | # 12 | *.bak 13 | *.old 14 | *.orig 15 | *.rbc 16 | /tmp/* 17 | 18 | 19 | # Bundler artifacts 20 | # 21 | /.bundle/ 22 | /Gemfile.lock 23 | /vendor/bundle/ 24 | 25 | 26 | # RubyGems-related artifacts 27 | # 28 | /*.gem 29 | 30 | 31 | # Testing artifacts and temp files 32 | # 33 | /coverage/ 34 | /test/reports/ 35 | /test/tmp/ 36 | **/test/version_tmp 37 | 38 | 39 | # Documentation 40 | # 41 | /.yardoc 42 | /_yardoc/ 43 | /doc/ 44 | /rdoc/ 45 | 46 | 47 | # Keep files 48 | # 49 | !**/.gitkeep 50 | !**/.keep 51 | 52 | 53 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.2.3 4 | before_install: gem install bundler -v 1.10.6 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in minitest-hyper.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Chris Kottom 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minitest::Hyper 2 | 3 | Generates attractive, self-contained HTML reports for your Minitest runs. 4 | 5 | This gem was created as a demonstration of how to build a Minitest extension for [The Minitest Cookbook](http://chriskottom.com/minitestcookbook/). 6 | 7 | ![Sample Report](./assets/sample_report.png) 8 | 9 | ## Installation 10 | 11 | Add this line to your application's Gemfile: 12 | 13 | ```ruby 14 | gem "minitest-hyper", require: false 15 | ``` 16 | 17 | And then execute: 18 | 19 | $ bundle 20 | 21 | Or install it yourself as: 22 | 23 | $ gem install minitest-hyper 24 | 25 | ## Usage 26 | 27 | To generate reports using Minitest::Hyper, you'll need to pass the `-H` or `--html` flag to Minitest on the command line in one of the usual ways. 28 | 29 | $ ruby -H test/foo_test.rb 30 | $ TEST_OPTS="--html" rake test 31 | 32 | You can also switch on report generation globally for every test run by putting the following in your test helper: 33 | 34 | ```ruby 35 | require "minitest/hyper" 36 | ``` 37 | 38 | ## Development 39 | 40 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 41 | 42 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 43 | 44 | ## Contributing 45 | 46 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/minitest-hyper. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct. 47 | 48 | [The issue tracker for this project](https://github.com/[USERNAME]/minitest-hyper/issues) is the master list of enhancements and defects in need of repair. If you're looking to contribute, start there. 49 | 50 | ## License 51 | 52 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 53 | 54 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test" 6 | t.libs << "lib" 7 | t.test_files = FileList['test/**/*_test.rb'] 8 | end 9 | 10 | task :default => :test 11 | -------------------------------------------------------------------------------- /assets/sample_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chriskottom/minitest-hyper/1c23c68e6ac464ba1c4320b5c1ca0a2ddad2a84c/assets/sample_report.png -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "minitest/hyper" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | bundle install 6 | 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /lib/minitest/hyper.rb: -------------------------------------------------------------------------------- 1 | require "minitest/hyper_plugin" 2 | 3 | Minitest.load_plugins 4 | Minitest::Hyper.enable! 5 | -------------------------------------------------------------------------------- /lib/minitest/hyper/report.rb: -------------------------------------------------------------------------------- 1 | require "erb" 2 | require "fileutils" 3 | 4 | module Minitest 5 | module Hyper 6 | class Report 7 | attr_reader :reporter 8 | 9 | def initialize(reporter) 10 | @reporter = reporter 11 | end 12 | 13 | def write 14 | ensure_output_dir 15 | move_existing_file 16 | write_file 17 | end 18 | 19 | def url 20 | "file://#{ filename.gsub(/\\/, "/") }" 21 | end 22 | 23 | def dirname 24 | Minitest::Hyper.report_dirname 25 | end 26 | 27 | def filename 28 | Minitest::Hyper.report_filename 29 | end 30 | 31 | private 32 | 33 | def ensure_output_dir 34 | unless Dir.exist?(dirname) 35 | FileUtils.mkdir_p dirname 36 | end 37 | end 38 | 39 | def move_existing_file 40 | if File.exist?(filename) 41 | ctime = File.ctime(filename) 42 | time_str = ctime.strftime("%Y%m%d%H%M%S") 43 | new_name = filename.sub(/\.html$/, "_#{ time_str }.html") 44 | FileUtils.mv(filename, new_name) 45 | end 46 | end 47 | 48 | def write_file 49 | page_info = { 50 | title: "Minitest::Hyper Test Report", 51 | styles: css_string, 52 | timestamp: Time.now 53 | } 54 | test_info = reporter.to_h 55 | 56 | erb = ERB.new(template_string) 57 | File.open(filename, "wb") do |file| 58 | file.write erb.result(binding) 59 | end 60 | end 61 | 62 | def css_string 63 | File.read(CSS_TEMPLATE) 64 | end 65 | 66 | def template_string 67 | File.read(HTML_TEMPLATE) 68 | end 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/minitest/hyper/reporter.rb: -------------------------------------------------------------------------------- 1 | require "minitest" 2 | 3 | module Minitest 4 | module Hyper 5 | class Reporter < Minitest::StatisticsReporter 6 | attr_accessor :all_results 7 | 8 | def initialize(io = $stdout, options = {}) 9 | super 10 | self.all_results = [] 11 | end 12 | 13 | def record(result) 14 | super 15 | all_results << result 16 | end 17 | 18 | def report 19 | super 20 | @report = Report.new(self) 21 | @report.write 22 | io.puts "Wrote HTML test report to #{ @report.url }" 23 | end 24 | 25 | def to_h 26 | HashFormatter.as_hash(self) 27 | end 28 | 29 | class HashFormatter 30 | def self.as_hash(reporter) 31 | self.new(reporter).to_h 32 | end 33 | 34 | def initialize(reporter) 35 | @reporter = reporter 36 | end 37 | 38 | def reporter 39 | @reporter 40 | end 41 | 42 | def to_h 43 | { 44 | count: reporter.count, 45 | assertions: reporter.assertions, 46 | start_time: reporter.start_time, 47 | total_time: reporter.total_time, 48 | failures: reporter.failures, 49 | errors: reporter.errors, 50 | skips: reporter.skips, 51 | results: result_data(reporter.all_results), 52 | non_passing: result_data(reporter.results) 53 | } 54 | end 55 | 56 | def result_data(results) 57 | collection = [] 58 | results.each do |result| 59 | collection << { 60 | name: result.name, 61 | code: result_code(result), 62 | class: result_class(result), 63 | outcome: result_string(result), 64 | time: result.time, 65 | assertions: result.assertions, 66 | location: result.location, 67 | failure: result.failure 68 | } 69 | end 70 | collection 71 | end 72 | 73 | def result_code(result) 74 | case result.failure 75 | when Skip 76 | :skip 77 | when UnexpectedError 78 | :error 79 | when Assertion 80 | :fail 81 | else 82 | :pass 83 | end 84 | end 85 | 86 | def result_class(result) 87 | result_code(result).to_s 88 | end 89 | 90 | def result_string(result) 91 | result_code(result).to_s.capitalize 92 | end 93 | end 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /lib/minitest/hyper_plugin.rb: -------------------------------------------------------------------------------- 1 | require "minitest" 2 | 3 | require "minitest/hyper/reporter" 4 | require "minitest/hyper/report" 5 | 6 | module Minitest 7 | # Mandatory Minitest initializer hook 8 | # Detected by Minitest.load_plugins, invoked during Minitest.init_plugins 9 | def self.plugin_hyper_init(options) 10 | if Hyper.enabled? 11 | reporter.reporters << Hyper::Reporter.new(options[:io], options) 12 | end 13 | end 14 | 15 | # Optional hook for command line params handling 16 | # Invoked by Minitest.process_args 17 | def self.plugin_hyper_options(opts, options) 18 | description = "Generate an HTML test report with Minitest::Hyper" 19 | opts.on "-H", "--html", description do 20 | Hyper.enable! 21 | end 22 | end 23 | 24 | module Hyper 25 | GEM_DIR = File.join(File.dirname(__FILE__), "../..") 26 | 27 | TEMPLATE_DIR = File.join(GEM_DIR, "lib/templates") 28 | CSS_TEMPLATE = File.join(TEMPLATE_DIR, "hyper.css") 29 | HTML_TEMPLATE = File.join(TEMPLATE_DIR, "index.html.erb") 30 | 31 | VERSION = "0.2.0" 32 | 33 | @@enabled = false 34 | 35 | def self.enabled? 36 | @@enabled 37 | end 38 | 39 | def self.enable! 40 | @@enabled = true 41 | end 42 | 43 | def self.report_dirname 44 | project_root = if defined?(Rails) && defined?(Rails.root) 45 | Rails.root 46 | else 47 | Dir.pwd 48 | end 49 | 50 | if Dir.exist?(File.join(project_root, "spec")) 51 | File.join(project_root, "spec/reports/hyper") 52 | else 53 | File.join(project_root, "test/reports/hyper") 54 | end 55 | end 56 | 57 | def self.report_filename 58 | File.join(report_dirname, "index.html") 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/templates/hyper.css: -------------------------------------------------------------------------------- 1 | body { padding-top: 70px; } 2 | 3 | .row { 4 | margin-bottom: 20px; 5 | } 6 | 7 | /* 8 | * SUMMARY ROW 9 | */ 10 | #summary .widget { 11 | border: 3px solid #eef; 12 | border-radius: 10px; 13 | margin-right: 2.5%; 14 | padding: 10px; 15 | width: 18%; 16 | } 17 | 18 | #summary .widget:last-child { 19 | margin-right: 0; 20 | } 21 | 22 | #summary .counter { 23 | display: block; 24 | font-size: 4em; 25 | font-weight: bold; 26 | text-align: center; 27 | } 28 | 29 | #summary .metric { 30 | display: block; 31 | font-size: 1.1em; 32 | font-weight: bold; 33 | text-align: center; 34 | } 35 | 36 | 37 | /* 38 | * INDIVIDUAL TEST RESULTS 39 | */ 40 | #test-results { 41 | margin: 0; 42 | } 43 | 44 | #test-results .result { 45 | border: solid; 46 | border-width: 3px thin; 47 | font-size: 14px; 48 | margin-bottom: 3px; 49 | padding: 6px; 50 | width: 100%; 51 | } 52 | 53 | #test-results .result span.outcome-name, 54 | #test-results .result span.time { 55 | display: inline-block; 56 | font-size: 15px; 57 | font-weight: bold; 58 | } 59 | 60 | #test-results .result span.outcome-name { 61 | overflow: hidden; 62 | max-width: 85%; 63 | white-space: nowrap; 64 | text-overflow: ellipsis; 65 | } 66 | 67 | #test-results .result span.time { 68 | float: right; 69 | width: 15%; 70 | } 71 | 72 | #test-results .result .failure-details { 73 | clear: both; 74 | } 75 | 76 | #test-results .result.pass { 77 | background-color: #eef; 78 | border-color: green; 79 | font-color: dark-green; 80 | } 81 | 82 | #test-results .result.fail { 83 | background-color: #ffe4b2; 84 | border-color: orange; 85 | } 86 | 87 | #test-results .result.error { 88 | background-color: #fdd; 89 | border-color: red; 90 | } 91 | 92 | #test-results .result.skip { 93 | background-color: #f0f0f0; 94 | border-color: #aaa; 95 | } 96 | 97 | 98 | /* 99 | * CHARTS 100 | */ 101 | #charts h3 { 102 | margin: 0; 103 | text-align: center; 104 | } 105 | 106 | #charts canvas { 107 | display: block; 108 | height: 300px; 109 | margin: 0 auto; 110 | width: 90%; 111 | } 112 | -------------------------------------------------------------------------------- /lib/templates/index.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= page_info[:title] %> 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |
23 | <%= test_info[:count] %> 24 | Tests Run 25 |
26 |
27 | <%= test_info[:assertions] %> 28 | Assertions 29 |
30 |
31 | <%= test_info[:failures] %> 32 | Failed 33 |
34 |
35 | <%= test_info[:errors] %> 36 | Errors 37 |
38 |
39 | <%= test_info[:skips] %> 40 | Skipped 41 |
42 |
43 | 44 |
45 |

Test Results

46 | 47 |
48 | <% test_info[:results].each do |result| %> 49 |
50 | 51 | <%= result[:outcome].upcase %>: <%= result[:name] %> 52 | 53 | <%= sprintf("%.2f", result[:time] * 1000.0) %> ms 54 |
55 | <%= result[:result] %> 56 |
57 |
58 | <% end %> 59 |
60 | 61 |
62 |

Results by Type

63 | 64 |
65 |
66 |
67 |
68 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /minitest-hyper.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'minitest/hyper_plugin' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "minitest-hyper" 8 | spec.version = Minitest::Hyper::VERSION 9 | spec.authors = ["Chris Kottom"] 10 | spec.email = ["chris@chriskottom.com"] 11 | 12 | spec.summary = "Pretty HTML reports for Minitest" 13 | spec.description = "Generate attractive, single-page HTML reports for your Minitest runs" 14 | spec.homepage = "https://github.com/chriskottom/minitest-hyper" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "exe" 19 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.10" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | spec.add_development_dependency "minitest", "~> 5.8" 25 | end 26 | -------------------------------------------------------------------------------- /test/minitest/hyper/report_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | describe Minitest::Hyper::Report do 4 | include FilesystemHelpers 5 | include FilesystemHelpers::Expectations 6 | 7 | let(:reporter) { FakeReporter.new(count: 20) } 8 | let(:report) { Minitest::Hyper::Report.new(reporter) } 9 | 10 | it "has a url" do 11 | expect(report.url).wont_be_nil 12 | end 13 | 14 | describe "#write" do 15 | before do 16 | reset_reports_directory(report.dirname) 17 | end 18 | 19 | it "writes the report file" do 20 | expect(report.filename).wont_be_a_file 21 | report.write 22 | expect(report.filename).must_be_a_file 23 | end 24 | 25 | describe "when the report directory doesn't exist" do 26 | it "creates the report directory" do 27 | expect(report.dirname).wont_be_a_dir 28 | report.write 29 | expect(report.dirname).must_be_a_dir 30 | end 31 | end 32 | 33 | describe "when the report file already exists" do 34 | before do 35 | touch_report(report.filename) 36 | end 37 | 38 | let(:out_file) { report.filename } 39 | let(:time_str) { File.ctime(out_file).strftime("%Y%m%d%H%M%S") } 40 | let(:new_name) { out_file.sub(/\.html$/, "_#{ time_str }.html") } 41 | 42 | it "moves the existing file to a new location" do 43 | expect(report.filename).must_be_a_file 44 | report.write 45 | expect(report.filename).must_be_a_file 46 | expect(new_name).must_be_a_file 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /test/minitest/hyper/reporter_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | describe Minitest::Hyper::Reporter do 4 | include FilesystemHelpers 5 | include FilesystemHelpers::Expectations 6 | 7 | let(:reporter) { Minitest::Hyper::Reporter.new } 8 | 9 | before do 10 | reporter.start 11 | end 12 | 13 | describe "#record" do 14 | it "stores all results, not just interesting results" do 15 | expect(reporter.all_results).must_be_empty 16 | reporter.record self 17 | expect(reporter.all_results.count).must_equal 1 18 | end 19 | end 20 | 21 | describe "#report" do 22 | let(:report_dir) { Minitest::Hyper.report_dirname } 23 | let(:report_file) { Minitest::Hyper.report_filename } 24 | 25 | before do 26 | reset_reports_directory(report_dir) 27 | end 28 | 29 | it "writes the report file" do 30 | expect(report_file).wont_be_a_file 31 | capture_subprocess_io do 32 | reporter.report 33 | end 34 | expect(report_file).must_be_a_file 35 | end 36 | 37 | it "writes the report URL to the console" do 38 | regexp = %r{Wrote HTML test report to file://#{ report_file }} 39 | out, err = capture_subprocess_io do 40 | reporter.report 41 | end 42 | expect(out).must_match regexp 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /test/minitest/hyper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require "fileutils" 3 | require "ostruct" 4 | 5 | describe Minitest::Hyper do 6 | it "has a version" do 7 | expect(Minitest::Hyper::VERSION).wont_be_nil 8 | end 9 | 10 | it "can be enabled" do 11 | Minitest::Hyper.class_variable_set(:@@enabled, false) 12 | Minitest::Hyper.enable! 13 | assert Minitest::Hyper.enabled? 14 | end 15 | 16 | describe "when testing a Rails app" do 17 | let(:rails_path) { File.join(File.expand_path("."), "rails") } 18 | 19 | before do 20 | @original_rails = Object.const_get(:Rails) if Object.const_defined?(:Rails) 21 | Object.const_set(:Rails, Struct.new(:root).new(rails_path)) 22 | end 23 | 24 | after do 25 | if @original_rails 26 | Object.const_set(:Rails, @original_rails) 27 | else 28 | Object.send(:remove_const, :Rails) 29 | end 30 | end 31 | 32 | it "returns the report target directory" do 33 | expected = File.join(rails_path, "test/reports/hyper") 34 | assert_equal expected, Minitest::Hyper.report_dirname 35 | end 36 | 37 | it "returns the report target file" do 38 | expected = File.join(rails_path, "test/reports/hyper/index.html") 39 | assert_equal expected, Minitest::Hyper.report_filename 40 | end 41 | 42 | describe "when the spec/ directory is present" do 43 | let(:spec_dir) { File.join(rails_path, "spec") } 44 | 45 | before do 46 | FileUtils.mkdir_p(spec_dir) 47 | end 48 | 49 | after do 50 | FileUtils.rm_rf(rails_path) 51 | end 52 | 53 | it "returns the report target directory" do 54 | expected = File.join(spec_dir, "reports/hyper") 55 | assert_equal expected, Minitest::Hyper.report_dirname 56 | end 57 | 58 | it "returns the report target file" do 59 | expected = File.join(spec_dir, "reports/hyper/index.html") 60 | assert_equal expected, Minitest::Hyper.report_filename 61 | end 62 | end 63 | end 64 | 65 | describe "when testing a non-Rails app" do 66 | it "returns the report target directory" do 67 | expected = File.join(File.expand_path("."), "test/reports/hyper") 68 | assert_equal expected, Minitest::Hyper.report_dirname 69 | end 70 | 71 | it "returns the report target file" do 72 | expected = File.join(File.expand_path("."), "test/reports/hyper/index.html") 73 | assert_equal expected, Minitest::Hyper.report_filename 74 | end 75 | 76 | describe "when the spec/ directory is present" do 77 | let(:spec_dir) { File.join(File.expand_path("."), "spec") } 78 | 79 | before do 80 | FileUtils.mkdir(spec_dir) 81 | end 82 | 83 | after do 84 | FileUtils.rm_rf(spec_dir) 85 | end 86 | 87 | it "returns the report target directory" do 88 | expected = File.join(spec_dir, "reports/hyper") 89 | assert_equal expected, Minitest::Hyper.report_dirname 90 | end 91 | 92 | it "returns the report target file" do 93 | expected = File.join(spec_dir, "reports/hyper/index.html") 94 | assert_equal expected, Minitest::Hyper.report_filename 95 | end 96 | end 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /test/support/fake_reporter.rb: -------------------------------------------------------------------------------- 1 | require "ostruct" 2 | 3 | class FakeReporter < OpenStruct 4 | DEFAULT_OPTIONS = { 5 | count: 0, assertions: 0, start_time: Time.now, total_time: 0.0, 6 | failures: 0, errors: 0, skips: 0, results: [], non_passing: [] 7 | } 8 | 9 | CODES = %i(pass skip fail error) 10 | 11 | attr_reader :all_results, :results 12 | 13 | def initialize(options = {}) 14 | options = DEFAULT_OPTIONS.merge(options) 15 | super options 16 | generate_result_set 17 | end 18 | 19 | def generate_result_set 20 | pass_count = count >= 2 ? count * 0.5 : 1 21 | passes = Array.new(pass_count) { generate_result(:pass) } 22 | 23 | fail_count = count >= 5 ? count * 0.2 : 1 24 | fails = Array.new(fail_count) { generate_result(:fail) } 25 | 26 | error_count = count >= 5 ? count * 0.2 : 1 27 | errors = Array.new(error_count) { generate_result(:error) } 28 | 29 | skip_count = count >= 10 ? count * 0.1 : 1 30 | skips = Array.new(skip_count) { generate_result(:skip) } 31 | 32 | @all_results = (passes + fails + skips + errors).shuffle 33 | @results = (fails + skips + errors).shuffle 34 | end 35 | 36 | def to_h 37 | Minitest::Hyper::Reporter::HashFormatter.as_hash(self) 38 | end 39 | 40 | private 41 | 42 | def generate_result(type) 43 | result = { 44 | name: "Fake Name", 45 | code: type, 46 | class: type.to_s, 47 | outcome: type.to_s.capitalize, 48 | time: rand, 49 | assertions: rand(7) 50 | } 51 | 52 | if type != :pass 53 | failure = case type 54 | when :fail 55 | Minitest::Assertion.new 56 | when :skip 57 | Minitest::Skip.new 58 | when :error 59 | begin 60 | raise 61 | rescue Exception => e 62 | Minitest::UnexpectedError.new(e) 63 | end 64 | end 65 | 66 | begin 67 | raise failure 68 | rescue Exception => e 69 | result[:failure] = failure 70 | result[:location] = failure.location 71 | end 72 | end 73 | 74 | OpenStruct.new result 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /test/support/filesystem_helpers.rb: -------------------------------------------------------------------------------- 1 | require "fileutils" 2 | require "minitest" 3 | require "minitest/spec" 4 | 5 | module FilesystemHelpers 6 | def reset_reports_directory(reports_dir) 7 | FileUtils.rm_rf(reports_dir) if Dir.exist?(reports_dir) 8 | end 9 | 10 | def touch_report(path) 11 | FileUtils.mkdir_p(File.dirname(path)) 12 | FileUtils.touch(path) 13 | end 14 | 15 | module Assertions 16 | def assert_file(name) 17 | assert File.exist?(name), "#{ name } does not exist" 18 | assert File.file?(name), "#{ name } is not a file" 19 | end 20 | 21 | def assert_dir(name) 22 | assert File.exist?(name), "#{ name } does not exist" 23 | assert File.directory?(name), "#{ name } is not a directory" 24 | end 25 | 26 | def assert_writable(name) 27 | assert (File.exist?(name) && File.writable?(name)), 28 | "#{ name } is not writable" 29 | end 30 | 31 | def refute_file(name) 32 | refute (File.exist?(name) && File.file?(name)), 33 | "#{ name } is a file" 34 | end 35 | 36 | def refute_dir(name) 37 | refute (File.exist?(name) && File.directory?(name)), 38 | "#{ name } is a directory" 39 | end 40 | 41 | def refute_writable(name) 42 | assert (File.exist?(name) && File.writable?(name)), 43 | "#{ name } is writable" 44 | end 45 | end 46 | 47 | module Expectations 48 | include Assertions 49 | 50 | infect_an_assertion :assert_file, :must_be_a_file, :unary 51 | infect_an_assertion :assert_dir, :must_be_a_dir, :unary 52 | infect_an_assertion :assert_writable, :must_be_writable, :unary 53 | infect_an_assertion :refute_file, :wont_be_a_file, :unary 54 | infect_an_assertion :refute_dir, :wont_be_a_dir, :unary 55 | infect_an_assertion :refute_writable, :wont_be_writable, :unary 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) 2 | require "minitest/hyper_plugin" 3 | 4 | require "minitest/autorun" 5 | require "minitest/spec" 6 | require "minitest/pride" 7 | 8 | require "support/filesystem_helpers" 9 | require "support/fake_reporter" 10 | --------------------------------------------------------------------------------