diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -19,7 +19,11 @@
 
   * **MacOS Catalina and newer:** `echo 'export PATH="${HOME}/.local/bin:${PATH}"' >> ~/.zshrc && export PATH="${HOME}/.local/bin:${PATH}"`
 
-3. Finally, install _runhs_: Download the appropriate executable for your platform from the [Releases page](https://github.com/friedbrice/runhs/releases/) and put it somewhere on your `PATH`, or `stack install runhs`.
+3. Finally, use one of the following install methods.
+
+  * **Stack (recommended):** `stack install runhs`
+
+  * **Download:** Download the appropriate executable for your platform from the [Releases page](https://github.com/friedbrice/runhs/releases/), unzip it, and put it somewhere on your `PATH`.
 
 
 ## Usage
diff --git a/runhs.cabal b/runhs.cabal
--- a/runhs.cabal
+++ b/runhs.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.2
 
 name: runhs
-version: 1.0.0.4
+version: 1.0.0.5
 synopsis: Stack wrapper for single-file Haskell programs.
 description:
   Stack wrapper for single-file Haskell programs.
@@ -30,4 +30,15 @@
     , file-embed >=0.0.10.1 && <1
     , process >=1.6.3.0 && <2
     , yaml >=0.8.32 && <1
+  default-language: Haskell2010
+
+test-suite runhs-test
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  hs-source-dirs: test
+  build-depends:
+      base
+    , directory >=1.3.1.5 && <2
+    , hspec >=2.5.5 && <3
+    , process
   default-language: Haskell2010
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -38,7 +38,7 @@
     header <- readHeader =<< readFile path
     (resolver, packages) <-
         maybe
-            (help $ "unable to parse the front matter in " <> path)
+            (help $ "Unable to parse the front matter in " <> path <> ".")
             pure
         . flip parseMaybe header
         . withObject "header"
@@ -59,11 +59,11 @@
     hSetBuffering stdout NoBuffering
     args <- getArgs
     case args of
-        "watch":file:_ -> watch =<< spec file
+        "watch":file:args' -> watch args' =<< spec file
         "repl":file:_ -> repl =<< spec file
         "compile":file:_ -> compile =<< spec file
         "script":file:args' -> script args' =<< spec file
-        _ -> help "unable to parse the command-line arguments"
+        _ -> help "Unable to parse the command-line arguments."
 
 runProcess :: CreateProcess -> IO ()
 runProcess process = do
@@ -71,9 +71,9 @@
     code <- waitForProcess h
     exitWith code
 
-watch :: RunSpec -> IO ()
-watch spec = runProcess $
-    proc "stack"
+watch :: [String] -> RunSpec -> IO ()
+watch args spec = runProcess $
+    proc "stack" $
         [ "exec"
         , "--resolver"
         , resolver spec
@@ -82,6 +82,7 @@
         , "--command"
         , unwords $ "stack" : "repl" : stackArgs spec
         ]
+        <> args
 
 repl :: RunSpec -> IO ()
 repl spec = runProcess $
@@ -100,5 +101,5 @@
     putStrLn (replicate 40 '~')
     putStrLn $(embedStringFile "README.md")
     putStrLn (replicate 40 '~')
-    putStrLn $ "runhs: " <> reason <> ". Please see ``Usage'' above."
+    putStrLn $ unwords ["runhs:", reason, "Please see \"Usage\" above."]
     exitWith (ExitFailure 1)
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,66 @@
+{-
+resolver: nightly
+packages:
+  - directory
+  - hspec
+  - process
+-}
+module Main (main) where
+
+import Test.Hspec
+import qualified System.Directory as Sys
+import qualified System.Exit as Sys
+import qualified System.Process as Sys
+
+data Mode = Watch | Repl | Script | Compile
+
+render Watch = "watch"
+render Repl = "repl"
+render Script = "script"
+render Compile = "compile"
+
+type Stdin = String
+type Stdout = String
+type Stderr = String
+
+runhs :: Mode -> FilePath -> [String] -> Stdin -> IO (Sys.ExitCode, Stdout, Stderr)
+runhs mode path args stdin =
+    Sys.readProcessWithExitCode "stack" args' stdin
+    where
+    args' = ["exec", "--resolver", "nightly", "runhs", render mode, path] <> args
+
+main :: IO ()
+main = hspec $ do
+    describe "hello-haskell test" $ do
+        let helloHaskell = "test/resources/hello-haskell.hs"
+
+        it "should load in repl mode" $ do
+            (status, _, _) <- runhs Repl helloHaskell [] ":t greet\n:q"
+            status `shouldBe` Sys.ExitSuccess
+
+        it "should load in watch mode" $ do
+            _ <- runhs Watch helloHaskell ["--allow-eval"] ""
+            -- Ghcid exits with success on Windows, with error on Unix.
+            return ()
+
+        it "should load in script mode" $ do
+            (status, out, _) <- runhs Script helloHaskell [] ""
+            status `shouldBe` Sys.ExitSuccess
+            out `shouldBe` "Hello, World!\n"
+
+        it "should forward arguments in script mode" $ do
+            (status, out, _) <- runhs Script helloHaskell ["Veni", "Vidi"] ""
+            status `shouldBe` Sys.ExitSuccess
+            out `shouldBe` "Hello, Veni!\nHello, Vidi!\n"
+
+        it "should forward stdin in script mode" $ do
+            (status, out, _) <- runhs Script helloHaskell [] "Veni Vidi\nVici"
+            status `shouldBe` Sys.ExitSuccess
+            out `shouldBe` "Hello, Veni!\nHello, Vidi!\nHello, Vici!\n"
+
+        it "should load in compile mode" $ do
+            (status, out, _) <- runhs Compile helloHaskell [] ""
+            status `shouldBe` Sys.ExitSuccess
+            Sys.removePathForcibly "test/resources/hello-haskell.o"
+            Sys.removePathForcibly "test/resources/hello-haskell.hi"
+            Sys.removePathForcibly "test/resources/hello-haskell"
