diff --git a/jsaddle-warp.cabal b/jsaddle-warp.cabal
--- a/jsaddle-warp.cabal
+++ b/jsaddle-warp.cabal
@@ -1,5 +1,5 @@
 name: jsaddle-warp
-version: 0.8.2.0
+version: 0.8.3.0
 cabal-version: >=1.10
 build-type: Simple
 license: MIT
@@ -25,18 +25,18 @@
         exposed-modules:
             Language.Javascript.JSaddle.WebSockets
         build-depends:
-            aeson >=0.8.0.2 && <1.1,
+            aeson >=0.8.0.2 && <1.2,
             containers >=0.5.6.2 && <0.6,
             http-types >=0.8.6 && <0.10,
             jsaddle >=0.8.0.0 && <0.9,
             stm >=2.4.4 && <2.5,
             text >=1.2.1.3 && <1.3,
-            time >=1.5.0.1 && <1.7,
+            time >=1.5.0.1 && <1.8,
             transformers >=0.4.2.0 && <0.6,
             wai >=3.0.3.0 && <3.3,
             wai-websockets >=3.0.0.6 && <3.1,
             warp >=3.1.2 && <3.3,
-            websockets >=0.9.5.0 && <0.10
+            websockets >=0.9.5.0 && <0.11
     exposed-modules:
         Language.Javascript.JSaddle.Warp
     build-depends:
@@ -51,17 +51,30 @@
 
     build-depends:
             QuickCheck -any,
+            aeson -any,
             bytestring -any,
+            containers -any,
             deepseq -any,
             doctest >=0.10.1 && <0.12,
             filepath >=1.4.0.0 && <1.5,
             ghc-prim -any,
+            http-types -any,
             jsaddle -any,
             jsaddle-warp -any,
             lens -any,
+            network -any,
             ref-tf -any,
             primitive -any,
-            process >=1.2.3.0 && <1.5
+            process >=1.2.3.0 && <1.5,
+            stm -any,
+            text -any,
+            time -any,
+            transformers -any,
+            wai -any,
+            wai-websockets -any,
+            warp -any,
+            webdriver >=0.8.4 && <0.9,
+            websockets -any
     type: exitcode-stdio-1.0
     main-is: DocTest.hs
     build-depends:
diff --git a/src/Language/Javascript/JSaddle/WebSockets.hs b/src/Language/Javascript/JSaddle/WebSockets.hs
--- a/src/Language/Javascript/JSaddle/WebSockets.hs
+++ b/src/Language/Javascript/JSaddle/WebSockets.hs
@@ -19,7 +19,8 @@
 ) where
 
 import Control.Monad (forever)
-import Control.Concurrent (forkIO)
+import Control.Concurrent (forkIO, threadDelay)
+import Control.Exception (handle, AsyncException, throwIO, fromException)
 
 import Data.Monoid ((<>))
 import Data.Aeson (encode, decode)
@@ -27,7 +28,7 @@
 import Network.Wai (Application)
 import Network.WebSockets
        (ConnectionOptions(..), sendTextData, receiveDataMessage,
-        acceptRequest, ServerApp)
+        acceptRequest, ServerApp, sendPing)
 import qualified Network.WebSockets as WS (DataMessage(..))
 import Network.Wai.Handler.WebSockets (websocketsOr)
 
@@ -35,6 +36,7 @@
 import qualified Network.Wai as W
        (responseLBS, requestMethod, Application, pathInfo)
 import Data.Text (Text)
+import qualified Data.Text as T (pack)
 import qualified Network.HTTP.Types as H
        (status403, status200, status405)
 import Language.Javascript.JSaddle.Run (runJavaScript)
@@ -55,6 +57,20 @@
                         Just r  -> processResult r
                 _ -> error "jsaddle WebSocket unexpected binary data"
         start
+        waitTillClosed conn
+
+    -- Based on Network.WebSocket.forkPingThread
+    waitTillClosed conn = ignore `handle` go 1
+      where
+        go :: Int -> IO ()
+        go i = do
+            threadDelay (1 * 1000 * 1000)
+            sendPing conn (T.pack $ show i)
+            go (i + 1)
+
+    ignore e = case fromException e of
+        Just async -> throwIO (async :: AsyncException)
+        Nothing    -> return ()
 
 jsaddleApp :: Application
 jsaddleApp req = jsaddleAppPieces (W.pathInfo req) req
diff --git a/tests/DocTest.hs b/tests/DocTest.hs
--- a/tests/DocTest.hs
+++ b/tests/DocTest.hs
@@ -13,13 +13,16 @@
 import System.Process (readProcess, system)
 import Control.Concurrent (forkIO)
 import Control.Monad (void)
+import Control.Monad.IO.Class (MonadIO(..))
 import Data.Monoid ((<>))
 import System.Environment (getArgs)
 import Language.Javascript.JSaddle.Run.Files (jsaddleJs)
 import qualified Data.ByteString.Lazy.Char8 as BS (unpack)
+import Test.WebDriver (runSession, defaultConfig, openPage, closeSession)
 
 main :: IO ()
 main = do
+    putStrLn "Hello"
     jsaddlePath <- getArgs >>= \case
         [arg] -> return arg
         _ -> do
@@ -27,70 +30,70 @@
             exitFailure
     hSetBuffering stdout LineBuffering
     hSetBuffering stderr LineBuffering
-    node <- system "nodejs --version" >>= \case
-                ExitSuccess -> return "nodejs"
-                _           -> return "node"
-    system (node <> " --version") >>= \case
-                ExitSuccess -> putStrLn "Node.js found"
+    node <- system "phantomjs --version" >>= \case
+                ExitSuccess -> return ()
                 e           -> do
