test_notifier 2.0.3 → 3.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5d8fd6d8f3c507c644caa30c41ecc00286ed974b
4
- data.tar.gz: c6985dcc140c2b59dded50c59bcc538a217778aa
2
+ SHA256:
3
+ metadata.gz: a4b46a9c384eb5f3be2092410e47fc46908be2cb8d43cf91921ad77b414b8ed3
4
+ data.tar.gz: 0faba90248d756a52211df5e83553256e15996e0e092729a63cac91d6a9b803c
5
5
  SHA512:
6
- metadata.gz: ef1b1773a57e18902b2264e41464f08998fb72cbb4c74cb9b4688fb79d4572f646ab085f82646047e654182b97527bcaffba8889bbea4ec7f2b945c01118e387
7
- data.tar.gz: 905c8b9129e4ca416ac8d0734beeb11cebcef1bb0c77e051596f22e34ef2aa05a4cf93236c633db52254ee13137a7c40ce900bdcc79afbd2948c7a9c30ca178b
6
+ metadata.gz: aac8c5ae3acc691ee740a4db73fa09a18d440e89d5532c11b57563e5bf98681ac1d12470faa1f570155969a2a5b88d2538deddae6fe6461565ffaef88966a654
7
+ data.tar.gz: fc03272885566e612f757b21dba81f6297e7fc6907ab61b60b675b6ce2628cec2b263edac21a8adc186daf6c0de08c5e73a29906f3216c6965f2d1ae16a64b03
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  *.gem
2
2
  pkg
3
- nbproject
3
+ nbproject
4
+ *.lock
5
+ hud.xcworkspace/xcuserdata
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ ---
2
+ inherit_gem:
3
+ rubocop-fnando: .rubocop.yml
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.4
7
+ NewCops: enable
8
+ Exclude:
9
+ - vendor/**/*
10
+
11
+ Minitest/UselessAssertion:
12
+ Exclude:
13
+ - test/fixtures/*
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
- source "http://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
  gemspec
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Test Notifier
2
+
3
+ Display notifications when tests run. Supports Minitest and RSpec.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ gem install test_notifier
9
+ ```
10
+
11
+ Check <https://github.com/fnando/notifier> to see how you can configure a
12
+ notifier for your OS.
13
+
14
+ ## Usage
15
+
16
+ You can set the default notifier, in case you want to use an specific one.
17
+
18
+ ```ruby
19
+ TestNotifier.default_notifier = :terminal_notifier
20
+ ```
21
+
22
+ The available notifiers are `:terminal_notifier`, `:hud`, `:kdialog`,
23
+ `:knotify`, `:notify_send`, `:osd_cat`, and `:snarl`.
24
+
25
+ If you'd like to make Test Notifier optional for your project:
26
+
27
+ ```ruby
28
+ TestNotifier.silence_no_notifier_warning = true
29
+ ```
30
+
31
+ ## Maintainer
32
+
33
+ - Nando Vieira - https://nandovieira.com
34
+
35
+ ## Collaborators
36
+
37
+ https://github.com/fnando/test_notifier/graphs/contributors
38
+
39
+ ## License
40
+
41
+ (The MIT License)
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
44
+ this software and associated documentation files (the 'Software'), to deal in
45
+ the Software without restriction, including without limitation the rights to
46
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
47
+ the Software, and to permit persons to whom the Software is furnished to do so,
48
+ subject to the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be included in all
51
+ copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
55
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
56
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
57
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
58
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,5 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler"
2
4
  Bundler::GemHelper.install_tasks
3
5
 
4
- require "rspec/core/rake_task"
5
- RSpec::Core::RakeTask.new
6
+ # require "rspec/core/rake_task"
7
+ # RSpec::Core::RakeTask.new
8
+
9
+ require "rake/testtask"
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << "test"
12
+ t.test_files = FileList["test/**/*_test.rb"]
13
+ t.warning = false
14
+ end
15
+
16
+ require "rubocop/rake_task"
17
+ RuboCop::RakeTask.new
18
+
19
+ task default: %i[test rubocop]
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Minitest
4
+ def self.plugin_test_notifier_init(_options)
5
+ reporter << TestNotifier::MinitestReporter.new
6
+ end
7
+ end
@@ -1,15 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_notifier"
2
- require "minitest/unit"
4
+ require "minitest"
5
+
6
+ module TestNotifier
7
+ class MinitestReporter < Minitest::AbstractReporter
8
+ attr_reader :count, :assertions, :failures, :errors, :pending
9
+
10
+ def initialize(*)
11
+ super
12
+ @assertions = 0
13
+ @count = 0
14
+ @failures = 0
15
+ @errors = 0
16
+ @pending = 0
17
+ end
18
+
19
+ def start
20
+ end
21
+
22
+ def prerecord(*)
23
+ end
3
24
 
