diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for wai-extra
 
+## 3.1.0
+
+* `Network.Wai.Test`: Add support for source locations to assertion primitives [#817](https://github.com/yesodweb/wai/pull/817)
+
 ## 3.0.32
 
 * Undo previous two release, restore code from 3.0.29.2
@@ -10,7 +14,7 @@
 
 ## 3.0.30
 
-* `Network.Wai.Test`: Add support source locations to assertion primitives [#812](https://github.com/yesodweb/wai/pull/812)
+* `Network.Wai.Test`: Add support for source locations to assertion primitives [#812](https://github.com/yesodweb/wai/pull/812)
 
 ## 3.0.29.2
 
diff --git a/Network/Wai/Test.hs b/Network/Wai/Test.hs
--- a/Network/Wai/Test.hs
+++ b/Network/Wai/Test.hs
@@ -29,7 +29,6 @@
     , assertClientCookieExists
     , assertNoClientCookieExists
     , assertClientCookieValue
-    , WaiTestFailure (..)
     ) where
 
 #if __GLASGOW_HASKELL__ < 710
@@ -62,6 +61,8 @@
 import qualified Data.Text.Encoding as TE
 import Data.IORef
 import Data.Time.Clock (getCurrentTime)
+import qualified Test.HUnit as HUnit
+import Data.CallStack (HasCallStack)
 
 -- |
 --
@@ -206,20 +207,16 @@
   where
     (s, h, withBody) = responseToStream res
 
-assertBool :: String -> Bool -> Session ()
+assertBool :: HasCallStack => String -> Bool -> Session ()
 assertBool s b = unless b $ assertFailure s
 
-assertString :: String -> Session ()
+assertString :: HasCallStack => String -> Session ()
 assertString s = unless (null s) $ assertFailure s
 
-assertFailure :: String -> Session ()
-assertFailure msg = msg `deepseq` liftIO (throwIO (WaiTestFailure msg))
-
-data WaiTestFailure = WaiTestFailure String
-    deriving (Show, Eq, Typeable)
-instance Exception WaiTestFailure
+assertFailure :: HasCallStack => String -> Session ()
+assertFailure = liftIO . HUnit.assertFailure
 
-assertContentType :: ByteString -> SResponse -> Session ()
+assertContentType :: HasCallStack => ByteString -> SResponse -> Session ()
 assertContentType ct SResponse{simpleHeaders = h} =
     case lookup "content-type" h of
         Nothing -> assertString $ concat
@@ -236,7 +233,7 @@
   where
     go = S8.takeWhile (/= ';')
 
-assertStatus :: Int -> SResponse -> Session ()
+assertStatus :: HasCallStack => Int -> SResponse -> Session ()
 assertStatus i SResponse{simpleStatus = s} = assertBool (concat
     [ "Expected status code "
     , show i
@@ -246,7 +243,7 @@
   where
     sc = H.statusCode s
 
-assertBody :: L.ByteString -> SResponse -> Session ()
+assertBody :: HasCallStack => L.ByteString -> SResponse -> Session ()
 assertBody lbs SResponse{simpleBody = lbs'} = assertBool (concat
     [ "Expected response body "
     , show $ L8.unpack lbs
@@ -254,7 +251,7 @@
     , show $ L8.unpack lbs'
     ]) $ lbs == lbs'
 
-assertBodyContains :: L.ByteString -> SResponse -> Session ()
+assertBodyContains :: HasCallStack => L.ByteString -> SResponse -> Session ()
 assertBodyContains lbs SResponse{simpleBody = lbs'} = assertBool (concat
     [ "Expected response body to contain "
     , show $ L8.unpack lbs
@@ -264,7 +261,7 @@
   where
     strict = S.concat . L.toChunks
 
-assertHeader :: CI ByteString -> ByteString -> SResponse -> Session ()
+assertHeader :: HasCallStack => CI ByteString -> ByteString -> SResponse -> Session ()
 assertHeader header value SResponse{simpleHeaders = h} =
     case lookup header h of
         Nothing -> assertString $ concat
@@ -283,7 +280,7 @@
             , show value'
             ]) (value == value')
 
-assertNoHeader :: CI ByteString -> SResponse -> Session ()
+assertNoHeader :: HasCallStack => CI ByteString -> SResponse -> Session ()
 assertNoHeader header SResponse{simpleHeaders = h} =
     case lookup header h of
         Nothing -> return ()
@@ -297,7 +294,7 @@
 -- |
 --
 -- Since 3.0.6
-assertClientCookieExists :: String -> ByteString -> Session ()
+assertClientCookieExists :: HasCallStack => String -> ByteString -> Session ()
 assertClientCookieExists s cookieName = do
   cookies <- getClientCookies
   assertBool s $ Map.member cookieName cookies
@@ -305,7 +302,7 @@
 -- |
 --
 -- Since 3.0.6
-assertNoClientCookieExists :: String -> ByteString -> Session ()
+assertNoClientCookieExists :: HasCallStack => String -> ByteString -> Session ()
 assertNoClientCookieExists s cookieName = do
   cookies <- getClientCookies
   assertBool s $ not $ Map.member cookieName cookies
@@ -313,7 +310,7 @@
 -- |
 --
 -- Since 3.0.6
-assertClientCookieValue :: String -> ByteString -> ByteString -> Session ()
+assertClientCookieValue :: HasCallStack => String -> ByteString -> ByteString -> Session ()
 assertClientCookieValue s cookieName cookieValue = do
   cookies <- getClientCookies
   case Map.lookup cookieName cookies of
diff --git a/wai-extra.cabal b/wai-extra.cabal
--- a/wai-extra.cabal
+++ b/wai-extra.cabal
@@ -1,5 +1,5 @@
 Name:                wai-extra
-Version:             3.0.32
+Version:             3.1.0
 Synopsis:            Provides some basic WAI handlers and middleware.
 description:
   Provides basic WAI handler and middleware functionality:
@@ -87,7 +87,7 @@
   default:            False
 
 Library
-  Build-Depends:     base                      >= 4.8 && < 5
+  Build-Depends:     base                      >= 4.10 && < 5
                    , bytestring                >= 0.10.4
                    , wai                       >= 3.0.3.0  && < 3.3
                    , old-locale                >= 1.0.0.2  && < 1.1
@@ -116,6 +116,8 @@
                    , aeson
                    , iproute
                    , http2
+                   , HUnit
+                   , call-stack
 
   if os(windows)
       cpp-options:   -DWINDOWS
