smartest 0.3.3.alpha4 → 0.5.0.alpha1

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.
@@ -10,7 +10,7 @@ module Smartest
10
10
 
11
11
  def run
12
12
  results = []
13
- suite_cleanup_errors = []
13
+ suite_teardown_errors = []
14
14
  suite_errors = []
15
15
  @suite_fixture_set = nil
16
16
 
@@ -18,7 +18,7 @@ module Smartest
18
18
 
19
19
  begin
20
20
  run_around_suite_hooks(@suite.around_suite_hooks.dup) do
21
- run_tests(results, suite_cleanup_errors)
21
+ run_tests(results, suite_teardown_errors)
22
22
  end
23
23
  rescue Exception => error
24
24
  raise if Smartest.fatal_exception?(error)
@@ -28,16 +28,16 @@ module Smartest
28
28
 
29
29
  @reporter.finish(
30
30
  results,
31
- suite_cleanup_errors: suite_cleanup_errors,
31
+ suite_teardown_errors: suite_teardown_errors,
32
32
  suite_errors: suite_errors
33
33
  )
34
34
 
35
- results.any?(&:failed?) || suite_cleanup_errors.any? || suite_errors.any? ? 1 : 0
35
+ results.any?(&:failed?) || suite_teardown_errors.any? || suite_errors.any? ? 1 : 0
36
36
  end
37
37
 
38
38
  private
39
39
 
40
- def run_tests(results, suite_cleanup_errors)
40
+ def run_tests(results, suite_teardown_errors)
41
41
  begin
42
42
  @tests.each do |test_case|
43
43
  result = run_one(test_case)
@@ -45,7 +45,7 @@ module Smartest
45
45
  @reporter.record(result)
46
46
  end
47
47
  ensure
48
- suite_cleanup_errors.concat(@suite_fixture_set.run_cleanups) if @suite_fixture_set
48
+ suite_teardown_errors.concat(@suite_fixture_set.run_teardowns) if @suite_fixture_set
49
49
  @suite_fixture_set = nil
50
50
  end
51
51
  end
@@ -68,13 +68,13 @@ module Smartest
68
68
  started_at = now
69
69
  error = nil
70
70
  skipped = nil
71
- cleanup_errors = []
71
+ teardown_errors = []
72
72
  run_state = TestRunState.new
73
73
  test_run = TestRun.new(
74
74
  fixture_classes: @suite.fixture_classes,
75
75
  matcher_modules: @suite.matcher_modules
76
76
  ) do |fixture_classes:, matcher_modules:, helper_modules:|
77
- run_test_body(test_case, fixture_classes, matcher_modules, helper_modules, run_state, cleanup_errors)
77
+ run_test_body(test_case, fixture_classes, matcher_modules, helper_modules, run_state, teardown_errors)
78
78
  end
79
79
 
80
80
  begin
@@ -89,12 +89,12 @@ module Smartest
89
89
 
90
90
  duration = now - started_at
91
91
 
92
- return TestResult.failed(test_case: test_case, error: nil, duration: duration, cleanup_errors: cleanup_errors) if skipped && cleanup_errors.any?
92
+ return TestResult.failed(test_case: test_case, error: nil, duration: duration, teardown_errors: teardown_errors) if skipped && teardown_errors.any?
93
93
  return TestResult.skipped(test_case: test_case, reason: skipped.reason, duration: duration) if skipped
94
94
 
95
95
  if run_state.pending?
96
96
  if error && !around_test_protocol_error?(error)
97
- return TestResult.failed(test_case: test_case, error: nil, duration: duration, cleanup_errors: cleanup_errors) if cleanup_errors.any?
97
+ return TestResult.failed(test_case: test_case, error: nil, duration: duration, teardown_errors: teardown_errors) if teardown_errors.any?
98
98
 
99
99
  return TestResult.pending(test_case: test_case, reason: run_state.pending_reason, duration: duration)
100
100
  end
@@ -102,19 +102,19 @@ module Smartest
102
102
  error ||= PendingPassedError.new(run_state.pending_reason)