4
- MiniTest::Unit.after_tests do
5
- runner = MiniTest::Unit.runner
25
+ def record(result)
26
+ flunked = result.failures.count { flunk?(it) }
6
27
 
7
- stats = TestNotifier::Stats.new(:minitest, {
8
- :count => runner.test_count,
9
- :assertions => runner.assertion_count,
10
- :failures => runner.failures,
11
- :errors => runner.errors
12
- })
28
+ @count += 1
29
+ @assertions += result.assertions
30
+ @assertions -= flunked if flunked.nonzero?
31
+ @errors += result.failures.count { error?(it) }
32
+ @failures += result.failures.count { failure?(it) }
33
+ @pending += flunked
34
+ end
13
35
 
14
- TestNotifier.notify(:status => stats.status, :message => stats.message)
36
+ def flunk?(failure)
37
+ (failure.backtrace_locations || [])
38
+ .any? { it.label == "Minitest::Assertions#flunk" }
39
+ end
40
+
41
+ def failure?(failure)
42
+ failure.is_a?(Minitest::Assertion) && !flunk?(failure)
43
+ end
44
+
45
+ def error?(failure)
46
+ failure.is_a?(Minitest::UnexpectedError)
47
+ end
48
+
49
+ def report
50
+ stats = TestNotifier::Stats.new(
51
+ :minitest,
52
+ count:,
53
+ assertions:,
54
+ failures:,
55
+ errors:,
56
+ pending:
57
+ )
58
+
59
+ TestNotifier.notify(status: stats.status, message: stats.message)
60
+ end
61
+ end
15
62
  end
63
+
64
+ Minitest.load(:test_notifier)
@@ -1,7 +1,49 @@
1
- require "rspec/core/version"
1
+ # frozen_string_literal: true
2
2
 
3
- if RSpec::Core::Version::STRING >= "3.0.0"
4
- require "test_notifier/runner/rspec3"
5
- else
6
- require "test_notifier/runner/rspec2"
3
+ require "test_notifier"
4
+ require "rspec/core"
5
+ require "rspec/core/formatters/base_text_formatter"
6
+
7
+ module RSpec
8
+ module Core
9
+ module Formatters
10
+ class BaseTextFormatter
11
+ alias dump_summary_original dump_summary
12
+
13
+ def error_filter
14
+ proc do |error|
15
+ error.exception.is_a?(UncaughtThrowError)
16
+ end
17
+ end
18
+
19
+ def failure_filter
20
+ proc do |error|
21
+ error.exception
22
+ .instance_of?(RSpec::Expectations::ExpectationNotMetError)
23
+ end
24
+ end
25
+
26
+ def dump_summary(options)
27
+ dump_summary_original(options)
28
+
29
+ count = options.example_count
30
+ pending = options.pending_count
31
+ errors = options.failed_examples.count(&error_filter)
32
+ failures = options.failed_examples.size - errors
33
+
34
+ return if count.zero?
35
+
36
+ stats = TestNotifier::Stats.new(
37
+ :rspec,
38
+ count:,
39
+ failures:,
40
+ pending:,
41
+ errors:
42
+ )
43
+
44
+ TestNotifier.notify(status: stats.status, message: stats.message)
45
+ end
46
+ end
47
+ end
48
+ end
7
49
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestNotifier
2
4
  module Runner
3
5
  autoload :RSpec, "test_notifier/runner/rspec"
4
- autoload :Spec, "test_notifier/runner/spec"
5
- autoload :TestUnit, "test_notifier/runner/test_unit"
6
+ autoload :Minitest, "test_notifier/runner/minitest"
6
7
  end
