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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -17
- data/DEVELOPMENT.md +48 -28
- data/README.md +69 -29
- data/SMARTEST_DESIGN.md +53 -36
- data/exe/smartest +50 -11
- data/lib/smartest/cli_arguments.rb +26 -3
- data/lib/smartest/constant_stub_helpers.rb +4 -4
- data/lib/smartest/fixture.rb +5 -5
- data/lib/smartest/fixture_set.rb +7 -7
- data/lib/smartest/init_browser_generator.rb +3 -3
- data/lib/smartest/reporter.rb +12 -12
- data/lib/smartest/runner.rb +14 -14
- data/lib/smartest/test_result.rb +11 -11
- data/lib/smartest/version.rb +1 -1
- data/smartest/simple_stub_test.rb +18 -18
- data/smartest/smartest_test.rb +133 -27
- data/smartest.gemspec +10 -3
- metadata +12 -7
data/lib/smartest/runner.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Smartest
|
|
|
10
10
|
|
|
11
11
|
def run
|
|
12
12
|
results = []
|
|
13
|
-
|
|
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,
|
|
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
|
-
|
|
31
|
+
suite_teardown_errors: suite_teardown_errors,
|
|
32
32
|
suite_errors: suite_errors
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
-
results.any?(&:failed?) ||
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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 ||
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
126
|
+
teardown_errors.concat(fixture_set.run_teardowns) if fixture_set
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
|
data/lib/smartest/test_result.rb
CHANGED
|
@@ -2,59 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
module Smartest
|
|
4
4
|
class TestResult
|
|
5
|
-
attr_reader :test_case, :status, :error, :duration, :
|
|
5
|
+
attr_reader :test_case, :status, :error, :duration, :teardown_errors, :reason
|
|
6
6
|
|
|
7
|
-
def self.passed(test_case:, duration:,
|
|
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
|
-
|
|
14
|
+
teardown_errors: teardown_errors
|
|
15
15
|
)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def self.failed(test_case:, error:, duration:,
|
|
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
|
-
|
|
25
|
+
teardown_errors: teardown_errors
|
|
26
26
|
)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def self.skipped(test_case:, reason:, duration:,
|
|
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
|
-
|
|
36
|
+
teardown_errors: teardown_errors
|
|
37
37
|
)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def self.pending(test_case:, reason:, duration:,
|
|
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
|
-
|
|
47
|
+
teardown_errors: teardown_errors
|
|
48
48
|
)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def initialize(test_case:, status:, error:, reason:, duration:,
|
|
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
|
-
@
|
|
57
|
+
@teardown_errors = teardown_errors
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def passed?
|
data/lib/smartest/version.rb
CHANGED
|
@@ -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
|
|
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
|
|
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("
|
|
162
|
-
result =
|
|
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("
|
|
172
|
-
|
|
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("
|
|
179
|
+
test("with_stub_const restores constants when the block raises") do
|
|
180
180
|
error = SimpleStubSelfTest.capture_error(RuntimeError) do
|
|
181
|
-
|
|
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("
|
|
191
|
+
test("with_stub_const requires a block") do
|
|
192
192
|
error = SimpleStubSelfTest.capture_error(ArgumentError) do
|
|
193
|
-
|
|
193
|
+
with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider)
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
-
expect(error.message).to eq("
|
|
196
|
+
expect(error.message).to eq("with_stub_const block is required")
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
-
test("
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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("
|
|
254
|
+
expect(output).to include("with_stub_const")
|
|
255
255
|
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
|
|
256
256
|
end
|
|
257
257
|
|
data/smartest/smartest_test.rb
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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([:
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
1251
|
-
expect(output).to include("
|
|
1252
|
-
expect(output).to include("1 test, 1 passed, 0 failed, 1 suite
|
|
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
|
|
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
|
-
|
|
1260
|
+
on_teardown { events << :server }
|
|
1261
1261
|
:server
|
|
1262
1262
|
end
|
|
1263
1263
|
|
|
1264
1264
|
fixture :browser do |server:|
|
|
1265
|
-
|
|
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
|
|
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
|
-
|
|
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 [
|
|
1660
|
-
expect(stdout).to include("
|
|
1661
|
-
expect(stdout).to include("smartest
|
|
1662
|
-
expect(stdout).to include("smartest
|
|
1663
|
-
expect(stdout).to include("
|
|
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 = "
|
|
11
|
-
spec.description =
|
|
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
|
|
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.
|
|
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-
|
|
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:
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
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:
|
|
111
|
+
summary: A Ruby test runner with pytest-style fixtures and Playwright-friendly browser
|
|
112
|
+
testing.
|
|
108
113
|
test_files: []
|