103
103
  end
104
104
 
105
- if error || cleanup_errors.any?
105
+ if error || teardown_errors.any?
106
106
  TestResult.failed(
107
107
  test_case: test_case,
108
108
  error: error,
109
109
  duration: duration,
110
- cleanup_errors: cleanup_errors
110
+ teardown_errors: teardown_errors
111
111
  )
112
112
  else
113
113
  TestResult.passed(test_case: test_case, duration: duration)
114
114
  end
115
115
  end
116
116
 
117
- def run_test_body(test_case, fixture_classes, matcher_modules, helper_modules, run_state, cleanup_errors)
117
+ def run_test_body(test_case, fixture_classes, matcher_modules, helper_modules, run_state, teardown_errors)
118
118
  context = build_context(matcher_modules, run_state, helper_modules)
119
119
  fixture_set = nil
120
120
 
@@ -123,7 +123,7 @@ module Smartest
123
123
  fixtures = fixture_set.resolve_keywords(test_case.fixture_names)
124
124
  context.instance_exec(**fixtures, &test_case.block)
125
125
  ensure
126
- cleanup_errors.concat(fixture_set.run_cleanups) if fixture_set
126
+ teardown_errors.concat(fixture_set.run_teardowns) if fixture_set
127
127
  end
128
128
  end
129
129
 
@@ -2,59 +2,59 @@
2
2
 
3
3
  module Smartest
4
4
  class TestResult
5
- attr_reader :test_case, :status, :error, :duration, :cleanup_errors, :reason
5
+ attr_reader :test_case, :status, :error, :duration, :teardown_errors, :reason
6
6
 
7
- def self.passed(test_case:, duration:, cleanup_errors: [])
7
+ def self.passed(test_case:, duration:, teardown_errors: [])
8
8
  new(
9
9
  test_case: test_case,
10
10
  status: :passed,
11
11
  error: nil,
12
12
  reason: nil,
13
13
  duration: duration,
14
- cleanup_errors: cleanup_errors
14
+ teardown_errors: teardown_errors
15
15
  )
16
16
  end
17
17
 
18
- def self.failed(test_case:, error:, duration:, cleanup_errors: [])
18
+ def self.failed(test_case:, error:, duration:, teardown_errors: [])
19
19
  new(
20
20
  test_case: test_case,
21
21
  status: :failed,
22
22
  error: error,
23
23
  reason: nil,
24
24
  duration: duration,
25
- cleanup_errors: cleanup_errors
25
+ teardown_errors: teardown_errors
26
26
  )
27
27
  end
28
28
 
29
- def self.skipped(test_case:, reason:, duration:, cleanup_errors: [])
29
+ def self.skipped(test_case:, reason:, duration:, teardown_errors: [])
30
30
  new(
31
31
  test_case: test_case,
32
32
  status: :skipped,
33
33
  error: nil,
34
34
  reason: reason,
35
35
  duration: duration,
36
- cleanup_errors: cleanup_errors
36
+ teardown_errors: teardown_errors
37
37
  )
38
38
  end
39
39
 
40
- def self.pending(test_case:, reason:, duration:, cleanup_errors: [])
40
+ def self.pending(test_case:, reason:, duration:, teardown_errors: [])
41
41
  new(
42
42
  test_case: test_case,
43
43
  status: :pending,
44
44
  error: nil,
45
45
  reason: reason,
46
46
  duration: duration,
47
- cleanup_errors: cleanup_errors
47
+ teardown_errors: teardown_errors
48
48
  )
49
49
  end
50
50
 
51
- def initialize(test_case:, status:, error:, reason:, duration:, cleanup_errors:)
51
+ def initialize(test_case:, status:, error:, reason:, duration:, teardown_errors:)
52
52
  @test_case = test_case
53
53
  @status = status
54
54
  @error = error
55
55
  @reason = reason
56
56
  @duration = duration
57
- @cleanup_errors = cleanup_errors
57
+ @teardown_errors = teardown_errors
58
58
  end