7
8
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestNotifier
2
4
  class Stats
3
5
  attr_accessor :adapter, :options
@@ -17,15 +19,14 @@ module TestNotifier
17
19
  send("message_for_#{adapter}")
18
20
  end
19
21
 
20
- private
21
- def normalize(options)
22
- [:count, :success, :failures, :pending, :errors, :assertions].inject({}) do |buffer, key|
23
- buffer[key] = options[key].to_i
24
- buffer
25
- end
22
+ private def normalize(options)
23
+ %i[count success failures pending errors assertions]
24
+ .each_with_object({}) do |key, buffer|
25
+ buffer[key] = options[key].to_i
26
+ end
26
27
  end
27
28
 
28
- def status_for_minitest
29
+ private def status_for_rspec
29
30
  if options[:errors].nonzero?
30
31
  :error
31
32
  elsif options[:failures].nonzero?
@@ -35,17 +36,22 @@ module TestNotifier
35
36
  end
36
37
  end
37
38
 
38
- def status_for_test_unit
39
- if options[:errors].nonzero?
40
- :error
41
- elsif options[:failures].nonzero?
42
- :fail
43
- else
44
- :success
39
+ private def message_for_rspec
40
+ options[:success] =
41
+ options[:count] - (options[:failures] + options[:errors])
42
+
43
+ text = []
44
+ text << ("#{options[:count]} " + pluralize(options[:count], "example"))
45
+ text << "#{options[:failures]} failed" unless options[:failures].zero?
46
+ text << "#{options[:pending]} pending" unless options[:pending].zero?
47
+ unless options[:errors].zero?
48
+ text << ("#{options[:errors]} " + pluralize(options[:errors],
49
+ "error"))
45
50
  end
51
+ text.join(", ")
46
52
  end
47
53
 
48
- def status_for_rspec
54
+ private def status_for_minitest
49
55
  if options[:errors].nonzero?
50
56
  :error
51
57
  elsif options[:failures].nonzero?
@@ -55,53 +61,25 @@ module TestNotifier
55
61
  end
56
62
  end
57
63
 
58
- def status_for_spec
59
- if options[:failures].nonzero?
60
- :fail
61
- else
62
- :success
63
- end
64
- end
65
-
66
- def message_for_rspec
67
- options[:success] = options[:count] - (options[:failures] + options[:errors])
68
-
64
+ private def message_for_minitest
69
65
  text = []
70
- text << "#{options[:count]} " + pluralize(options[:count], "example")
66
+ text << ("#{options[:count]} " + pluralize(options[:count], "test"))
67
+ text << ("#{options[:assertions]} " + pluralize(options[:assertions],
68
+ "assertion"))
71
69
  text << "#{options[:failures]} failed" unless options[:failures].zero?
72
- text << "#{options[:pending]} pending" unless options[:pending].zero?
73
- text << "#{options[:errors]} " + pluralize(options[:errors], "error") unless options[:errors].zero?
74
- text.join(", ")
75
- end
76
70
 
77
- def message_for_spec
78
- text = []
79
- text << "#{options[:count]} " + pluralize(options[:count], "example")
80
- text << "#{options[:failures]} failed" unless options[:failures].zero?
81
- text << "#{options[:pending]} pending" unless options[:pending].zero?
82
- text.join(", ")
83
- end
71
+ unless options[:errors].zero?
72
+ text << ("#{options[:errors]} " + pluralize(options[:errors],
73
+ "error"))
74
+ end
84
75
 
85
- def message_for_test_unit
86
- text = []
87
- text << "#{options[:count]} " + pluralize(options[:count], "test")
88
- text << "#{options[:assertions]} " + pluralize(options[:assertions], "assertion")
89
- text << "#{options[:failures]} failed" unless options[:failures].zero?
90
- text << "#{options[:errors]} " + pluralize(options[:errors], "error") unless options[:errors].zero?
91
- text.join(", ")
92
- end
76
+ text << "#{options[:pending]} pending" unless options[:pending].zero?
93
77
 
