smartest 0.1.0 → 0.2.0.alpha2

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
2
  SHA256:
3
- metadata.gz: 7b82e9b950c32ec5f3a65ca3a99eb123e1befcacedd8f6960cc8ace06a750a10
4
- data.tar.gz: 9ad2694c4ac24b45fc848b3d9d1f4ec0470c5a1895a75f057ee50f4fa091236d
3
+ metadata.gz: e0953c11bf61f80c4a310701920e5b6a22727149ed135d86678b3e49b25c8a92
4
+ data.tar.gz: d51839a9cb597da3d63a15aa803661946ceb3ae2a6982317ea108797f4203380
5
5
  SHA512:
6
- metadata.gz: 22900d08d05c65b6f3ec4fba2a694dd93521d3942592c49d5066c911b475a8e64847e45e25e068e7424129afe2d0756319b1e559e75996e616245d057f8b852d
7
- data.tar.gz: f97daa9190ccfa9698c6a0c7c4655e3fd4a3f3df888333dd4fef954d8aa4332239e2d037481b01b56bf09b8d8e56c49c6b874b78fd8f506dcfc0f77605fe5320
6
+ metadata.gz: 2e3be2ebdc5b116e6f16e396d4befda198c0063bb4da6e7f487266642d1edd8083bcc4dce9b37746969fdcbd9916424068f043344cc732edf4738f849fb87d9c
7
+ data.tar.gz: 0c299af8b8dd05fac80ec1eefaeade8f747f8d2776e87ba6cb684ff84c619be8a21dfd3e33c99fa43d05ee0d40aabc361f86ab1e33af696a5a9ef4c9ee78054d
data/DEVELOPMENT.md CHANGED
@@ -102,7 +102,8 @@ Responsibilities:
102
102
 
103
103
  - test registry
104
104
  - fixture class registry
105
- - hook registry, if hooks are implemented later
105
+ - matcher registry
106
+ - `around_suite` hook registry
106
107
 
107
108
  Example shape:
108
109
 
@@ -125,10 +126,14 @@ Required methods:
125
126
 
126
127
  ```ruby
127
128
  test(name, **metadata, &block)
128
- use_fixture(klass)
129
- use_matcher(matcher_module)
129
+ around_suite(&block)
130
+ around_test(&block)
130
131
  ```
131
132
 
133
+ `use_fixture(klass)` and `use_matcher(matcher_module)` are not top-level DSL
134
+ methods. They are available only from hook execution contexts: `around_suite`
135
+ and `around_test`.
136
+
132
137
  Possible later methods:
133
138
 
134
139
  ```ruby
@@ -219,6 +224,7 @@ Responsibilities:
219
224
  - supports inheritance
220
225
  - exposes `cleanup` to fixture blocks
221
226
  - optionally delegates helper methods to `ExecutionContext`
227
+ - does not delegate `skip` or `pending` to fixture blocks
222
228
 
223
229
  Fixture definitions should not execute at declaration time.
224
230
 
@@ -263,7 +269,10 @@ Responsibilities:
263
269
  Example:
264
270
 
265
271
  ```ruby
266
- use_fixture AppFixture
272
+ around_suite do |suite|
273
+ use_fixture AppFixture
274
+ suite.run
275
+ end
267
276
  ```
268
277
 
269
278
  should register `AppFixture`.
@@ -298,6 +307,7 @@ Responsibilities:
298
307
 
299
308
  - include expectation methods
300
309
  - include matchers
310
+ - expose `skip` and `pending` to test bodies
301
311
  - expose helper methods
302
312
  - optionally provide integration helpers later
303
313
 
@@ -314,21 +324,29 @@ Runs tests.
314
324
  Responsibilities:
315
325
 
316
326
  - iterate over registered test cases
327
+ - run registered `around_suite` hooks around the suite body
317
328
  - create a lazy suite-scoped `FixtureSet`
318
329
  - create a fresh `ExecutionContext` per test
319
330
  - create a fresh `FixtureSet` per test
320
331
  - resolve test keyword fixtures
321
332
  - run test body
322
333
  - run cleanup in `ensure`
334
+ - track skipped and pending test state
323
335
  - run suite fixture cleanup after all tests
324
336
  - produce `TestResult`
325
337
  - notify reporter
326
338
 
339
+ `around_suite` hooks receive a run target and must call `suite.run` exactly once.
340
+ Registered hooks compose in registration order, so the first hook is the
341
+ outermost wrapper. If a hook raises or does not call `suite.run`, the runner
342
+ reports a suite failure and exits with status `1`.
343
+
327
344
  Pseudo-code:
328
345
 
329
346
  ```ruby