59
59
 
60
60
  def passed?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Smartest
4
- VERSION = "0.3.3.alpha4"
4
+ VERSION = "0.5.0.alpha1"
5
5
  end
@@ -96,7 +96,7 @@ test("simple stub can be reset from a fresh stub object") do
96
96
  expect(SimpleStubSelfTestSubject.new("Alice").greeting("Hi")).to eq("Hi, Alice")
97
97
  end
98
98
 
99
- test("simple_stub_any_instance_of applies and resets from fixture cleanup") do
99
+ test("simple_stub_any_instance_of applies and resets from fixture teardown") do
100
100
  fixture_class = Class.new(Smartest::Fixture) do
101
101
  fixture :stubbed_name do
102
102
  simple_stub_any_instance_of(SimpleStubSelfTestSubject, :name) { "fixture #{@name}" }
@@ -127,7 +127,7 @@ test("simple_stub_any_instance_of applies and resets from fixture cleanup") do
127
127
  expect(status).to eq(0)
128
128
  end
129
129
 
130
- test("simple_stub applies and resets singleton methods from fixture cleanup") do
130
+ test("simple_stub applies and resets singleton methods from fixture teardown") do
131
131
  fixture_class = Class.new(Smartest::Fixture) do
132
132
  fixture :stubbed_time do
133
133
  simple_stub(SimpleStubSelfTestClock, :now) { :stubbed_now }
@@ -158,8 +158,8 @@ test("simple_stub applies and resets singleton methods from fixture cleanup") do
158
158
  expect(status).to eq(0)
159
159
  end
160
160
 
161
- test("simple_stub_const applies and resets existing constants in test body blocks") do
162
- result = simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider) do
161
+ test("with_stub_const applies and resets existing constants in test body blocks") do
162
+ result = with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider) do
163
163
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:stubbed_provider)
164
164
  :block_result
165
165
  end
@@ -168,17 +168,17 @@ test("simple_stub_const applies and resets existing constants in test body block
168
168
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
169
169
  end
170
170
 
171
- test("simple_stub_const removes newly defined constants after test body blocks") do
172
- simple_stub_const("SimpleStubSelfTestConfig::MISSING_PROVIDER", :stubbed_missing_provider) do
171
+ test("with_stub_const removes newly defined constants after test body blocks") do
172
+ with_stub_const("SimpleStubSelfTestConfig::MISSING_PROVIDER", :stubbed_missing_provider) do
173
173
  expect(SimpleStubSelfTestConfig::MISSING_PROVIDER).to eq(:stubbed_missing_provider)
174
174
  end
175
175
 
176
176
  expect(SimpleStubSelfTestConfig.const_defined?(:MISSING_PROVIDER, false)).to eq(false)
177
177
  end
178
178
 
179
- test("simple_stub_const restores constants when the block raises") do
179
+ test("with_stub_const restores constants when the block raises") do
180
180
  error = SimpleStubSelfTest.capture_error(RuntimeError) do
181
- simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider) do
181
+ with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider) do
182
182
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:stubbed_provider)
183
183
  raise "stubbed block failed"
184
184
  end
@@ -188,18 +188,18 @@ test("simple_stub_const restores constants when the block raises") do
188
188
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
189
189
  end
190
190
 
191
- test("simple_stub_const requires a block") do
191
+ test("with_stub_const requires a block") do
192
192
  error = SimpleStubSelfTest.capture_error(ArgumentError) do
193
- simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider)
193
+ with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider)
194
194
  end
195
195
 
196
- expect(error.message).to eq("simple_stub_const block is required")
196
+ expect(error.message).to eq("with_stub_const block is required")
197
197
  end
198
198
 
199
- test("simple_stub_const wraps around_test hooks") do
199
+ test("with_stub_const wraps around_test hooks") do
200
200
  suite = Smartest::Suite.new
201
201
  suite.around_test_hooks << proc do |test_run|