94
- def message_for_minitest
95
- text = []
96
- text << "#{options[:count]} " + pluralize(options[:count], "test")
97
- text << "#{options[:assertions]} " + pluralize(options[:assertions], "assertion")
98
- text << "#{options[:failures]} failed" unless options[:failures].zero?
99
- text << "#{options[:errors]} " + pluralize(options[:errors], "error") unless options[:errors].zero?
100
78
  text.join(", ")
101
79
  end
102
80
 
103
- def pluralize(count, text)
104
- count > 1 ? "#{text}s" : text
81
+ private def pluralize(count, text)
82
+ count == 1 ? text : "#{text}s"
105
83
  end
106
84
  end
107
85
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestNotifier
2
4
  module Version
3
- MAJOR = 2
5
+ MAJOR = 3
4
6
  MINOR = 0
5
- PATCH = 3
6
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ PATCH = 0
8
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}".freeze
7
9
  end
8
10
  end
data/lib/test_notifier.rb CHANGED
@@ -1,42 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "notifier"
2
4
 
3
5
  module TestNotifier
4
- class << self
5
- attr_accessor :silence_no_notifier_warning
6
- end
7
-
8
6
  extend self
9
7
 
10
- NO_NOTIFIERS_MESSAGE = "[TEST NOTIFIER] You have no supported notifiers installed. Please read documentation.\n"
8
+ NO_NOTIFIERS_MESSAGE = "[TEST NOTIFIER] You have no supported notifiers " \
9
+ "installed. Please read documentation.\n"
11
10
 
12
11
  IMAGES = {
13
- :fail => File.dirname(__FILE__) + "/../resources/fail.png",
14
- :error => File.dirname(__FILE__) + "/../resources/error.png",
15
- :success => File.dirname(__FILE__) + "/../resources/success.png"
16
- }
12
+ fail: File.expand_path("#{__dir__}/../resources/fail.png"),
13
+ error: File.expand_path("#{__dir__}/../resources/error.png"),
14
+ success: File.expand_path("#{__dir__}/../resources/success.png")
15
+ }.freeze
16
+
17
+ HUD_SYMBOLS = {
18
+ fail: "exclamationmark.triangle",
19
+ error: "xmark.octagon",
20
+ success: "checkmark.circle"
21
+ }.freeze
17
22
 
18
23
  TITLES = {
19
- :fail => "Failed!",
20
- :success => "Passed!",
21
- :error => "Error!"
22
- }
24
+ fail: "Failed!",
25
+ success: "Passed!",
26
+ error: "Error!"
27
+ }.freeze
23
28
 
24
29
  COLORS = {
25
- :fail => "orange",
26
- :success => "green",
27
- :error => "red"
28
- }
30
+ fail: "orange",
31
+ success: "green",
32
+ error: "red"
33
+ }.freeze
34
+
35
+ attr_accessor :silence_no_notifier_warning
29
36
 
30
37
  def default_notifier=(notifier)
31
38
  Notifier.default_notifier = notifier
32
39
  end
33
40
 
34
41
  def notify(options)
35
- options.merge!({
36
- :title => TITLES[options[:status]],
37
- :image => IMAGES[options[:status]],
38
- :color => COLORS[options[:status]]
39
- })
42
+ options = options.merge(
43
+ title: TITLES[options[:status]],
44
+ image: IMAGES[options[:status]],
45
+ color: COLORS[options[:status]]
46
+ )
47
+
48
+ if Notifier.notifier == Notifier::Hud
49
+ options[:image] = HUD_SYMBOLS[options[:status]]
50
+ end
40
51
 
41
52
  notifier.notify(options)
42
53
  end
@@ -44,13 +55,14 @@ module TestNotifier
44
55
  def notifier
45
56
  notifier = Notifier.notifier
46
57
 
47
- if notifier == Notifier::Placebo && !silence_no_notifier_warning
48
- STDERR << NO_NOTIFIERS_MESSAGE
58
+ if notifier == Notifier::Noop && !silence_no_notifier_warning
59
+ $stderr << NO_NOTIFIERS_MESSAGE
49
60
  end
50
61
 
51
62
  notifier
52
63
  end
53
64
 
54
- require "test_notifier/runner"
55
65
  require "test_notifier/stats"
