diff --git a/shakespeare-js.cabal b/shakespeare-js.cabal
--- a/shakespeare-js.cabal
+++ b/shakespeare-js.cabal
@@ -1,5 +1,5 @@
 name:            shakespeare-js
-version:         0.10.1
+version:         0.10.2
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -14,6 +14,11 @@
     Please see http://docs.yesodweb.com/book/templates for a more thorough description and examples
     .
     shakespeare-js was originally called julius, and shakespeare originated from the hamlet template package.
+extra-source-files:
+  test/external1.coffee
+  test/external1.julius
+  test/external2.julius
+  test/main.hs
 
 category:        Web, Yesod
 stability:       Stable
@@ -43,7 +48,7 @@
                  , shakespeare      >= 0.10    && < 0.11
                  , base             >= 4       && < 5
                  , HUnit
-                 , hspec >= 0.6.1 && < 0.7
+                 , hspec            >= 0.8     && < 0.9
                  , text             >= 0.7     && < 0.12
 
 
diff --git a/test/external1.coffee b/test/external1.coffee
new file mode 100644
--- /dev/null
+++ b/test/external1.coffee
@@ -0,0 +1,5 @@
+'שלום'
+%{var}
+'@{Home}'
+'@?{urlp}'
+^{cofmixin}
diff --git a/test/external1.julius b/test/external1.julius
new file mode 100644
--- /dev/null
+++ b/test/external1.julius
@@ -0,0 +1,5 @@
+שלום
+#{var}
+@{Home}
+@?{urlp}
+^{jmixin}
diff --git a/test/external2.julius b/test/external2.julius
new file mode 100644
--- /dev/null
+++ b/test/external2.julius
@@ -0,0 +1,1 @@
+var #{var} = 2;
diff --git a/test/main.hs b/test/main.hs
new file mode 100644
--- /dev/null
+++ b/test/main.hs
@@ -0,0 +1,141 @@
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE TemplateHaskell #-}
+import Test.HUnit hiding (Test)
+import Test.Hspec
+import Test.Hspec.HUnit ()
+
+import Prelude hiding (reverse)
+import Text.Julius
+import Data.List (intercalate)
+import qualified Data.Text.Lazy as T
+import qualified Data.List
+import qualified Data.List as L
+import Data.Text (Text, pack, unpack)
+import Data.Monoid (mappend)
+
+main :: IO ()
+main = hspecX $ descriptions [specs]
+
+specs :: [Spec]
+specs = describe "hamlet"
+  [ it "julius" $ do
+    let var = "var"
+    let urlp = (Home, [(pack "p", pack "q")])
+    flip jelper [julius|שלום
+#{var}
+@{Home}
+@?{urlp}
+^{jmixin}
+|] $ intercalate "\r\n"
+        [ "שלום"
+        , var
+        , "url"
+        , "url?p=q"
+        , "var x;"
+        ] ++ "\r\n"
+
+
+  , it "juliusFile" $ do
+    let var = "var"
+    let urlp = (Home, [(pack "p", pack "q")])
+    flip jelper $(juliusFile "test/external1.julius") $ unlines
+        [ "שלום"
+        , var
+        , "url"
+        , "url?p=q"
+        , "var x;"
+        ]
+
+
+  , it "juliusFileDebug" $ do
+    let var = "var"
+    let urlp = (Home, [(pack "p", pack "q")])
+    flip jelper $(juliusFileDebug "test/external1.julius") $ unlines
+        [ "שלום"
+        , var
+        , "url"
+        , "url?p=q"
+        , "var x;"
+        ]
+
+{- TODO
+  , it "juliusFileDebugChange" $ do
+      let var = "somevar"
+          test result = jelper result $(juliusFileDebug "test/external2.julius")
+      writeFile "test/external2.julius" "var #{var} = 1;"
+      test "var somevar = 1;"
+      writeFile "test/external2.julius" "var #{var} = 2;"
+      test "var somevar = 2;"
+      writeFile "test/external2.julius" "var #{var} = 1;"
+      -}
+
+
+  , it "julius module names" $
+    let foo = "foo"
+        double = 3.14 :: Double
+        int = -5 :: Int in
+      jelper "oof oof 3.14 -5"
+        [julius|#{Data.List.reverse foo} #{L.reverse foo} #{show double} #{show int}|]
+
+
+  , it "single dollar at and caret" $ do
+    jelper "$@^" [julius|$@^|]
+    jelper "#{@{^{" [julius|#\{@\{^\{|]
+
+
+  , it "dollar operator" $ do
+    let val = (1 :: Int, (2 :: Int, 3 :: Int))
+    jelper "2" [julius|#{ show $ fst $ snd val }|]
+    jelper "2" [julius|#{ show $ fst $ snd $ val}|]
+  ]
+
+
+
+data Url = Home | Sub SubUrl
+data SubUrl = SubUrl
+render :: Url -> [(Text, Text)] -> Text
+render Home qs = pack "url" `mappend` showParams qs
+render (Sub SubUrl) qs = pack "suburl" `mappend` showParams qs
+
+showParams :: [(Text, Text)] -> Text
+showParams [] = pack ""
+showParams z =
+    pack $ '?' : intercalate "&" (map go z)
+  where
+    go (x, y) = go' x ++ '=' : go' y
+    go' = concatMap encodeUrlChar . unpack
+
+-- | Taken straight from web-encodings; reimplemented here to avoid extra
+-- dependencies.
+encodeUrlChar :: Char -> String
+encodeUrlChar c
+    -- List of unreserved characters per RFC 3986
+    -- Gleaned from http://en.wikipedia.org/wiki/Percent-encoding
+    | 'A' <= c && c <= 'Z' = [c]
+    | 'a' <= c && c <= 'z' = [c]
+    | '0' <= c && c <= '9' = [c]
+encodeUrlChar c@'-' = [c]
+encodeUrlChar c@'_' = [c]
+encodeUrlChar c@'.' = [c]
+encodeUrlChar c@'~' = [c]
+encodeUrlChar ' ' = "+"
+encodeUrlChar y =
+    let (a, c) = fromEnum y `divMod` 16
+        b = a `mod` 16
+        showHex' x
+            | x < 10 = toEnum $ x + (fromEnum '0')
+            | x < 16 = toEnum $ x - 10 + (fromEnum 'A')
+            | otherwise = error $ "Invalid argument to showHex: " ++ show x
+     in ['%', showHex' b, showHex' c]
+
+
+
+
+jmixin :: JavascriptUrl u
+jmixin = [julius|var x;|]
+
+jelper :: String -> JavascriptUrl Url -> Assertion
+jelper res h = T.pack res @=? renderJavascriptUrl render h
+
+instance Show Url where
+    show _ = "FIXME remove this instance show Url"