202
- simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :around_test_provider) do
202
+ with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :around_test_provider) do
203
203
  test_run.run
204
204
  end
205
205
  end
@@ -216,10 +216,10 @@ test("simple_stub_const wraps around_test hooks") do
216
216
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
217
217
  end
218
218
 
219
- test("simple_stub_const wraps around_suite hooks") do
219
+ test("with_stub_const wraps around_suite hooks") do
220
220
  suite = Smartest::Suite.new
221
221
  suite.around_suite_hooks << proc do |suite_run|
222
- simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :around_suite_provider) do
222
+ with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :around_suite_provider) do
223
223
  suite_run.run
224
224
  end
225
225
  end
@@ -236,10 +236,10 @@ test("simple_stub_const wraps around_suite hooks") do
236
236
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
237
237
  end
238
238
 
239
- test("simple_stub_const is not available inside fixture blocks") do
239
+ test("with_stub_const is not available inside fixture blocks") do
240
240
  fixture_class = Class.new(Smartest::Fixture) do
241
241
  fixture :bad_constant_stub do
242
- simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :fixture_provider) { :fixture_provider }
242
+ with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :fixture_provider) { :fixture_provider }
243
243
  end
244
244
  end
245
245
 
@@ -251,7 +251,7 @@ test("simple_stub_const is not available inside fixture blocks") do
251
251
 
252
252
  expect(status).to eq(1)
253
253
  expect(output).to include("NoMethodError")
254
- expect(output).to include("simple_stub_const")
254
+ expect(output).to include("with_stub_const")
255
255
  expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
256
256
  end
257
257
 
@@ -697,7 +697,7 @@ test("caches fixture values within one test") do
697
697
  expect(calls).to eq(1)
698
698
  end
699
699
 
700
- test("suite fixtures are created once and cleaned up after the suite") do
700
+ test("suite fixtures are created once and torn down after the suite") do
701
701
  events = []
702
702
  servers = []
703
703
 
@@ -705,7 +705,7 @@ test("suite fixtures are created once and cleaned up after the suite") do
705
705
  suite_fixture :server do
706
706
  events << :server_setup
707
707
  server = Object.new
708
- cleanup { events << :server_cleanup }
708
+ on_teardown { events << :server_teardown }
709
709
  server
710
710
  end
711
711
  end
@@ -718,7 +718,7 @@ test("suite fixtures are created once and cleaned up after the suite") do
718
718
  status, = SmartestSelfTest.run_suite(suite)
719
719
 
720
720
  expect(status).to eq(0)
721
- expect(events).to eq(%i[server_setup first second server_cleanup])
721
+ expect(events).to eq(%i[server_setup first second server_teardown])
722
722
  expect(servers.length).to eq(2)
723
723
  expect(servers[0].object_id).to eq(servers[1].object_id)
724
724
  end
@@ -773,14 +773,14 @@ test("suite fixtures cannot depend on test fixtures") do
773
773
  expect(output).to include("suite-scoped fixture server cannot depend on test-scoped fixture user")
774
774
  end
775
775
 
776
- test("suite fixture setup failures are cached and cleaned up once") do
776
+ test("suite fixture setup failures are cached and torn down once") do
777
777
  calls = 0
778
778
  events = []
779
779
 
780
780
  fixture_class = Class.new(Smartest::Fixture) do
781
781
  suite_fixture :server do
782
782
  calls += 1
783
- cleanup { events << :server_cleanup }
783
+ on_teardown { events << :server_teardown }
784
784
  raise "server setup failed"
785
785
  end
786
786
  end
@@ -794,17 +794,17 @@ test("suite fixture setup failures are cached and cleaned up once") do
794
794
 
795
795
  expect(status).to eq(1)
796
796
  expect(calls).to eq(1)
797
- expect(events).to eq([:server_cleanup])
797
+ expect(events).to eq([:server_teardown])
798
798
  expect(output.scan("RuntimeError: server setup failed").length).to eq(2)
799
799
  end
800
800
 
