diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,18 @@
 # ChangeLog for yesod-test
 
+
+## 1.6.22
+
+- Add upper bounds to all build dependencies to comply with Hackage upload requirements. [#1873](https://github.com/yesodweb/yesod/pull/1873)
+
+## 1.6.21
+
+* Add `browseBody` to yesod-test. [#1872](https://github.com/yesodweb/yesod/pull/1872)
+
+## 1.6.20
+
+* Add `HasCallStack` to more functions. [#1858](https://github.com/yesodweb/yesod/pull/1858)
+
 ## 1.6.19
 
 * Add `selectByLabel` to yesod-test. [#1845](https://github.com/yesodweb/yesod/pull/1845)
diff --git a/Yesod/Test.hs b/Yesod/Test.hs
--- a/Yesod/Test.hs
+++ b/Yesod/Test.hs
@@ -218,6 +218,7 @@
 
     -- * Debug output
     , printBody
+    , browseBody
     , printMatches
 
     -- * Utils for building your own assertions
@@ -285,6 +286,10 @@
 import Yesod.Test.Internal (getBodyTextPreview, contentTypeHeaderIsUtf8)
 import Yesod.Test.Internal.SIO
 
+import System.Directory (getTemporaryDirectory)
+import System.Info (os)
+import System.Process (callCommand)
+
 {-# DEPRECATED byLabel "This function seems to have multiple bugs (ref: https://github.com/yesodweb/yesod/pull/1459). Use byLabelExact, byLabelContain, byLabelPrefix or byLabelSuffix instead" #-}
 {-# DEPRECATED fileByLabel "This function seems to have multiple bugs (ref: https://github.com/yesodweb/yesod/pull/1459). Use fileByLabelExact, fileByLabelContain, fileByLabelPrefix or fileByLabelSuffix instead" #-}
 
@@ -810,6 +815,29 @@
 printBody = withResponse $ \ SResponse { simpleBody = b } ->
   liftIO $ BSL8.hPutStrLn stderr b
 
+-- | Render the last response and open it in a web browser
+--
+-- This is similar to 'printBody', except that it opens the markup in your web
+-- browser instead, which may be easier to read than seeing it printed in the
+-- terminal.
+--
+-- @since 1.6.21
+browseBody :: YesodExample site ()
+browseBody = withResponse $ \SResponse{ simpleBody = b } -> liftIO $ do
+  tempDir <- getTemporaryDirectory
+  (fp, h) <- openTempFile tempDir "yesod-test-response.html"
+  BSL8.hPutStrLn h b
+  hFlush h
+  hClose h
+  openInBrowser fp
+  where
+  openInBrowser path = callCommand $ cmd ++ " " ++ path
+  cmd = case os of
+    "darwin"  -> "open"
+    "linux"   -> "xdg-open"
+    "mingw32" -> "start"
+    _         -> error $ "Unsupported OS: " ++ os
+
 -- | Performs a CSS query and print the matches to stderr.
 --
 -- ==== __Examples__
@@ -836,7 +864,7 @@
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > post $ do
 -- >   addPostParam "key" "value"
-addPostParam :: T.Text -> T.Text -> RequestBuilder site ()
+addPostParam :: HasCallStack => T.Text -> T.Text -> RequestBuilder site ()
 addPostParam name value =
   modifySIO $ \rbd -> rbd { rbdPostData = (addPostData (rbdPostData rbd)) }
   where addPostData (BinaryPostData _) = error "Trying to add post param to binary content."
@@ -881,7 +909,8 @@
 --
 -- > request $ do
 -- >   addFile "profile_picture" "static/img/picture.png" "img/png"
-addFile :: T.Text -- ^ The parameter name for the file.
+addFile :: HasCallStack
+        => T.Text -- ^ The parameter name for the file.
         -> FilePath -- ^ The path to the file.
         -> T.Text -- ^ The MIME type of the file, e.g. "image/png".
         -> RequestBuilder site ()
@@ -955,7 +984,8 @@
         name:_ -> Right name
     _ -> Left $ "More than one label contained " <> label
 
-byLabelWithMatch :: (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
+byLabelWithMatch :: HasCallStack
+                 => (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
                  -> T.Text                     -- ^ The text contained in the @\<label>@.
                  -> T.Text                     -- ^ The value to set the parameter to.
                  -> RequestBuilder site ()
@@ -963,7 +993,8 @@
   name <- genericNameFromLabel match label
   addPostParam name value
 
-bySelectorLabelWithMatch :: (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
+bySelectorLabelWithMatch :: HasCallStack
+                 => (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
                  -> T.Text                     -- ^ The CSS selector.
                  -> T.Text                     -- ^ The text contained in the @\<label>@.
                  -> T.Text                     -- ^ The value to set the parameter to.
@@ -1017,7 +1048,8 @@
 --
 -- Therefore, this function is deprecated. Please consider using 'byLabelExact',
 -- which performs the exact match over the provided text.
-byLabel :: T.Text -- ^ The text contained in the @\<label>@.
+byLabel :: HasCallStack
+        => T.Text -- ^ The text contained in the @\<label>@.
         -> T.Text -- ^ The value to set the parameter to.
         -> RequestBuilder site ()
 byLabel = byLabelWithMatch T.isInfixOf
@@ -1047,7 +1079,8 @@
 -- > </form>
 --
 -- @since 1.5.9
-byLabelExact :: T.Text -- ^ The text in the @\<label>@.
+byLabelExact :: HasCallStack
+             => T.Text -- ^ The text in the @\<label>@.
              -> T.Text -- ^ The value to set the parameter to.
              -> RequestBuilder site ()
 byLabelExact = byLabelWithMatch (==)
@@ -1058,7 +1091,8 @@
 -- Note: Just like 'byLabel', this function throws an error if it finds multiple labels
 --
 -- @since 1.6.2
-byLabelContain :: T.Text -- ^ The text in the @\<label>@.
+byLabelContain :: HasCallStack
+               => T.Text -- ^ The text in the @\<label>@.
                -> T.Text -- ^ The value to set the parameter to.
                -> RequestBuilder site ()
 byLabelContain = byLabelWithMatch T.isInfixOf
@@ -1069,7 +1103,8 @@
 -- Note: Just like 'byLabel', this function throws an error if it finds multiple labels
 --
 -- @since 1.6.2
-byLabelPrefix :: T.Text -- ^ The text in the @\<label>@.
+byLabelPrefix :: HasCallStack
+              => T.Text -- ^ The text in the @\<label>@.
               -> T.Text -- ^ The value to set the parameter to.
               -> RequestBuilder site ()
 byLabelPrefix = byLabelWithMatch T.isPrefixOf
@@ -1080,7 +1115,8 @@
 -- Note: Just like 'byLabel', this function throws an error if it finds multiple labels
 --
 -- @since 1.6.2
-byLabelSuffix :: T.Text -- ^ The text in the @\<label>@.
+byLabelSuffix :: HasCallStack
+              => T.Text -- ^ The text in the @\<label>@.
               -> T.Text -- ^ The value to set the parameter to.
               -> RequestBuilder site ()
 byLabelSuffix = byLabelWithMatch T.isSuffixOf
@@ -1091,13 +1127,15 @@
 -- fragments.
 --
 -- @since 1.6.15
-bySelectorLabelContain :: T.Text -- ^ The CSS selector.
+bySelectorLabelContain :: HasCallStack
+               => T.Text -- ^ The CSS selector.
                -> T.Text -- ^ The text in the @\<label>@.
                -> T.Text -- ^ The value to set the parameter to.
                -> RequestBuilder site ()
 bySelectorLabelContain = bySelectorLabelWithMatch T.isInfixOf
 
-fileByLabelWithMatch  :: (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
+fileByLabelWithMatch  :: HasCallStack
+                      => (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
                       -> T.Text                     -- ^ The text contained in the @\<label>@.
                       -> FilePath                   -- ^ The path to the file.
                       -> T.Text                     -- ^ The MIME type of the file, e.g. "image/png".
@@ -1130,7 +1168,8 @@
 -- > </form>
 --
 -- Warning: This function has the same issue as 'byLabel'. Please use 'fileByLabelExact' instead.
-fileByLabel :: T.Text -- ^ The text contained in the @\<label>@.
+fileByLabel :: HasCallStack
+            => T.Text -- ^ The text contained in the @\<label>@.
             -> FilePath -- ^ The path to the file.
             -> T.Text -- ^ The MIME type of the file, e.g. "image/png".
             -> RequestBuilder site ()
@@ -1160,7 +1199,8 @@
 -- > </form>
 --
 -- @since 1.5.9
-fileByLabelExact :: T.Text -- ^ The text contained in the @\<label>@.
+fileByLabelExact :: HasCallStack
+                 => T.Text -- ^ The text contained in the @\<label>@.
                  -> FilePath -- ^ The path to the file.
                  -> T.Text -- ^ The MIME type of the file, e.g. "image/png".
                  -> RequestBuilder site ()
@@ -1172,7 +1212,8 @@
 -- Note: Just like 'fileByLabel', this function throws an error if it finds multiple labels
 --
 -- @since 1.6.2
-fileByLabelContain :: T.Text -- ^ The text contained in the @\<label>@.
+fileByLabelContain :: HasCallStack
+                   => T.Text -- ^ The text contained in the @\<label>@.
                    -> FilePath -- ^ The path to the file.
                    -> T.Text -- ^ The MIME type of the file, e.g. "image/png".
                    -> RequestBuilder site ()
@@ -1184,7 +1225,8 @@
 -- Note: Just like 'fileByLabel', this function throws an error if it finds multiple labels
 --
 -- @since 1.6.2
-fileByLabelPrefix :: T.Text -- ^ The text contained in the @\<label>@.
+fileByLabelPrefix :: HasCallStack
+                  => T.Text -- ^ The text contained in the @\<label>@.
                   -> FilePath -- ^ The path to the file.
                   -> T.Text -- ^ The MIME type of the file, e.g. "image/png".
                   -> RequestBuilder site ()
@@ -1196,7 +1238,8 @@
 -- Note: Just like 'fileByLabel', this function throws an error if it finds multiple labels
 --
 -- @since 1.6.2
-fileByLabelSuffix :: T.Text -- ^ The text contained in the @\<label>@.
+fileByLabelSuffix :: HasCallStack
+                  => T.Text -- ^ The text contained in the @\<label>@.
                   -> FilePath -- ^ The path to the file.
                   -> T.Text -- ^ The MIME type of the file, e.g. "image/png".
                   -> RequestBuilder site ()
@@ -1408,7 +1451,8 @@
 --
 -- > request $ do
 -- >   setUrl ("http://google.com/" :: Text)
-setUrl :: (Yesod site, RedirectUrl site url)
+setUrl :: HasCallStack
+       => (Yesod site, RedirectUrl site url)
        => url
        -> RequestBuilder site ()
 setUrl url' = do
@@ -1501,7 +1545,8 @@
 -- >   byLabel "First Name" "Felipe"
 -- >   setMethod "PUT"
 -- >   setUrl NameR
-request :: RequestBuilder site ()
+request :: HasCallStack
+        => RequestBuilder site ()
         -> YesodExample site ()
 request reqBuilder = do
     YesodExampleData app site oldCookies mRes <- getSIO
@@ -1706,7 +1751,7 @@
 -- >   chooseByLabel "Blue"
 --
 -- @since 1.6.17
-chooseByLabel :: T.Text -> RequestBuilder site ()
+chooseByLabel :: HasCallStack => T.Text -> RequestBuilder site ()
 chooseByLabel label = do
     name <- genericNameFromLabel (==) label
     value <- genericValueFromLabel (==) label
@@ -1740,7 +1785,7 @@
 -- >   checkByLabel "Black"
 --
 -- @since 1.6.18
-checkByLabel :: T.Text -> RequestBuilder site ()
+checkByLabel :: HasCallStack => T.Text -> RequestBuilder site ()
 checkByLabel label = do
     name <- genericNameFromLabel (==) label
     value <- genericValueFromLabel (==) label
@@ -1770,7 +1815,7 @@
 -- >   selectByLabel "Selection List" "Blue"
 --
 -- @since 1.6.19
-selectByLabel :: T.Text -> T.Text -> RequestBuilder site ()
+selectByLabel :: HasCallStack => T.Text -> T.Text -> RequestBuilder site ()
 selectByLabel label option = do
     name <- genericNameFromLabel (==) label
     parsedHtml <- parseHTML <$> htmlBody "selectByLabel"
@@ -1830,7 +1875,7 @@
         value:_ -> Right value
     _ -> Left $ "More than one label contained " <> label
 
-htmlBody :: String -> RequestBuilder site BSL8.ByteString
+htmlBody :: HasCallStack => String -> RequestBuilder site BSL8.ByteString
 htmlBody funcName = do
   mres <- fmap rbdResponse getSIO
   res <-
diff --git a/yesod-test.cabal b/yesod-test.cabal
--- a/yesod-test.cabal
+++ b/yesod-test.cabal
@@ -1,5 +1,5 @@
 name:               yesod-test
-version:            1.6.19
+version:            1.6.22
 license:            MIT
 license-file:       LICENSE
 author:             Nubis <nubis@woobiz.com.ar>
@@ -7,72 +7,84 @@
 synopsis:           integration testing for WAI/Yesod Applications
 category:           Web, Yesod, Testing
 stability:          Experimental
-cabal-version:      >= 1.10
+cabal-version:      >=1.10
 build-type:         Simple
 homepage:           http://www.yesodweb.com
-description:     API docs and the README are available at <http://www.stackage.org/package/yesod-test>
-extra-source-files: README.md, LICENSE, test/main.hs, ChangeLog.md
+description:
+  API docs and the README are available at <http://www.stackage.org/package/yesod-test>
 
+extra-source-files:
+  ChangeLog.md
+  LICENSE
+  README.md
+  test/main.hs
+
 library
-    default-language: Haskell2010
-    build-depends:   HUnit                     >= 1.2
-                   , aeson
-                   , attoparsec                >= 0.10
-                   , base                      >= 4.10     && < 5
-                   , blaze-builder
-                   , blaze-html                >= 0.5
-                   , bytestring                >= 0.9
-                   , case-insensitive          >= 0.2
-                   , conduit
-                   , containers
-                   , cookie
-                   , hspec-core                == 2.*
-                   , html-conduit              >= 0.1
-                   , http-types                >= 0.7
-                   , network                   >= 2.2
-                   , memory
-                   , pretty-show               >= 1.6
-                   , text
-                   , time
-                   , mtl                       >= 2.0.0
-                   , transformers              >= 0.2.2
-                   , wai                       >= 3.0
-                   , wai-extra
-                   , xml-conduit               >= 1.0
-                   , xml-types                 >= 0.3
-                   , yesod-core                >= 1.6.17
-                   , blaze-markup
+  default-language: Haskell2010
+  build-depends:
+      aeson             >= 1.0     && < 2.3
+    , attoparsec        >= 0.10    && < 0.15
+    , base              >= 4.10    && < 5
+    , blaze-builder     >= 0.3.1   && < 0.5
+    , blaze-html        >= 0.5     && < 0.10
+    , blaze-markup      >= 0.6     && < 0.9
+    , bytestring        >= 0.9     && < 0.13
+    , case-insensitive  >= 0.2     && < 1.3
+    , conduit           >= 1.3     && < 1.4
+    , containers        >= 0.5     && < 0.8
+    , cookie            >= 0.4     && < 0.6
+    , directory         >= 1.2     && < 1.4
+    , hspec-core        >= 2       && < 3
+    , html-conduit      >= 0.1     && < 1.4
+    , http-types        >= 0.7     && < 0.13
+    , HUnit             >= 1.2     && < 1.7
+    , memory            >= 0.14    && < 0.19
+    , mtl               >= 2.0.0   && < 2.4
+    , network           >= 2.2     && < 3.3
+    , pretty-show       >= 1.6     && < 1.11
+    , process           >= 1.6     && < 1.7
+    , text              >= 1.2     && < 2.2
+    , time              >= 1.5     && < 1.13
+    , transformers      >= 0.2.2   && < 0.7
+    , wai               >= 3.0     && < 3.3
+    , wai-extra         >= 3.0     && < 3.2
+    , xml-conduit       >= 1.0     && < 1.10
+    , xml-types         >= 0.3     && < 0.4
+    , yesod-core        >= 1.6.17  && < 1.7
 
-    exposed-modules: Yesod.Test
-                     Yesod.Test.CssQuery
-                     Yesod.Test.TransversingCSS
-                     Yesod.Test.Internal
-                     Yesod.Test.Internal.SIO
-    ghc-options:  -Wall
+  exposed-modules:
+    Yesod.Test
+    Yesod.Test.CssQuery
+    Yesod.Test.Internal
+    Yesod.Test.Internal.SIO
+    Yesod.Test.TransversingCSS
 
+  ghc-options:      -Wall
+
 test-suite test
-    default-language: Haskell2010
-    type: exitcode-stdio-1.0
-    main-is: main.hs
-    hs-source-dirs: test
-    build-depends:          base
-                          , yesod-test
-                          , hspec
-                          , HUnit
-                          , xml-conduit
-                          , bytestring
-                          , containers
-                          , html-conduit
-                          , yesod-core
-                          , yesod-form >= 1.6
-                          , text
-                          , wai
-                          , wai-extra
-                          , http-types
-                          , unliftio
-                          , cookie
-                          , unliftio-core
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          main.hs
+  hs-source-dirs:   test
+  build-depends:
+      base
+    , bytestring
+    , containers
+    , cookie
+    , hspec
+    , html-conduit
+    , http-types
+    , HUnit
+    , text
+    , unliftio
+    , unliftio-core
+    , wai
+    , wai-extra
+    , xml-conduit
+    , yesod-core
+    , yesod-form     >=1.6
+    , yesod-test
 
 source-repository head
-  type: git
-  location: git://github.com/yesodweb/yesod.git
+  type:     git
+  location: https://github.com/yesodweb/yesod.git
