tasty-flaky 0.1.2.0 → 0.1.3.0
raw patch · 6 files changed
+51/−5 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +14/−0
- LICENSE +1/−1
- README.md +1/−1
- src/Test/Tasty/Flaky.hs +19/−2
- tasty-flaky.cabal +1/−1
- test/Main.hs +15/−0
CHANGELOG.md view
@@ -1,5 +1,19 @@ # Revision history for tasty-flaky +## 0.1.3.0 -- 2025-12-13++* Exceptions in tests will now be caught and considered test failures, even if the test runner+ doesn't catch the exception. This allows, for example, to retry on pattern match failure:++ ```haskell+ test :: TestTree+ test = testCase "Pattern match" $ do+ Just x <- f+ ...+ ```+ + This test will now be retried instead of throwing an exception.+ ## 0.1.2.0 -- 2025-02-10 * Add `flakyTestWithRetryAction`. Retry logic can now be based on test results (#1).
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2024, Laurent Rene de Cotret+Copyright (c), Laurent Rene de Cotret Redistribution and use in source and binary forms, with or without
README.md view
@@ -4,7 +4,7 @@ ## Example usage -This package provides a single function, `flakyTest`, which can attach retrying logic to *any* test.+This package provides functions, like `flakyTest`, which can attach retrying logic to *any* test. For example, you can retry test cases from [`tasty-hunit`](https://hackage.haskell.org/package/tasty-hunit) like so: ```haskell
src/Test/Tasty/Flaky.hs view
@@ -55,8 +55,10 @@ import Data.Functor ( (<&>) ) import Data.Tagged (Tagged, retag ) import Test.Tasty.Providers ( IsTest(..), Progress, Result, TestTree )-import Test.Tasty.Runners ( TestTree(..), Result(..), Progress(..), emptyProgress, resultSuccessful )+import Test.Tasty.Runners ( TestTree(..), Result(..), Progress(..), emptyProgress, resultSuccessful, Outcome (Failure), FailureReason (TestThrewException) ) import Test.Tasty.Options ( OptionDescription, OptionSet )+import Control.Exception (catch, SomeException, Exception (displayException))+import Test.Tasty.Providers.ConsoleFormat (noResultDetails) -- | A test tree of type @t@, with an associated retry policy@@ -136,7 +138,9 @@ -- the final result. go :: RetryStatus -> IO Result go status = do- result <- run opts test progressCallback+ -- We need to explicitly catch exceptions as some runnints, like HUnit,+ -- will not consider this strictly a test failure.+ result <- run opts test progressCallback `catch` (pure . exceptionResult) let done = pure $ annotateResult status result consultPolicy policy' = do rs <- applyAndDelay policy' status@@ -175,3 +179,16 @@ testOptions :: Tagged (FlakyTest t) [OptionDescription] testOptions = retag (testOptions :: Tagged t [OptionDescription])+++-- | Shortcut for creating a 'Result' that indicates exception+--+-- This is defined in `tasty`, but not exported :(+exceptionResult :: SomeException -> Result+exceptionResult e = Result+ { resultOutcome = Failure $ TestThrewException e+ , resultDescription = "Exception: " ++ displayException e+ , resultShortDescription = "FAIL"+ , resultTime = 0+ , resultDetailsPrinter = noResultDetails+ }
tasty-flaky.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.4 name: tasty-flaky-version: 0.1.2.0+version: 0.1.3.0 synopsis: Handle flaky Tasty-based tests description: Handle flaky Tasty-based tests, with configuration retry policies. homepage: https://github.com/LaurentRDC/tasty-flaky
test/Main.hs view
@@ -8,6 +8,7 @@ import Test.Tasty ( TestTree, testGroup, defaultMain, withResource ) import Test.Tasty.Flaky ( limitRetries, flakyTest ) import Test.Tasty.HUnit ( testCase, assertFailure )+import Control.Exception (throwIO) main :: IO ()@@ -15,6 +16,7 @@ $ testGroup "Test suite" [ testSuccessOnFirstTry , testFlakyWithRetries+ , testFlakyWithException , testFlakyWithRetriesProgressCallback ] @@ -35,6 +37,19 @@ unless (n == 0) $ do IORef.modifyIORef' ioref (\m -> m - 1) assertFailure "Not yet"+++-- This test will throw an exception until the contents of the IORef is zero+testFlakyWithException :: TestTree+testFlakyWithException + = flakyTest (limitRetries 4) + $ withResource (IORef.newIORef (3 :: Int)) (const $ pure ()) + $ \getioref -> testCase "exception" $ do+ ioref <- getioref+ n <- IORef.readIORef ioref+ unless (n == 0) $ do+ IORef.modifyIORef' ioref (\m -> m - 1)+ throwIO $ userError "Oh no!" -- This test will fail until the contents of the IORef is zero