-                    putStrLn "Node.js not found"
+                    putStrLn "phantomjs not found"
                     exitWith e
-    forkIO . void $ readProcess node ["--harmony"] (BS.unpack jsaddleJs) >>= putStr
-    doctest [
-        "-hide-all-packages",
-        "-package=base-" ++ VERSION_base,
-        "-package=lens-" ++ VERSION_lens,
-        "-package=text-" ++ VERSION_text,
-        "-package=bytestring-" ++ VERSION_bytestring,
-        "-package=transformers-" ++ VERSION_transformers,
-        "-package=websockets-" ++ VERSION_websockets,
-        "-package=primitive-" ++ VERSION_primitive,
-        "-package=aeson-" ++ VERSION_aeson,
-        "-package=websockets-" ++ VERSION_websockets,
-        "-package=wai-" ++ VERSION_wai,
-        "-package=wai-websockets-" ++ VERSION_wai_websockets,
-        "-package=warp-" ++ VERSION_warp,
-        "-package=http-types-" ++ VERSION_http_types,
-        "-package=stm-" ++ VERSION_stm,
-        "-package=time-" ++ VERSION_time,
-        "-package=containers-" ++ VERSION_containers,
-        "-package=process-" ++ VERSION_process,
-        "-package=filepath-" ++ VERSION_filepath,
-        "-package=ref-tf-" ++ VERSION_ref_tf,
-        "-package=deepseq-" ++ VERSION_deepseq,
-        "-package=ghc-prim-" ++ VERSION_ghc_prim,
-        "-i" <> jsaddlePath </> "jsaddle-warp/src",
-        "-i" <> jsaddlePath </> "jsaddle-warp/src-ghc",
-        jsaddlePath </> "jsaddle-warp/src/Language/Javascript/JSaddle/Test.hs",
-        "-i" <> jsaddlePath </> "jsaddle",
-        jsaddlePath </> "jsaddle/src-ghc/Data/JSString/Text.hs",
-        jsaddlePath </> "jsaddle/src-ghc/Data/JSString/Internal/Type.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Foreign.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Foreign/Internal.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Internal/Types.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Marshal.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Marshal/Pure.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Marshal/Internal.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Prim.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Prim/Internal.hs",
-        jsaddlePath </> "jsaddle/src-ghc/GHCJS/Types.hs",
-        jsaddlePath </> "jsaddle/src-ghc/JavaScript/Array.hs",
-        jsaddlePath </> "jsaddle/src-ghc/JavaScript/Array/Internal.hs",
-        jsaddlePath </> "jsaddle/src-ghc/JavaScript/Object/Internal.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Arguments.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Classes.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Classes/Internal.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Evaluate.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Exception.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Monad.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Marshal/String.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Native.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Native/Internal.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Object.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Properties.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Run.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Run/Files.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/String.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Types.hs",
-        jsaddlePath </> "jsaddle/src/Language/Javascript/JSaddle/Value.hs" ]
+    forkIO . void $ readProcess "phantomjs" ["--webdriver=4444"] (BS.unpack jsaddleJs) >>= putStr
+    runSession defaultConfig $ do
+        openPage "http://localhost:3709"
+        liftIO $ doctest [
+            "-hide-all-packages",
+            "-package=base-" ++ VERSION_base,
+            "-package=lens-" ++ VERSION_lens,
+            "-package=text-" ++ VERSION_text,
+            "-package=bytestring-" ++ VERSION_bytestring,
+            "-package=transformers-" ++ VERSION_transformers,
+            "-package=websockets-" ++ VERSION_websockets,
+            "-package=primitive-" ++ VERSION_primitive,
+            "-package=aeson-" ++ VERSION_aeson,
+            "-package=websockets-" ++ VERSION_websockets,
+            "-package=wai-" ++ VERSION_wai,
+            "-package=wai-websockets-" ++ VERSION_wai_websockets,
+            "-package=warp-" ++ VERSION_warp,
+            "-package=http-types-" ++ VERSION_http_types,
+            "-package=stm-" ++ VERSION_stm,
+            "-package=time-" ++ VERSION_time,
+            "-package=containers-" ++ VERSION_containers,
+            "-package=process-" ++ VERSION_process,
+            "-package=filepath-" ++ VERSION_filepath,
+            "-package=ref-tf-" ++ VERSION_ref_tf,
+            "-package=deepseq-" ++ VERSION_deepseq,
+            "-package=ghc-prim-" ++ VERSION_ghc_prim,
+            "-i" <> "src",
+            "-i" <> "src-ghc",
+            "src/Language/Javascript/JSaddle/Test.hs",
+            "-i" <> jsaddlePath,
+            jsaddlePath </> "src-ghc/Data/JSString/Text.hs",
+            jsaddlePath </> "src-ghc/Data/JSString/Internal/Type.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Foreign.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Foreign/Internal.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Internal/Types.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Marshal.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Marshal/Pure.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Marshal/Internal.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Prim.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Prim/Internal.hs",
+            jsaddlePath </> "src-ghc/GHCJS/Types.hs",
+            jsaddlePath </> "src-ghc/JavaScript/Array.hs",
+            jsaddlePath </> "src-ghc/JavaScript/Array/Internal.hs",
+            jsaddlePath </> "src-ghc/JavaScript/Object/Internal.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Arguments.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Classes.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Classes/Internal.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Evaluate.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Exception.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Monad.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Marshal/String.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Native.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Native/Internal.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Object.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Properties.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Run.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Run/Files.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/String.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Types.hs",
+            jsaddlePath </> "src/Language/Javascript/JSaddle/Value.hs" ]
+        closeSession