330
347
  def run_one(test_case)
331
- context = ExecutionContext.new
348
+ run_state = TestRunState.new
349
+ context = ExecutionContext.new(run_state: run_state)
332
350
  fixture_set = FixtureSet.new(
333
351
  @fixture_classes,
334
352
  context: context,
@@ -339,9 +357,19 @@ def run_one(test_case)
339
357
 
340
358
  context.instance_exec(**kwargs, &test_case.block)
341
359
 
342
- TestResult.passed(test_case)
360
+ if run_state.pending?
361
+ TestResult.failed(test_case, PendingPassedError.new(run_state.pending_reason))
362
+ else
363
+ TestResult.passed(test_case)
364
+ end
365
+ rescue Skipped => skipped
366
+ TestResult.skipped(test_case, skipped.reason)
343
367
  rescue Exception => error
344
- TestResult.failed(test_case, error)
368
+ if run_state.pending?
369
+ TestResult.pending(test_case, run_state.pending_reason)
370
+ else
371
+ TestResult.failed(test_case, error)
372
+ end
345
373
  ensure
346
374
  fixture_set&.run_cleanups
347
375
  end
@@ -356,13 +384,15 @@ Fields:
356
384
  - test case
357
385
  - status
358
386
  - error
387
+ - reason
359
388
  - duration
360
389
 
361
390
  Statuses:
362
391
 
363
392
  - passed
364
393
  - failed
365
- - skipped, later
394
+ - skipped
395
+ - pending
366
396
 
367
397
  ### `Smartest::Reporter`
368
398
 
@@ -371,7 +401,7 @@ Console reporter for MVP.
371
401
  Responsibilities:
372
402
 
373
403
  - print run start
374
- - print per-test pass/fail
404
+ - print per-test pass/fail/skip/pending
375
405
  - print failure details
376
406
  - print summary
377
407
  - return appropriate exit status through runner
@@ -551,6 +581,8 @@ module Smartest
551
581
  class CircularFixtureDependencyError < Error; end
552
582
  class InvalidFixtureParameterError < Error; end
553
583
  class AssertionFailed < Error; end
584
+ class Skipped < Error; end
585
+ class PendingPassedError < AssertionFailed; end
554
586
  end
555
587
  ```
556
588
 
@@ -577,7 +609,7 @@ A practical approach:
577
609
 
578
610
  - `Smartest::Fixture`
579
611
  - `fixture :name do ... end`
580
- - `use_fixture`
612
+ - `use_fixture` from a hook context
581
613
  - test block keyword fixture resolution
582
614
 
583
615
  ### Phase 3: Fixture dependencies
@@ -620,6 +652,30 @@ A practical approach:
620
652
  - generate a `smartest/test_helper.rb` that loads `smartest/fixtures/**/*.rb`
621
653
  - exit code 0 on success, 1 on failure
622
654
 
655
+ ### Phase 7: Suite hooks
656
+
657
+ - `around_suite do |suite| ... end`
658
+ - run hooks around the full suite body
659
+ - include suite fixture cleanup inside the wrapped body
660
+ - report hook failures as suite failures
661
+
662
+ ### Phase 8: Test hooks
663
+
664
+ - `around_test do |test| ... end`
665
+ - snapshot file-local hooks when each test is registered
666
+ - run hooks around fixture setup, test body, and fixture cleanup
667
+ - expose `use_fixture` and `use_matcher` only inside hook contexts
668
+ - make `around_test` registered from `around_suite` suite-wide
669
+
670
+ ### Phase 9: Skipped and pending tests
671
+
672
+ - `skip "reason"` inside test bodies and `around_test` hooks
673
+ - `pending "reason"` inside test bodies and `around_test` hooks
674
+ - skipped tests do not fail the run
675
+ - pending tests pass only when the remaining execution fails
676
+ - pending tests fail with `Smartest::PendingPassedError` when they pass
677
+ - `skip` and `pending` are not `test` metadata
678
+
623
679
  ## MVP API rules
624
680
 
625
681
  Supported:
@@ -629,6 +685,19 @@ test("name") do
629
685
  end
630
686
  ```
631
687
 
688
+ ```ruby
689
+ test("name") do
690
+ skip "reason" if runtime_condition?
691
+ end
692
+ ```
693
+
694
+ ```ruby
695
+ test("name") do
696
+ pending "reason" if expected_to_fail?
697
+ expect(actual).to eq(expected)
698
+ end
699
+ ```
700
+
632
701
  ```ruby
633
702
  test("name") do |user:|
634
703
  end
@@ -648,6 +717,19 @@ end
648
717
  cleanup { ... }
649
718
  ```
650
719
 
720
+ ```ruby
721
+ around_suite do |suite|
722
+ suite.run
723
+ end
724
+ ```
725
+
726
+ ```ruby
727
+ around_test do |test|
728
+ pending "reason" if expected_to_fail?
729
+ test.run
730
+ end
731
+ ```
732
+
651
733
  Not supported in MVP:
652
734
 
653
735
  ```ruby
@@ -665,6 +747,16 @@ fixture :client, with: [:server] do |server|
665
747
  end
666
748
  ```
667
749
 
750
+ ```ruby
751
+ test("name", skip: true) do
752
+ end
753
+ ```
754
+
755
+ ```ruby
756
+ test("name", pending: true) do
757
+ end
758
+ ```
759
+
668
760
  ```ruby
669
761
  resource :server do |use|
670
762
  end
data/README.md CHANGED
@@ -143,6 +143,34 @@ end
143
143
 
144
144
  This makes fixture usage explicit and avoids relying on positional argument order.
145
145
 
146
+ ## Skipping and pending tests
147
+
148
+ Use `skip` at the start of a test when the rest of the body should not run:
149
+
150
+ ```ruby
151
+ test("PDF export") do |browser:|
152
+ skip "firefox is not supported" if browser.firefox?
153
+
154
+ export_pdf(browser)
155
+ end
156
+ ```
157
+
158
+ Use `pending` when the test should continue running but is expected to fail. If
159
+ the test passes after `pending`, Smartest fails it so the stale pending marker is
160
+ removed.
161
+
162
+ ```ruby
163
+ test("PDF export") do |browser:|
164
+ pending "Not supported by WebDriver BiDi yet" if browser.bidi?
165
+
166
+ export_pdf(browser)
167
+ end
168
+ ```
169
+
170
+ `skip` and `pending` are available in test bodies and `around_test` hooks, but
171
+ not as `test` metadata or fixture APIs. See
172
+ [Skipping Tests](documentation/docs/skipping-tests.md).
173
+
146
174
  ## Expectations
147
175
 
148
176
  Smartest uses an expectation style:
@@ -173,9 +201,9 @@ be_nil
173
201
  raise_error(ErrorClass)
174
202
  ```
175
203
 
176
- Custom matcher modules can be registered with `use_matcher`. The generated
177
- scaffold includes a `PredicateMatcher` custom matcher for `be_<predicate>` calls.
178
- See [Matchers](documentation/docs/matchers.md).
204
+ Custom matcher modules can be registered from `around_suite` or `around_test`
205
+ with `use_matcher`. The generated scaffold includes a `PredicateMatcher` custom
206
+ matcher for `be_<predicate>` calls. See [Matchers](documentation/docs/matchers.md).
179
207
 
180
208
  ## Fixtures
181
209
 
@@ -192,10 +220,13 @@ class AppFixture < Smartest::Fixture
192
220
  end
193
221
  ```
194
222
 
195
- Register fixture classes from `smartest/test_helper.rb`:
223
+ Register fixture classes from `around_suite` in `smartest/test_helper.rb`:
196
224
 
197
225
  ```ruby
198
- use_fixture AppFixture
226
+ around_suite do |suite|
227
+ use_fixture AppFixture
228
+ suite.run
229
+ end
199
230
  ```
200
231
 
201
232
  Tests request fixtures by keyword:
@@ -274,6 +305,100 @@ Suite fixtures are lazy: setup runs the first time a test requests the fixture,
274
305
  and cleanup runs once after all tests finish. Test-scoped fixtures can depend on
275
306
  suite fixtures, but suite fixtures cannot depend on test-scoped fixtures.
276
307
 
308
+ ## Suite hooks
309
+
310
+ Use `around_suite` when the full test run must execute inside another block:
311
+
312
+ ```ruby
313
+ around_suite do |suite|
314
+ Async do
315
+ suite.run
316
+ end
317
+ end
318
+ ```
319
+
320
+ The hook receives a run target and must call `suite.run` exactly once. The block
321
+ wraps every test, test-scoped fixture setup and cleanup, suite fixture setup, and
322
+ suite fixture cleanup.
323
+
324
+ Fixture and matcher registrations made before `suite.run` are applied to that
325
+ run:
326
+
327
+ ```ruby
328
+ around_suite do |suite|
329
+ use_fixture GlobalFixture
330
+ suite.run
331
+ end
332
+ ```
333
+
334
+ Multiple `around_suite` hooks run in registration order. The first hook is the
335
+ outermost wrapper:
336
+
337
+ ```ruby
338
+ around_suite do |suite|
339
+ with_outer_resource { suite.run }
340
+ end
341
+
342
+ around_suite do |suite|
343
+ with_inner_resource { suite.run }
344
+ end
345
+ ```
346
+
347
+ If an `around_suite` hook raises or does not call `suite.run`, Smartest reports a
348
+ suite failure and exits with status `1`.
349
+
350
+ ## Test hooks
351
+
352
+ Use `around_test` when each test needs to run inside another block:
353
+
354
+ ```ruby
355
+ around_test do |test|
356
+ SomeAutoCloseResource.new do
357
+ test.run
358
+ end
359
+ end
360
+ ```
361
+
362
+ The hook receives a run target and must call `test.run` exactly once. It wraps
363
+ fixture setup, the test body, and fixture cleanup.
364
+
365
+ `around_test` is file-scoped when it is written directly in a test file. Smartest
366
+ copies the current file's `around_test` hooks when each `test` is registered, so
367
+ hooks apply to tests defined later in the same file.
368
+
369
+ Define `around_test` inside `around_suite` when the hook should apply to the
370
+ whole run:
371
+
372
+ ```ruby
373
+ around_suite do |suite|
374
+ around_test do |test|
375
+ with_some_resource do
376
+ test.run
377
+ end
378
+ end
379
+
380
+ suite.run
381
+ end
382
+ ```
383
+
384
+ `around_test` can also register fixture classes or matcher modules for that test
385
+ run:
386
+
387
+ ```ruby
388
+ around_test do |test|
389
+ use_fixture LocalFixture
390
+ use_matcher LocalMatcher
391
+ test.run
392
+ end
393
+ ```
394
+
395
+ Fixture classes registered from `around_test` must define only test-scoped
396
+ fixtures. If a class defines `suite_fixture`, register it from `around_suite`
397
+ instead so its cache and cleanup belong to the suite lifecycle.
398
+
399
+ `use_fixture` and `use_matcher` are only available inside `around_suite` or
400
+ `around_test` blocks. They are not top-level DSL methods.
401
+
277
402
  ## Fixtures with teardown
278
403
 
279
404
  Not every fixture needs teardown. For fixtures that do, use `cleanup`.
@@ -355,7 +480,10 @@ end
355
480
 
356
481
  ```ruby
357
482
  # smartest/test_helper.rb
358
- use_fixture WebFixture
483
+ around_suite do |suite|
484
+ use_fixture WebFixture
485
+ suite.run
486
+ end
359
487
  ```
360
488
 
361
489
  ```ruby
@@ -391,41 +519,34 @@ server cleanup
391
519
 
392
520
  ## Registering fixture classes
393
521
 
394
- Use `use_fixture` from `smartest/test_helper.rb`:
522
+ Use `use_fixture` inside `around_suite` from `smartest/test_helper.rb`:
395
523
 
396
524
  ```ruby
397
- use_fixture AppFixture
525
+ around_suite do |suite|
526
+ use_fixture AppFixture
527
+ suite.run
528
+ end
398
529
  ```
399
530
 
400
531
  Multiple fixture classes can be registered:
401
532
 
402
533
  ```ruby
403
- use_fixture UserFixture
404
- use_fixture WebFixture
405
- use_fixture ApiFixture
534
+ around_suite do |suite|
535
+ use_fixture UserFixture
536
+ use_fixture WebFixture
537
+ use_fixture ApiFixture
538
+ suite.run
539
+ end
406
540
  ```
407
541
 
408
542
  Fixture names must be unique across registered fixture classes.
409
543
 
410
544
  If two fixture classes define the same fixture name, Smartest raises an error.
411
545
 
412
- ## Hooks
546
+ ## Suite hooks and fixture cleanup
413
547
 
414
- Smartest may support simple hooks:
415
-
416
- ```ruby
417
- before do
418
- DatabaseCleaner.start
419
- end
420
-
421
- after do
422
- DatabaseCleaner.clean
423
- end
424
- ```
425
-
426
- Hooks are separate from fixture cleanup.
427
-
428
- Use fixture cleanup for resource-specific teardown:
548
+ Suite hooks are separate from fixture cleanup. Use fixture cleanup for
549
+ resource-specific teardown:
429
550
 
430
551
  ```ruby
431
552
  fixture :server do
@@ -435,11 +556,11 @@ fixture :server do
435
556
  end
436
557
  ```
437
558
 
438
- Use hooks for broad test-level behavior:
559
+ Use `around_suite` for broad suite-level execution context:
439
560
 
440
561
  ```ruby
441
- before do
442
- reset_global_state
562
+ around_suite do |suite|
563
+ Async { suite.run }
443
564
  end
444
565
  ```
445
566
 
@@ -469,13 +590,16 @@ Dir[File.join(__dir__, "matchers", "**", "*.rb")].sort.each do |matcher_file|
469
590
  require matcher_file
470
591
  end
471
592
 
472
- use_fixture WebFixture
473
- use_matcher PredicateMatcher
593
+ around_suite do |suite|
594
+ use_fixture WebFixture
595
+ use_matcher PredicateMatcher
596
+ suite.run
597
+ end
474
598
  ```
475
599
 
476
600
  The generated helper loads Ruby files under `smartest/fixtures/` and
477
- `smartest/matchers/` in sorted order. Register fixture classes and matcher
478
- modules from the helper with `use_fixture` and `use_matcher`.
601
+ `smartest/matchers/` in sorted order. Register suite-wide fixture classes and
602
+ matcher modules from `around_suite` with `use_fixture` and `use_matcher`.
479
603
 
480
604
  Example:
481
605
 
@@ -550,6 +674,9 @@ The intended MVP includes:
550
674
  - keyword-argument fixture injection
551
675
  - fixture dependencies through keyword arguments
552
676
  - fixture cleanup
677
+ - suite hooks with `around_suite`
678
+ - test hooks with `around_test`
679
+ - skipped and pending tests through `skip` and `pending`
553
680
  - `expect(...).to eq(...)`
554
681
  - console reporter
555
682
  - CLI runner