66
+ require "test_notifier/runner/minitest" if defined?(Minitest)
67
+ require "test_notifier/runner/rspec" if defined?(RSpec)
56
68
  end
data/resources/error.png CHANGED
Binary file
data/resources/fail.png CHANGED
Binary file
Binary file
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "minitest/autorun"
5
+ require "test_notifier"
6
+
7
+ class MinitestSample < Minitest::Test
8
+ def test_passes
9
+ assert true
10
+ assert true
11
+ end
12
+
13
+ def test_fails
14
+ refute true
15
+ end
16
+
17
+ def test_errors
18
+ raise "foo"
19
+ end
20
+
21
+ def test_flunks
22
+ flunk "this is pending"
23
+ end
24
+ end
25
+
26
+ class MinitestSample2 < Minitest::Test
27
+ def test_passes
28
+ assert true
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "rspec/autorun"
5
+ require "test_notifier"
6
+
7
+ describe "test" do
8
+ it "passes" do
9
+ expect(true).to be
10
+ end
11
+
12
+ it "passes too" do
13
+ expect(true).to be
14
+ end
15
+
16
+ it "fails" do
17
+ expect(false).to be
18
+ end
19
+
20
+ it "pending" do
21
+ expect(true).to be
22
+ end
23
+
24
+ it "raises" do
25
+ throw "error"
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "minitest/utils"
5
+ require "minitest/autorun"
6
+ require "test_notifier"
7
+
8
+ module Minitest
9
+ class Test
10
+ def unsupport_all_notifiers
11
+ Notifier.notifiers.each do |notifier|
12
+ next if notifier == Notifier::Noop
13
+
14
+ notifier.stubs(:supported?).returns(false)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class StatsMinitestTest < Minitest::Test
6
+ let(:stats) { TestNotifier::Stats.new(:minitest) }
7
+
8
+ test "returns success message" do
9
+ stats.options = {count: 10, assertions: 20}
10
+
11
+ assert_equal "10 tests, 20 assertions", stats.message
12
+ end
13
+
14
+ test "message with failing tests" do
15
+ stats.options = {count: 10, assertions: 20, failures: 5}
16
+
17
+ assert_equal "10 tests, 20 assertions, 5 failed", stats.message
18
+ end
19
+
20
+ test "message with error tests" do
21
+ stats.options = {count: 10, assertions: 20, errors: 5}
22
+
23
+ assert_equal "10 tests, 20 assertions, 5 errors", stats.message
24
+ end
25
+
26
+ test "message with pending tests" do
27
+ stats.options = {count: 10, assertions: 20, pending: 5}
28
+
29
+ assert_equal "10 tests, 20 assertions, 5 pending", stats.message
30
+ end
31
+
32
+ test "message with all types" do
33
+ stats.options = {
34
+ count: 6,
35
+ failures: 2,
36
+ errors: 3,
37
+ assertions: 20,
38
+ pending: 4
39
+ }
40
+
41
+ expected = "6 tests, 20 assertions, 2 failed, 3 errors, 4 pending"
42
+
43
+ assert_equal expected, stats.message
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class StatsTest < Minitest::Test
6
+ let(:stats) { TestNotifier::Stats.new(:rspec) }
7
+
8
+ test "returns success message" do
9
+ stats.options = {count: 10}
10
+
11
+ assert_equal "10 examples", stats.message
12
+ end
13
+
14
+ test "returns message with failing examples" do
15
+ stats.options = {count: 10, failures: 5}
16
+
17
+ assert_equal "10 examples, 5 failed", stats.message
18
+ end
19
+
20
+ test "returns message with pending examples" do
21
+ stats.options = {count: 10, pending: 5}
22
+
23
+ assert_equal "10 examples, 5 pending", stats.message
24
+ end
25
+
26
+ test "returns message with error examples" do
27
+ stats.options = {count: 10, failures: 5, errors: 5}
28
+
29
+ assert_equal "10 examples, 5 failed, 5 errors", stats.message
30
+ end
31
+
32
+ test "returns message with all types" do
33
+ stats.options = {count: 6, failures: 3, errors: 2, pending: 3}
34
+
35
+ assert_equal "6 examples, 3 failed, 3 pending, 2 errors", stats.message
36
+ end
37
+ end