801
- test("around_suite wraps tests and suite fixture cleanup") do
801
+ test("around_suite wraps tests and suite fixture teardown") do
802
802
  events = []
803
803
 
804
804
  fixture_class = Class.new(Smartest::Fixture) do
805
805
  suite_fixture :server do
806
806
  events << :server_setup
807
- cleanup { events << :server_cleanup }
807
+ on_teardown { events << :server_teardown }
808
808
  :server
809
809
  end
810
810
  end
@@ -821,7 +821,7 @@ test("around_suite wraps tests and suite fixture cleanup") do
821
821
  status, = SmartestSelfTest.run_suite(suite)
822
822
 
823
823
  expect(status).to eq(0)
824
- expect(events).to eq(%i[around_before server_setup test server_cleanup around_after])
824
+ expect(events).to eq(%i[around_before server_setup test server_teardown around_after])
825
825
  end
826
826
 
827
827
  test("around_suite hooks run in registration order") do
@@ -886,13 +886,13 @@ test("around_suite can register suite-wide around_test hooks") do
886
886
  expect(events).to eq(%i[around_test_before test around_test_after])
887
887
  end
888
888
 
889
- test("around_test wraps fixture setup, test body, and cleanup") do
889
+ test("around_test wraps fixture setup, test body, and teardown") do
890
890
  events = []
891
891
 
892
892
  fixture_class = Class.new(Smartest::Fixture) do
893
893
  fixture :resource do
894
894
  events << :fixture_setup
895
- cleanup { events << :fixture_cleanup }
895
+ on_teardown { events << :fixture_teardown }
896
896
  :resource
897
897
  end
898
898
  end
@@ -918,7 +918,7 @@ test("around_test wraps fixture setup, test body, and cleanup") do
918
918
  status, = SmartestSelfTest.run_suite(suite)
919
919
 
920
920
  expect(status).to eq(0)
921
- expect(events).to eq(%i[around_test_before fixture_setup test fixture_cleanup around_test_after])
921
+ expect(events).to eq(%i[around_test_before fixture_setup test fixture_teardown around_test_after])
922
922
  end
923
923
 
924
924
  test("around_test can register fixtures for one test run") do
@@ -1232,10 +1232,10 @@ test("around_suite must call suite.run") do
1232
1232
  expect(output).to include("Smartest::AroundSuiteRunError: around_suite hook did not call suite.run")
1233
1233
  end
1234
1234
 
1235
- test("suite cleanup failures fail the run") do
1235
+ test("suite teardown failures fail the run") do
1236
1236
  fixture_class = Class.new(Smartest::Fixture) do
1237
1237
  suite_fixture :browser do
1238
- cleanup { raise "browser close failed" }
1238
+ on_teardown { raise "browser close failed" }
1239
1239
  :browser
1240
1240
  end
1241
1241
  end
@@ -1247,22 +1247,22 @@ test("suite cleanup failures fail the run") do
1247
1247
  status, output = SmartestSelfTest.run_suite(suite)
1248
1248
 
1249
1249
  expect(status).to eq(1)
1250
- expect(output).to include("Suite cleanup failures:")
1251
- expect(output).to include("cleanup failed: RuntimeError: browser close failed")
1252
- expect(output).to include("1 test, 1 passed, 0 failed, 1 suite cleanup failed")
1250
+ expect(output).to include("Suite teardown failures:")
1251
+ expect(output).to include("teardown failed: RuntimeError: browser close failed")
1252
+ expect(output).to include("1 test, 1 passed, 0 failed, 1 suite teardown failed")
1253
1253
  end
1254
1254
 
1255
- test("runs cleanup in reverse order after failures") do
1255
+ test("runs teardown in reverse order after failures") do
1256
1256
  events = []
1257
1257
 
1258
1258
  fixture_class = Class.new(Smartest::Fixture) do
1259
1259
  fixture :server do
1260
- cleanup { events << :server }
1260
+ on_teardown { events << :server }
1261
1261
  :server
1262
1262
  end
1263
1263
 
