Skip to content

Commit

Permalink
Add xit, xspecify, xdescribe and xcontext (see #252)
Browse files Browse the repository at this point in the history
  • Loading branch information
sol committed Oct 26, 2016
1 parent 0aaa24e commit 06afa64
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGES.markdown
@@ -1,4 +1,5 @@
## Changes next
- Add `xit`, `xspecify`, `xdescribe` and `xcontext` (see #252)
- Run around-hook for Bool and Result (see #252)
- More graceful shutdown on ctrl-c (see #270)
- Report exceptions in `beforeAll` operations only once
Expand Down
4 changes: 3 additions & 1 deletion hspec-core/src/Test/Hspec/Core/Hooks.hs
Expand Up @@ -17,7 +17,9 @@ module Test.Hspec.Core.Hooks (
import Control.Exception (SomeException, finally, throwIO, try)
import Control.Concurrent.MVar

import Test.Hspec.Core.Spec
import Test.Hspec.Core.Example
import Test.Hspec.Core.Tree
import Test.Hspec.Core.Spec.Monad

-- | Run a custom action before every spec item.
before :: IO a -> SpecWith a -> Spec
Expand Down
45 changes: 41 additions & 4 deletions hspec-core/src/Test/Hspec/Core/Spec.hs
Expand Up @@ -8,10 +8,16 @@
module Test.Hspec.Core.Spec (

-- * Defining a spec
describe
, it
it
, specify
, describe
, context
, pending
, pendingWith
, xit
, xspecify
, xdescribe
, xcontext
, parallel

-- * The @SpecM@ monad
Expand All @@ -30,13 +36,29 @@ import Data.CallStack
import Test.Hspec.Expectations (Expectation)

import Test.Hspec.Core.Example
import Test.Hspec.Core.Hooks
import Test.Hspec.Core.Tree
import Test.Hspec.Core.Spec.Monad

-- | The @describe@ function combines a list of specs into a larger spec.
describe :: String -> SpecWith a -> SpecWith a
describe label spec = runIO (runSpecM spec) >>= fromSpecList . return . specGroup label

-- | @context@ is an alias for `describe`.
context :: String -> SpecWith a -> SpecWith a
context = describe

-- |
-- Changing `describe` to `xdescribe` marks all spec items of the corresponding subtree as pending.
--
-- This can be used to temporarily disable spec items.
xdescribe :: String -> SpecWith a -> SpecWith a
xdescribe label spec = before_ pending $ describe label spec

-- | @xcontext@ is an alias for `xdescribe`.
xcontext :: String -> SpecWith a -> SpecWith a
xcontext = xdescribe

-- | The @it@ function creates a spec item.
--
-- A spec item consists of:
Expand All @@ -51,12 +73,27 @@ describe label spec = runIO (runSpecM spec) >>= fromSpecList . return . specGrou
it :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
it label action = fromSpecList [specItem label action]

-- | @specify@ is an alias for `it`.
specify :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
specify = it

-- |
-- Changing `it` to `xit` marks the corresponding spec item as pending.
--
-- This can be used to temporarily disable a spec item.
xit :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
xit label action = before_ pending $ it label action

-- | @xspecify@ is an alias for `xit`.
xspecify :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
xspecify = xit

-- | `parallel` marks all spec items of the given spec to be safe for parallel
-- evaluation.
parallel :: SpecWith a -> SpecWith a
parallel = mapSpecItem_ $ \item -> item {itemIsParallelizable = True}

-- | `pending` can be used to indicate that an example is /pending/.
-- | `pending` can be used to mark a spec item as pending.
--
-- If you want to textually specify a behavior but do not have an example yet,
-- use this:
Expand All @@ -69,6 +106,6 @@ pending = E.throwIO (Pending Nothing)

-- |
-- `pendingWith` is similar to `pending`, but it takes an additional string
-- argument that can be used to specify the reason for why it's pending.
-- argument that can be used to specify the reason for why the spec item is pending.
pendingWith :: String -> Expectation
pendingWith = E.throwIO . Pending . Just
12 changes: 12 additions & 0 deletions hspec-core/test/Test/Hspec/Core/SpecSpec.hs
Expand Up @@ -31,6 +31,12 @@ spec = do
[Node d _] <- runSpecM (H.describe "" (pure ()))
d `shouldBe` "(no description given)"

describe "xdescribe" $ do
it "creates a tree of pending examples" $ do
[Node _ [Leaf item]] <- runSpecM (H.xdescribe "" $ H.it "whatever" True)
Right r <- itemExample item defaultParams ($ ()) noOpProgressCallback
r `shouldBe` Pending Nothing

describe "it" $ do
it "takes a description of a desired behavior" $ do
[Leaf item] <- runSpecM (H.it "whatever" True)
Expand All @@ -56,6 +62,12 @@ spec = do
[Leaf item] <- runSpecM (H.it "" True)
itemRequirement item `shouldBe` "(unspecified behavior)"

describe "xit" $ do
it "creates a pending example" $ do
[Leaf item] <- runSpecM (H.xit "whatever" True)
Right r <- itemExample item defaultParams ($ ()) noOpProgressCallback
r `shouldBe` Pending Nothing

describe "pending" $ do
it "specifies a pending example" $ do
r <- runSpec $ do
Expand Down
28 changes: 16 additions & 12 deletions src/Test/Hspec.hs
Expand Up @@ -17,16 +17,28 @@ module Test.Hspec (
, module Test.Hspec.Expectations

-- * Defining a spec
, describe
, context
, it
, specify
, describe
, context
, example
, pending
, pendingWith
, parallel
, runIO

-- * Pending spec items
-- |
-- During a test run a /pending/ spec item is:
--
-- 1. not executed
--
-- 1. reported as \"pending\"
, pending
, pendingWith
, xit
, xspecify
, xdescribe
, xcontext

-- * Hooks
, ActionWith
, before
Expand Down Expand Up @@ -65,11 +77,3 @@ import Test.Hspec.Expectations
-- > putStrLn
example :: Expectation -> Expectation
example = id

-- | @context@ is an alias for `describe`.
context :: String -> SpecWith a -> SpecWith a
context = describe

-- | @specify@ is an alias for `it`.
specify :: Example a => String -> a -> SpecWith (Arg a)
specify = it

0 comments on commit 06afa64

Please sign in to comment.