Skip to content

Support for non-Identity generator monad #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.0.3

## Changed

- `runSpecAndExitProcess'` and `runSpecAndGetResults` now work for any test tree
generator monad, via the new `TestTreeGenerator` class.

## 0.0.2

### Changed
Expand Down
85 changes: 77 additions & 8 deletions src/Node.purs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Node.Process (exit')
import Test.Spec (Spec)
import Test.Spec (SpecT, Spec)
import Test.Spec.Result (Result)
import Test.Spec.Runner (Reporter)
import Test.Spec.Runner as Spec
Expand All @@ -19,6 +19,9 @@ import Test.Spec.Tree (Tree)

-- | Runs the given spec, using configuration derived from CLI options (if any),
-- | and exits the process with an exit indicating success or failure.
-- |
-- | For more control over the configuration or test tree generating monad, use
-- | `runSpecAndExitProcess'`.
runSpecAndExitProcess :: Array Reporter -> Spec Unit -> Effect Unit
runSpecAndExitProcess =
runSpecAndExitProcess' { defaultConfig: Cfg.defaultConfig, parseCLIOptions: true }
Expand All @@ -29,12 +32,26 @@ runSpecAndExitProcess =
-- | The `parseCLIOptions` parameter determines whether the `defaultConfig`
-- | should be used as is or CLI options (if any provided) should be applied on
-- | top of it.
runSpecAndExitProcess' :: ∀ c.
{ defaultConfig :: Cfg.TestRunConfig' c
, parseCLIOptions :: Boolean
}
-- |
-- | Note that, because this function works for any test tree generator monad
-- | `m`, you will need to specify it somehow. You can either give the spec
-- | parameter an explicit type:
-- |
-- | spec :: SpecT Aff Unit Aff Unit
-- | spec = do
-- | ...
-- |
-- | Or specify the monad via visible type application:
-- |
-- | runSpecAndExitProcess' @Aff ...
-- |
runSpecAndExitProcess' :: ∀ @m c.
TestTreeGenerator m
=> { defaultConfig :: Cfg.TestRunConfig' c
, parseCLIOptions :: Boolean
}
-> Array Reporter
-> Spec Unit
-> SpecT Aff Unit m Unit
-> Effect Unit
runSpecAndExitProcess' args reporters spec = launchAff_ do
config <-
Expand All @@ -45,9 +62,61 @@ runSpecAndExitProcess' args reporters spec = launchAff_ do
res <- runSpecAndGetResults config reporters spec
liftEffect $ exit' $ if successful res then 0 else 1

runSpecAndGetResults :: ∀ c. Cfg.TestRunConfig' c -> Array Reporter -> Spec Unit -> Aff (Array (Tree String Void Result))
-- | The core logic of a persistent test run:
-- |
-- | * Runs the spec tree generation in the given monad `m` (which is usually
-- | just `Identity`, but can be different in most complex scenarios)
-- | * Persists results to disk.
-- | * Returns the tree of results.
-- |
runSpecAndGetResults :: ∀ c m
. TestTreeGenerator m
=> Cfg.TestRunConfig' c
-> Array Reporter
-> SpecT Aff Unit m Unit
-> Aff (Array (Tree String Void Result))
runSpecAndGetResults config reporters spec = do
specCfg <- Cfg.toSpecConfig config <#> _ { exit = false }
results <- un Identity $ Spec.evalSpecT specCfg reporters spec
results <- generateTestTree $ Spec.evalSpecT specCfg reporters spec
Persist.persistResults results
pure results

-- | A monad in which test tree generation happens. This is different from the
-- | monad in which the tests themselves run.
-- |
-- | In most cases the test tree would be generated in `Identity`, making for
-- | deterministic, pure test trees:
-- |
-- | spec :: SpecT Aff Unit Identity Unit
-- | spec = do
-- | it "is a pure test" do
-- | (2 + 2) `shouldEqual` 4
-- |
-- | But in more complicated scenarios, you might want to generate test trees in
-- | a more powerful monad. For example, the following test tree is generated in
-- | the `Effect` monad, utilizing the effectful function `randomInt` to
-- | determine the number of tests to generate:
-- |
-- | spec :: SpecT Aff Unit Effect Unit
-- | spec = do
-- | numTests <- randomInt 1 10
-- | for_ numTests \i -> do
-- | it ("is test number " <> show i) do
-- | (i + i - i) `shouldEqual` i
-- |
-- | This class assumes that the monad can be evaluated without any additional
-- | parameters. This allows for most normal use cases with ergonomic API. For
-- | more complicated cases, where the generator monad requires something extra
-- | (such as `StateT` or `ReaderT`), you can always use the `mapSpecTree`
-- | function to transform the generated test tree before running it.
class Monad m <= TestTreeGenerator m where
-- | Evaluates the test tree generator monad, returning the generated test
-- | tree. See comments on the `TestTreeGenerator` class for more information.
generateTestTree :: ∀ a. m (Aff a) -> Aff a

instance TestTreeGenerator Identity where
generateTestTree = un Identity
instance TestTreeGenerator Aff where
generateTestTree = join
instance TestTreeGenerator Effect where
generateTestTree = liftEffect >>> join
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Summary
0/0 tests passed
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
✓︎ test number 1
✓︎ test number 2
✓︎ test number 3

Summary
3/3 tests passed
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
✓︎ test number 1
✓︎ test number 2
✓︎ test number 3
✓︎ test number 4
✓︎ test number 5

Summary
5/5 tests passed
Loading