1264
1264
  fixture :browser do |server:|
1265
- cleanup { events << :browser }
1265
+ on_teardown { events << :browser }
1266
1266
  server
1267
1267
  end
1268
1268
  end
@@ -1277,12 +1277,12 @@ test("runs cleanup in reverse order after failures") do
1277
1277
  expect(events).to eq(%i[browser server])
1278
1278
  end
1279
1279
 
1280
- test("runs cleanup when fixture setup fails after cleanup registration") do
1280
+ test("runs teardown when fixture setup fails after teardown registration") do
1281
1281
  events = []
1282
1282
 
1283
1283
  fixture_class = Class.new(Smartest::Fixture) do
1284
1284
  fixture :server do
1285
- cleanup { events << :server }
1285
+ on_teardown { events << :server }
1286
1286
  raise "server setup failed"
1287
1287
  end
1288
1288
  end
@@ -1298,6 +1298,25 @@ test("runs cleanup when fixture setup fails after cleanup registration") do
1298
1298
  expect(output).to include("RuntimeError: server setup failed")
1299
1299
  end
1300
1300
 
1301
+ test("does not keep cleanup as a fixture teardown alias") do
1302
+ fixture_class = Class.new(Smartest::Fixture) do
1303
+ fixture :server do
1304
+ cleanup { :server }
1305
+ :server
1306
+ end
1307
+ end
1308
+
1309
+ suite = Smartest::Suite.new
1310
+ suite.fixture_classes.add(fixture_class)
1311
+ suite.tests.add(SmartestSelfTest.test_case("needs server", proc { |server:| expect(server).to eq(:server) }))
1312
+
1313
+ status, output = SmartestSelfTest.run_suite(suite)
1314
+
1315
+ expect(status).to eq(1)
1316
+ expect(output).to include("NoMethodError")
1317
+ expect(output).to include("cleanup")
1318
+ end
1319
+
1301
1320
  test("duplicate fixture names fail the test") do
1302
1321
  first_fixture = Class.new(Smartest::Fixture) do
1303
1322
  fixture(:user) { "Alice" }
@@ -1435,6 +1454,44 @@ test("cli loads files and returns failure status") do
1435
1454
  end
1436
1455
  end
1437
1456
 
1457
+ test("cli expands directory paths to tests under that directory") do
1458
+ Dir.mktmpdir do |dir|
1459
+ smartest_dir = File.join(dir, "smartest")
1460
+ FileUtils.mkdir_p(File.join(smartest_dir, "nested"))
1461
+ File.write(File.join(smartest_dir, "test_helper.rb"), <<~RUBY)
1462
+ require "smartest/autorun"
1463
+ RUBY
1464
+ File.write(File.join(smartest_dir, "root_test.rb"), <<~RUBY)
1465
+ require "test_helper"
1466
+
1467
+ test("root directory test") do
1468
+ expect(1).to eq(1)
1469
+ end
1470
+ RUBY
1471
+ File.write(File.join(smartest_dir, "nested", "nested_test.rb"), <<~RUBY)
1472
+ require "test_helper"
1473
+
1474
+ test("nested directory test") do
1475
+ expect(2).to eq(2)
1476
+ end
1477
+ RUBY
1478
+
1479
+ stdout, stderr, status = Open3.capture3(
1480
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
1481
+ "ruby",
1482
+ File.expand_path("../exe/smartest", __dir__),
1483
+ "smartest/",
1484
+ chdir: dir
1485
+ )
1486
+
1487
+ expect(status.success?).to eq(true)
1488
+ expect(stderr).to eq("")
1489
+ expect(stdout).to include("root directory test")
1490
+ expect(stdout).to include("nested directory test")
1491
+ expect(stdout).to include("2 tests, 2 passed, 0 failed")
1492
+ end
1493
+ end
1494
+
1438
1495
  test("cli loads matcher files registered in test helper") do
1439
1496
  Dir.mktmpdir do |dir|
1440
1497
  smartest_dir = File.join(dir, "smartest")
