diff --git a/quasar.cabal b/quasar.cabal
index 6c5b8dd71b5aafb3fe968453a6ea39e7db6c18cc..06c26caf771f914ccea835fbd9c0b47b3f422518 100644
--- a/quasar.cabal
+++ b/quasar.cabal
@@ -101,8 +101,10 @@ test-suite quasar-test
   type: exitcode-stdio-1.0
   build-depends:
     base >=4.7 && <5,
+    exceptions,
     hspec,
     quasar,
+    stm,
     unordered-containers,
   main-is: Spec.hs
   other-modules:
diff --git a/test/Quasar/AwaitableSpec.hs b/test/Quasar/AwaitableSpec.hs
index e2b7c45ed76d491cf989693ff3e8f53a5b4d625d..504564300c742114bd1ea45b32614105d2615769 100644
--- a/test/Quasar/AwaitableSpec.hs
+++ b/test/Quasar/AwaitableSpec.hs
@@ -1,10 +1,17 @@
 module Quasar.AwaitableSpec (spec) where
 
 import Control.Concurrent
-import Control.Monad (void)
-import Prelude
+import Control.Concurrent.STM
+import Control.Monad.Catch
+import GHC.Conc (unsafeIOToSTM)
 import Test.Hspec
 import Quasar.Awaitable
+import Quasar.Prelude
+
+data TestException = TestException
+  deriving stock (Eq, Show)
+
+instance Exception TestException
 
 spec :: Spec
 spec = parallel $ do
@@ -55,3 +62,54 @@ spec = parallel $ do
         threadDelay 100000
         putAsyncVar_ avar2 ()
       awaitAny2 avar1 avar2
+
+  describe "cacheAwaitable" do
+    it "can cache an awaitable" $ io do
+      var <- newTVarIO (0 :: Int)
+      awaitable <- cacheAwaitable do
+        unsafeAwaitSTM (modifyTVar var (+ 1)) :: Awaitable ()
+      await awaitable
+      await awaitable
+      readTVarIO var `shouldReturn` 1
+
+    it "can cache a bind" $ io do
+      var1 <- newTVarIO (0 :: Int)
+      var2 <- newTVarIO (0 :: Int)
+      awaitable <- cacheAwaitable do
+        unsafeAwaitSTM (modifyTVar var1 (+ 1)) >>= \_ -> unsafeAwaitSTM (modifyTVar var2 (+ 1)) :: Awaitable ()
+      await awaitable
+      await awaitable
+      readTVarIO var1 `shouldReturn` 1
+      readTVarIO var2 `shouldReturn` 1
+
+    it "can cache an exception" $ io do
+      var <- newMVar (0 :: Int)
+      awaitable <- cacheAwaitable do
+        unsafeAwaitSTM (unsafeIOToSTM (modifyMVar_ var (pure . (+ 1))) >> throwM TestException) :: Awaitable ()
+      await awaitable `shouldThrow` \TestException -> True
+      await awaitable `shouldThrow` \TestException -> True
+      readMVar var `shouldReturn` 1
+
+    it "can cache the left side of an awaitAny2" $ io do
+      var <- newTVarIO (0 :: Int)
+
+      let a1 = unsafeAwaitSTM (modifyTVar var (+ 1)) :: Awaitable ()
+      let a2 = unsafeAwaitSTM retry :: Awaitable ()
+
+      awaitable <- cacheAwaitable $ (awaitAny2 a1 a2 :: Awaitable ())
+
+      await awaitable
+      await awaitable
+      readTVarIO var `shouldReturn` 1
+
+    it "can cache the right side of an awaitAny2" $ io do
+      var <- newTVarIO (0 :: Int)
+
+      let a1 = unsafeAwaitSTM retry :: Awaitable ()
+      let a2 = unsafeAwaitSTM (modifyTVar var (+ 1)) :: Awaitable ()
+
+      awaitable <- cacheAwaitable $ (awaitAny2 a1 a2 :: Awaitable ())
+
+      await awaitable
+      await awaitable
+      readTVarIO var `shouldReturn` 1