@@ -1656,14 +1713,61 @@ test("cli prints help") do
1656
1713
  expect(status.success?).to eq(true)
1657
1714
  expect(stderr).to eq("")
1658
1715
  expect(stdout).to include("Usage:")
1659
- expect(stdout).to include("smartest [--profile N] [paths...]")
1660
- expect(stdout).to include("smartest [--profile N] path/to/test_file.rb:line[-line]")
1661
- expect(stdout).to include("smartest --init")
1662
- expect(stdout).to include("smartest --init-browser")
1663
- expect(stdout).to include("Use --profile N")
1716
+ expect(stdout).to include("bundle exec smartest [options] [paths...]")
1717
+ expect(stdout).to include("Common commands:")
1718
+ expect(stdout).to include("bundle exec smartest smartest/suite1/")
1719
+ expect(stdout).to include("Run test files matching smartest/suite1/**/*_test.rb")
1720
+ expect(stdout).to include("bundle exec smartest smartest/user_test.rb")
1721
+ expect(stdout).to include("bundle exec smartest smartest/user_test.rb:12")
1722
+ expect(stdout).not_to include("bundle exec smartest smartest/example_browser_test.rb")
1723
+ expect(stdout).not_to include("Run a browser test file")
1724
+ expect(stdout).to include("bundle exec smartest --init")
1725
+ expect(stdout).to include("bundle exec smartest --init-browser")
1726
+ expect(stdout).to include("--profile N")
1664
1727
  expect(stdout).to include("smartest/**/*_test.rb")
1665
1728
  end
1666
1729
 
1730
+ test("cli explains how to initialize when default smartest directory is missing") do
1731
+ Dir.mktmpdir do |dir|
1732
+ stdout, stderr, status = Open3.capture3(
1733
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
1734
+ "ruby",
1735
+ File.expand_path("../exe/smartest", __dir__),
1736
+ chdir: dir
1737
+ )
1738
+
1739
+ expect(status.success?).to eq(false)
1740
+ expect(stderr).to eq("")
1741
+ expect(stdout).to include("No smartest/ directory found.")
1742
+ expect(stdout).to include("bundle exec smartest --init")
1743
+ expect(stdout).to include("bundle exec smartest --init-browser")
1744
+ expect(stdout).to include("bundle exec smartest --help")
1745
+ end
1746
+ end
1747
+
1748
+ test("cli still runs explicit paths when default smartest directory is missing") do
1749
+ Dir.mktmpdir do |dir|
1750
+ File.write(File.join(dir, "sample_test.rb"), <<~RUBY)
1751
+ test("explicit path") do
1752
+ expect(1).to eq(1)
1753
+ end
1754
+ RUBY
1755
+
1756
+ stdout, stderr, status = Open3.capture3(
1757
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
1758
+ "ruby",
1759
+ File.expand_path("../exe/smartest", __dir__),
1760
+ "sample_test.rb",
1761
+ chdir: dir
1762
+ )
1763
+
1764
+ expect(status.success?).to eq(true)
1765
+ expect(stderr).to eq("")
1766
+ expect(stdout).to include("explicit path")
1767
+ expect(stdout).to include("1 test, 1 passed, 0 failed")
1768
+ end
1769
+ end
1770
+
1667
1771
  test("--profile prints the slowest tests with default count of 5") do
1668
1772
  output = StringIO.new
1669
1773
  reporter = Smartest::Reporter.new(output, profile_count: 5)
@@ -1760,7 +1864,9 @@ test("CLIArguments defaults profile count and parses --profile N") do
1760
1864
 
1761
1865
  expect(arguments.profile_count).to eq(5)
1762
1866
  expect(arguments.files).to eq(Dir["smartest/**/*_test.rb"])
1867
+ expect(arguments.default_paths?).to eq(true)
1763
1868
  expect(Smartest::CLIArguments.new(["--profile", "3"]).profile_count).to eq(3)
1869
+ expect(Smartest::CLIArguments.new(["smartest/foo_test.rb"]).default_paths?).to eq(false)
1764
1870
  end
1765
1871
 
1766
1872
  test("CLIArguments leaves unsupported profile forms as paths") do
data/smartest.gemspec CHANGED
@@ -7,8 +7,15 @@ Gem::Specification.new do |spec|
7
7
  spec.version = Smartest::VERSION
8
8
  spec.authors = ["Yusuke Iwaki"]
9
9
 
10
- spec.summary = "Pytest-style fixtures for Ruby."
11
- spec.description = "Smartest is a Ruby test runner with pytest-style fixture injection. Tests request fixtures using keyword arguments, fixtures can depend on other fixtures, and cleanup is registered only when needed."
10
+ spec.summary = "A Ruby test runner with pytest-style fixtures and Playwright-friendly browser testing."
11
+ spec.description = <<~TEXT
12
+ Smartest is a Ruby test runner that brings pytest-style fixture injection
13
+ to Ruby. Tests declare dependencies with keyword arguments, fixtures can
14
+ depend on other fixtures, and teardown is handled explicitly when needed.
15
+
16
+ Smartest is designed for readable Ruby tests, Rails system tests, and
17
+ Playwright-powered browser testing.
18
+ TEXT
12
19
  spec.homepage = "https://smartest-rb.vercel.app"
13
20
  spec.license = "MIT"
14
21
  spec.required_ruby_version = ">= 2.7"
@@ -17,7 +24,7 @@ Gem::Specification.new do |spec|
17
24
  "allowed_push_host" => "https://rubygems.org",
18
25
  "bug_tracker_uri" => "https://github.com/YusukeIwaki/smartest/issues",
19
26
  "changelog_uri" => "https://github.com/YusukeIwaki/smartest/blob/main/CHANGELOG.md",
20
- "documentation_uri" => "https://smartest-rb.vercel.app/docs/fixtures",
27
+ "documentation_uri" => "https://smartest-rb.vercel.app/docs",
21
28
  "homepage_uri" => spec.homepage,
22
29
  "rubygems_mfa_required" => "true",
23
30
  "source_code_uri" => "https://github.com/YusukeIwaki/smartest"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3.alpha4
4
+ version: 0.5.0.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke Iwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-04 00:00:00.000000000 Z
11
+ date: 2026-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,9 +24,13 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '13.0'
27
- description: Smartest is a Ruby test runner with pytest-style fixture injection. Tests
28
- request fixtures using keyword arguments, fixtures can depend on other fixtures,
29
- and cleanup is registered only when needed.
27
+ description: |
28
+ Smartest is a Ruby test runner that brings pytest-style fixture injection
29
+ to Ruby. Tests declare dependencies with keyword arguments, fixtures can
30
+ depend on other fixtures, and teardown is handled explicitly when needed.
31
+
32
+ Smartest is designed for readable Ruby tests, Rails system tests, and
33
+ Playwright-powered browser testing.
30
34
  email:
31
35
  executables:
32
36
  - smartest
@@ -82,7 +86,7 @@ metadata:
82
86
  allowed_push_host: https://rubygems.org
83
87
  bug_tracker_uri: https://github.com/YusukeIwaki/smartest/issues
84
88
  changelog_uri: https://github.com/YusukeIwaki/smartest/blob/main/CHANGELOG.md
85
- documentation_uri: https://smartest-rb.vercel.app/docs/fixtures
89
+ documentation_uri: https://smartest-rb.vercel.app/docs
86
90
  homepage_uri: https://smartest-rb.vercel.app
87
91
  rubygems_mfa_required: 'true'
88
92
  source_code_uri: https://github.com/YusukeIwaki/smartest
@@ -104,5 +108,6 @@ requirements: []
104
108
  rubygems_version: 3.4.19
105
109
  signing_key:
106
110
  specification_version: 4
107
- summary: Pytest-style fixtures for Ruby.
111
+ summary: A Ruby test runner with pytest-style fixtures and Playwright-friendly browser
112
+ testing.
108
113
  test_files: []