diff --git a/curl-runnings.cabal b/curl-runnings.cabal
--- a/curl-runnings.cabal
+++ b/curl-runnings.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 3c27906a20aba4f4ab885acf4616178457bdbd82ce1dcd57942ff7e06a0bba25
+-- hash: f7b42ddbfbcd70bee034e064181b72a998e326a895efdf2c524583c4f47131ca
 
 name:           curl-runnings
-version:        0.16.4
+version:        0.17.0
 synopsis:       A framework for declaratively writing curl based API tests
 description:    Please see the README on Github at <https://github.com/aviaviavi/curl-runnings#readme>
 category:       Testing
@@ -37,6 +37,7 @@
       Testing.CurlRunnings
       Testing.CurlRunnings.Types
       Testing.CurlRunnings.Internal
+      Testing.CurlRunnings.Internal.Aeson
       Testing.CurlRunnings.Internal.Parser
       Testing.CurlRunnings.Internal.Headers
       Testing.CurlRunnings.Internal.KeyValuePairs
@@ -46,7 +47,7 @@
   hs-source-dirs:
       src
   build-depends:
-      aeson >=1.2.4.0 && <2.0
+      aeson >=1.2.4.0
     , base >=4.0 && <5
     , base64-bytestring >=1.0.0.2
     , bytestring >=0.10.8.2
@@ -57,8 +58,6 @@
     , dhall-json >=1.0.9
     , directory >=1.3.0.2
     , hashable >=1.2.7.0
-    , hspec >=2.4.4
-    , hspec-expectations >=0.8.2
     , http-client-tls >=0.3.5.3
     , http-conduit >=2.3.6
     , http-types >=0.12.3
@@ -66,7 +65,6 @@
     , pretty-simple >=2.0.2.1
     , regex-posix >=0.95.2
     , text >=1.2.2.2
-    , time >=1.8.0.2
     , transformers >=0.5.2.0
     , unordered-containers >=0.2.8.0
     , vector >=0.12.0
@@ -81,7 +79,7 @@
       app
   ghc-options: -threaded -rtsopts -with-rtsopts=-N
   build-depends:
-      aeson >=1.2.4.0 && <2.0
+      aeson >=1.2.4.0
     , base >=4.7
     , bytestring >=0.10.8.2
     , cmdargs >=0.10.20
@@ -102,7 +100,7 @@
       test
   ghc-options: -threaded -rtsopts -with-rtsopts=-N
   build-depends:
-      aeson >=1.2.4.0 && <2.0
+      aeson >=1.2.4.0
     , base >=4.0 && <5
     , bytestring >=0.10.8.2
     , curl-runnings
diff --git a/src/Testing/CurlRunnings.hs b/src/Testing/CurlRunnings.hs
--- a/src/Testing/CurlRunnings.hs
+++ b/src/Testing/CurlRunnings.hs
@@ -15,7 +15,6 @@
 
 import           Control.Arrow
 import           Control.Exception
-import qualified Control.Exception
 import           Control.Monad
 import           Control.Monad.IO.Class
 import           Control.Monad.Trans.Except
@@ -26,19 +25,13 @@
 import qualified Data.ByteString.Lazy                 as B
 import qualified Data.CaseInsensitive                 as CI
 import           Data.Either
-import qualified Data.HashMap.Strict                  as H
-import           Data.List
+import           Data.List                            (find)
 import           Data.Maybe
-import           Data.Monoid
+import           Data.String                          (fromString)
 import qualified Data.Text                            as T
 import qualified Data.Text.Encoding                   as T
 import qualified Data.Text.IO                         as TIO
-import qualified Data.Text.Lazy                       as TL
-import qualified Data.Text.Lazy.IO                    as TLIO
-import           Data.Time.Clock
 import qualified Data.Vector                          as V
-import qualified Data.Vector                          as V
-import qualified Data.Yaml                            as Y
 import qualified Data.Yaml.Include                    as YI
 import qualified Dhall
 import qualified Dhall.Import
@@ -46,7 +39,6 @@
 import qualified Dhall.Parser
 import qualified Dhall.TypeCheck
 import           Network.Connection                   (TLSSettings (..))
-import           Network.HTTP.Client.TLS              (mkManagerSettings)
 import           Network.HTTP.Conduit
 import           Network.HTTP.Simple                  hiding (Header)
 import qualified Network.HTTP.Simple                  as HTTP
@@ -54,6 +46,7 @@
 import           System.Directory
 import           System.Environment
 import           Testing.CurlRunnings.Internal
+import qualified Testing.CurlRunnings.Internal.Aeson  as A
 import           Testing.CurlRunnings.Internal.Parser
 import           Testing.CurlRunnings.Types
 import           Text.Printf
@@ -110,7 +103,7 @@
 appendQueryParameters :: [KeyValuePair] -> Request -> Request
 appendQueryParameters newParams r = setQueryString (existing ++ newQuery) r where
   existing = NT.parseQuery $ queryString r
-  newQuery = NT.simpleQueryToQuery $ fmap (\(KeyValuePair k v) -> (T.encodeUtf8 k, T.encodeUtf8 v)) newParams
+  newQuery = NT.simpleQueryToQuery $ fmap (\(KeyValuePair k v) -> (T.encodeUtf8 . A.toText $ k, T.encodeUtf8 v)) newParams
 
 setPayload :: Maybe Payload -> Request -> Request
 -- TODO - for backwards compatability, empty requests will set an empty json
@@ -121,7 +114,7 @@
 setPayload Nothing = setRequestBodyJSON emptyObject
 setPayload (Just (JSON v)) = setRequestBodyJSON v
 setPayload (Just (URLEncoded (KeyValuePairs xs))) = setRequestBodyURLEncoded $ kvpairs xs where
-  kvpairs = fmap (\(KeyValuePair k v) -> (T.encodeUtf8 k, T.encodeUtf8 v))
+  kvpairs = fmap (\(KeyValuePair k v) -> (T.encodeUtf8 . A.toText $ k, T.encodeUtf8 v))
 
 -- | Run a single test case, and returns the result. IO is needed here since this method is responsible
 -- for actually curling the test case endpoint and parsing the result.
@@ -249,15 +242,17 @@
         (Just (BasicAuthentication u p)) ->
           let interpolated = sequence [interpolateQueryString state u, interpolateQueryString state p] in
           case interpolated of
-            Right [u, p] -> Right [Header "Authorization" ("Basic " <> (makeBasicAuthToken u p))]
+            Right [u', p'] -> Right [Header "Authorization" ("Basic " <> (makeBasicAuthToken u' p'))]
             Left l -> Left l
-        Nothing -> Right []
+            _ -> Left $ QueryValidationError "FIXME Pattern match error in interpolatingHeaders"
+        _ -> Right []
   mainHeaders <- (mapM
         (\(Header k v) ->
           case sequence
                   [interpolateQueryString state k, interpolateQueryString state v] of
             Left err       -> Left err
-            Right [k', v'] -> Right $ Header k' v')
+            Right [k', v'] -> Right $ Header k' v'
+            _ -> Left $ QueryValidationError "FIXME Pattern match error in interpolatingHeaders")
       headerList)
   Right . HeaderSet $ mainHeaders <> authHeaders
 
@@ -282,7 +277,8 @@
 runSuite :: CurlSuite -> LogLevel -> TLSCheckType -> IO [CaseResult]
 runSuite (CurlSuite cases filterRegex) logLevel tlsType = do
   fullEnv <- getEnvironment
-  let envMap = H.fromList $ map (\(x, y) -> (T.pack x, T.pack y)) fullEnv
+  let envMap :: A.MapType T.Text
+      envMap = A.fromList $ map (\(x, y) -> (fromString x :: A.KeyType, T.pack y)) fullEnv :: A.MapType T.Text
       filterNameByRegexp curlCase =
         maybe
           True
@@ -389,19 +385,19 @@
 -- | runReplacements
 runReplacements :: CurlRunningsState -> Value -> Either QueryError Value
 runReplacements state (Object o) =
-  let keys = H.keys o
+  let keys = A.keys o
       keysWithUpdatedKeyVal =
         map
           (\key ->
-             let value = fromJust $ H.lookup key o
+             let value = fromJust $ A.lookup key o
               -- (old key, new key, new value)
              in ( key
-                , interpolateQueryString state key
+                , interpolateQueryString state (A.toText key)
                 , runReplacements state value))
           keys
   in mapRight Object $
      foldr
-       (\((key, eKeyResult, eValueResult) :: ( T.Text
+       (\((key, eKeyResult, eValueResult) :: ( A.KeyType
                                              , Either QueryError T.Text
                                              , Either QueryError Value)) (eObjectToUpdate :: Either QueryError Object) ->
           case (eKeyResult, eValueResult, eObjectToUpdate)
@@ -412,11 +408,12 @@
             (_, Left queryErr, _) -> Left queryErr
             (_, _, Left queryErr) -> Left queryErr
             (Right newKey, Right newValue, Right objectToUpdate) ->
-              if key /= newKey
-                then let inserted = H.insert newKey newValue objectToUpdate
-                         deleted = H.delete key inserted
+              let newKey' = A.fromText newKey
+              in if key /= newKey'
+                then let inserted = A.insert newKey' newValue objectToUpdate
+                         deleted = A.delete key inserted
                      in Right deleted
-                else Right $ H.insert key newValue objectToUpdate)
+                else Right $ A.insert key newValue objectToUpdate)
        (Right o)
        keysWithUpdatedKeyVal
 runReplacements p (Array a) =
@@ -442,9 +439,9 @@
 interpolateViaJSON :: (ToJSON a, FromJSON a) => CurlRunningsState -> a -> Either QueryError a
 interpolateViaJSON state i = do
   replaced <- runReplacements state $ toJSON i
-  resultToEither $ fromJSON replaced where
-    resultToEither (Error e)   = Left $ QueryValidationError $ T.pack e
-    resultToEither (Success a) = Right a
+  resultToEither' $ fromJSON replaced where
+    resultToEither' (Error e)   = Left $ QueryValidationError $ T.pack e
+    resultToEither' (Success a) = Right a
 
 -- | Given a query string, return some text with interpolated values. Type
 -- errors will be returned if queries don't resolve to strings
@@ -474,7 +471,7 @@
     Right (String s) -> Right $ rawText <> s
     (Right o)        -> Left $ QueryTypeMismatch "Expected a string" o
 getStringValueForQuery (CurlRunningsState env _ _ _) (InterpolatedQuery rawText (EnvironmentVariable v)) =
-  Right $ rawText <> H.lookupDefault "" v env
+  Right $ rawText <> A.findWithDefault "" (A.fromText v) env
 
 -- | Lookup the value for the specified query
 getValueForQuery ::
@@ -499,7 +496,7 @@
                         case (eitherVal, index) of
                           (Left l, _) -> Left l
                           (Right (Object o), KeyIndex k) ->
-                            Right $ H.lookupDefault Null k o
+                            Right $ A.findWithDefault Null (A.fromText k :: A.KeyType) o
                           (Right (Array a), ArrayIndex i') ->
                             maybe
                               (Left $
@@ -524,7 +521,7 @@
       "'$< ... >' queries must start with a RESPONSES[index] query: " ++
       show full
 getValueForQuery (CurlRunningsState env _ _ _) (NonInterpolatedQuery (EnvironmentVariable var)) =
-  Right . String $ H.lookupDefault "" var env
+  Right . String $ A.findWithDefault "" (A.fromText var) env
 getValueForQuery state (InterpolatedQuery _ q) =
   case getValueForQuery state (NonInterpolatedQuery q) of
     Right (String s) -> Right . String $ s
@@ -539,12 +536,12 @@
   -> Bool
 jsonContains f jsonValue =
   let traversedValue = traverseValue jsonValue
-  in f $ \match ->
-       case match of
+  in f $ \match' ->
+       case match' of
          ValueMatch subval -> subval `elem` traversedValue
-         KeyMatch key -> any (`containsKey` key) traversedValue
+         KeyMatch key -> any (`containsKey` (A.fromText key)) traversedValue
          KeyValueMatch key subval ->
-           any (\o -> containsKeyVal o key subval) traversedValue
+           any (\o -> containsKeyVal o (A.fromText key) subval) traversedValue
 
 -- | Does the json value contain all of these sub-values?
 jsonContainsAll :: Value -> [JsonSubExpr] -> Bool
@@ -555,24 +552,24 @@
 jsonContainsAny = jsonContains any
 
 -- | Does the json value contain the given key value pair?
-containsKeyVal :: Value -> T.Text -> Value -> Bool
+containsKeyVal :: Value -> A.KeyType -> Value -> Bool
 containsKeyVal jsonValue key val =
   case jsonValue of
-    Object o -> H.lookup key o == Just val
+    Object o -> A.lookup key o == Just val
     _        -> False
 
 -- | Does the json value contain the given key value pair?
-containsKey :: Value -> T.Text -> Bool
+containsKey :: Value -> A.KeyType -> Bool
 containsKey jsonValue key =
   case jsonValue of
-    Object o -> isJust $ H.lookup key o
+    Object o -> isJust $ A.lookup key o
     _        -> False
 
 -- | Fully traverse the json and return a list of all the values
 traverseValue :: Value -> [Value]
 traverseValue val =
   case val of
-    Object o     -> val : concatMap traverseValue (H.elems o)
+    Object o     -> val : concatMap traverseValue (A.elems o)
     Array o      -> val : concatMap traverseValue o
     n@(Number _) -> [n]
     s@(String _) -> [s]
diff --git a/src/Testing/CurlRunnings/Internal.hs b/src/Testing/CurlRunnings/Internal.hs
--- a/src/Testing/CurlRunnings/Internal.hs
+++ b/src/Testing/CurlRunnings/Internal.hs
@@ -20,15 +20,12 @@
   ) where
 
 import           Control.Monad
-import           Data.Monoid
 import qualified Data.Text          as T
 import qualified Data.Text.Lazy     as TL
 import           Debug.Trace
 import           System.Clock
 import qualified Text.Pretty.Simple as P
-import           Text.Printf
 
-
 makeGreen :: T.Text -> T.Text
 makeGreen s = "\x1B[32m" <> s <> "\x1B[0m"
 
@@ -83,9 +80,6 @@
 nowMillis = do
   t <- getTime Realtime
   return $ (toNanoSecs t) `div` 1000000
-
-roundToStr :: (PrintfArg a, Floating a) => a -> String
-roundToStr = printf "%0.2f"
 
 millisToS :: Integer -> Double
 millisToS t = (fromIntegral t :: Double) / 1000.0
diff --git a/src/Testing/CurlRunnings/Internal/Aeson.hs b/src/Testing/CurlRunnings/Internal/Aeson.hs
new file mode 100644
--- /dev/null
+++ b/src/Testing/CurlRunnings/Internal/Aeson.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE CPP #-}
+
+-- | Module for the purpose of Aeson compatibility
+module Testing.CurlRunnings.Internal.Aeson
+  ( module Map
+  , KeyType
+  , MapType
+  , findWithDefault
+  , fromText
+  , toText
+  ) where
+
+#if MIN_VERSION_aeson(2,0,0)
+
+import Data.Aeson.KeyMap as Map
+import Data.Aeson.Key (Key, fromText, toText)
+
+type MapType v = Map.KeyMap v
+type KeyType = Key
+
+#else
+
+import Data.Text (Text)
+import Data.HashMap.Strict as Map hiding (findWithDefault)
+
+type MapType v = Map.HashMap Text v
+type KeyType = Text
+
+fromText :: Text -> Text
+fromText = id
+
+toText :: Text -> Text
+toText = id
+
+#endif
+
+findWithDefault :: a -> KeyType -> MapType a -> a
+findWithDefault def k kv = case Map.lookup k kv of
+    Just v -> v
+    _      -> def
+{-# INLINABLE findWithDefault #-}
diff --git a/src/Testing/CurlRunnings/Internal/KeyValuePairs.hs b/src/Testing/CurlRunnings/Internal/KeyValuePairs.hs
--- a/src/Testing/CurlRunnings/Internal/KeyValuePairs.hs
+++ b/src/Testing/CurlRunnings/Internal/KeyValuePairs.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings  #-}
+{-# LANGUAGE StandaloneDeriving #-}
 
 -- | A module defining the KeyValuePairs type. This type may be used to
 -- represent a structure in a specification that is a collection of
@@ -17,24 +18,31 @@
 import           Data.Aeson
 import           Data.Aeson.Types
 import qualified Data.ByteString.Lazy as LBS
-import           Data.HashMap.Strict  as H
+import           Data.List            ((\\))
 import qualified Data.Text            as T
 import           Data.Text.Encoding   as T
+import qualified Testing.CurlRunnings.Internal.Aeson as A
 
 -- | A container for a list of key-value pairs
 newtype KeyValuePairs = KeyValuePairs [KeyValuePair] deriving Show
 
 -- | A representation of a single key-value pair
-data KeyValuePair = KeyValuePair T.Text T.Text deriving Show
+data KeyValuePair = KeyValuePair A.KeyType T.Text deriving Show
 
+deriving instance Eq KeyValuePair
+
+-- KeyValuePairs should be considered equal if they contain the same elements.
+instance Eq KeyValuePairs where
+  (==) (KeyValuePairs x) (KeyValuePairs y) = null (x \\ y) && null (y \\ x)
+
 instance ToJSON KeyValuePairs where
   toJSON (KeyValuePairs qs) =
     object (fmap (\(KeyValuePair k v) -> k .= toJSON v) qs)
 
 instance FromJSON KeyValuePairs where
   parseJSON = withObject "keyValuePairs" parseKeyValuePairs where
-    parseKeyValuePairs o = KeyValuePairs <$> traverse parseKeyValuePair (H.toList o)
-    parseKeyValuePair (t, v) = KeyValuePair t <$> parseSingleValueType v
+    parseKeyValuePairs o = KeyValuePairs <$> traverse parseKeyValuePair (A.toList o)
+    parseKeyValuePair (k, v) = KeyValuePair k <$> parseSingleValueType v
 
 parseSingleValueType :: Value -> Parser T.Text
 parseSingleValueType (Bool b)   = parseToText b
diff --git a/src/Testing/CurlRunnings/Internal/Parser.hs b/src/Testing/CurlRunnings/Internal/Parser.hs
--- a/src/Testing/CurlRunnings/Internal/Parser.hs
+++ b/src/Testing/CurlRunnings/Internal/Parser.hs
@@ -34,9 +34,9 @@
       parseQuery
     ) where
 
-import           Data.Bifunctor             (Bifunctor (..))
-import           Data.Char                  (isAscii)
-import           Data.List
+import           Data.Bifunctor             ()
+import           Data.Char                  ()
+import           Data.List                  (isInfixOf)
 import qualified Data.Text                  as T
 import           Data.Void
 import           Testing.CurlRunnings.Types
diff --git a/src/Testing/CurlRunnings/Internal/Payload.hs b/src/Testing/CurlRunnings/Internal/Payload.hs
--- a/src/Testing/CurlRunnings/Internal/Payload.hs
+++ b/src/Testing/CurlRunnings/Internal/Payload.hs
@@ -53,28 +53,28 @@
 
 import           Data.Aeson
 import qualified Data.Char                                   as C
-import qualified Data.HashMap.Strict                         as H
 import qualified Data.Text                                   as T
 import           GHC.Generics
+import qualified Testing.CurlRunnings.Internal.Aeson         as A
 import           Testing.CurlRunnings.Internal.KeyValuePairs
 
 data Payload = JSON Value | URLEncoded KeyValuePairs deriving Generic
 
 instance Show Payload where
   show (JSON v) = show v
-  show (URLEncoded (KeyValuePairs xs)) = T.unpack $ T.intercalate "&" $ fmap (\(KeyValuePair k v) -> k <> "=" <> v) xs
+  show (URLEncoded (KeyValuePairs xs)) = T.unpack $ T.intercalate "&" $ fmap (\(KeyValuePair k v) -> A.toText k <> "=" <> v) xs
 
-payloadTagFieldName :: T.Text
+payloadTagFieldName :: A.KeyType
 payloadTagFieldName = "bodyType"
 
-payloadContentsFieldName :: T.Text
+payloadContentsFieldName :: A.KeyType
 payloadContentsFieldName = "content"
 
 instance FromJSON Payload where
   parseJSON v = withObject "payload" parsePayload v where
-    parsePayload o = if not (H.member payloadTagFieldName o) then return (JSON v) else genericParseJSON payloadOptions v
-    payloadOptions = defaultOptions { sumEncoding = TaggedObject { tagFieldName = T.unpack payloadTagFieldName
-                                                                 , contentsFieldName = T.unpack payloadContentsFieldName
+    parsePayload o = if not (A.member payloadTagFieldName o) then return (JSON v) else genericParseJSON payloadOptions v
+    payloadOptions = defaultOptions { sumEncoding = TaggedObject { tagFieldName = T.unpack . A.toText $ payloadTagFieldName
+                                                                 , contentsFieldName = T.unpack . A.toText $ payloadContentsFieldName
                                                                  }
                                     , constructorTagModifier = fmap C.toLower
                                     }
diff --git a/src/Testing/CurlRunnings/Types.hs b/src/Testing/CurlRunnings/Types.hs
--- a/src/Testing/CurlRunnings/Types.hs
+++ b/src/Testing/CurlRunnings/Types.hs
@@ -40,15 +40,12 @@
 
 import           Data.Aeson
 import           Data.Aeson.Types
-import qualified Data.Char                                   as C
-import           Data.Hashable                               (Hashable)
-import qualified Data.HashMap.Strict                         as H
 import           Data.Maybe
-import           Data.Monoid
 import qualified Data.Text                                   as T
 import qualified Data.Vector                                 as V
 import           GHC.Generics
 import           Testing.CurlRunnings.Internal
+import qualified Testing.CurlRunnings.Internal.Aeson         as A
 import           Testing.CurlRunnings.Internal.Headers
 import           Testing.CurlRunnings.Internal.KeyValuePairs
 import           Testing.CurlRunnings.Internal.Payload
@@ -92,9 +89,9 @@
     | justAndNotEmpty "notContains" v = NotContains <$> v .: "notContains"
   parseJSON invalid = typeMismatch "JsonMatcher" invalid
 
-justAndNotEmpty :: (Eq k, Hashable k) => k -> H.HashMap k Value -> Bool
+justAndNotEmpty :: A.KeyType -> A.MapType Value -> Bool
 justAndNotEmpty key obj =
-  (isJust $ H.lookup key obj) && (H.lookup key obj /= Just Null)
+  isJust (A.lookup key obj) && A.lookup key obj /= Just Null
 
 -- | Simple predicate to check value constructor type
 isContains :: JsonMatcher -> Bool
@@ -177,12 +174,12 @@
 instance FromJSON JsonSubExpr where
   parseJSON (Object v)
     | justAndNotEmpty "keyValueMatch" v =
-      let toParse = fromJust $ H.lookup "keyValueMatch" v
+      let toParse = fromJust $ A.lookup "keyValueMatch" v
       in case toParse of
            Object o -> KeyValueMatch <$> o .: "key" <*> o .: "value"
            _        -> typeMismatch "JsonSubExpr" toParse
     | justAndNotEmpty "keyMatch" v =
-      let toParse = fromJust $ H.lookup "keyMatch" v
+      let toParse = fromJust $ A.lookup "keyMatch" v
       in case toParse of
            String s -> return $ KeyMatch s
            _        -> typeMismatch "JsonSubExpr" toParse
@@ -403,7 +400,7 @@
 isFailing = not . isPassing
 
 -- | A map of the system environment
-type Environment = H.HashMap T.Text T.Text
+type Environment = A.MapType T.Text
 
 data TLSCheckType = SkipTLSCheck | DoTLSCheck deriving (Show, Eq)
 
@@ -428,11 +425,6 @@
   | ArrayIndex Integer
   deriving (Show)
 
-printOriginalQuery :: Index -> String
-printOriginalQuery (CaseResultIndex t) = "RESPONSES[" ++ show t ++ "]"
-printOriginalQuery (KeyIndex key)      = "." ++ T.unpack key
-printOriginalQuery (ArrayIndex i)      = printf "[%d]" i
-
 -- | A single entity to be queries from a json value
 data Query =
   -- | A single query contains a list of discrete index operations
@@ -451,12 +443,6 @@
   -- | Just a query, no leading text
   | NonInterpolatedQuery Query
   deriving (Show)
-
-printQueryString :: InterpolatedQuery -> String
-printQueryString (LiteralText t) = show t
-printQueryString (InterpolatedQuery raw (Query indexes)) =
-  printf "%s$<%s>" raw $ concatMap show indexes
-printQueryString (NonInterpolatedQuery (Query indexes)) = printf "$<%s>" (concatMap show indexes)
 
 -- | The full string in which a query appears, eg "prefix-${{RESPONSES[0].key.another_key[0].last_key}}"
 type FullQueryText = T.Text
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,18 +1,17 @@
 {-# LANGUAGE OverloadedStrings  #-}
 {-# LANGUAGE QuasiQuotes        #-}
-{-# LANGUAGE StandaloneDeriving #-}
 
 module Main where
 
 import           Data.Aeson
 import           Data.ByteString                             (ByteString)
 import           Data.Either
-import           Data.List
 import qualified Data.Text                                   as T
 import           System.Directory
 import           Test.Hspec
 import           Testing.CurlRunnings
 import           Testing.CurlRunnings.Internal
+import qualified Testing.CurlRunnings.Internal.Aeson         as A
 import           Testing.CurlRunnings.Internal.Headers
 import           Testing.CurlRunnings.Internal.KeyValuePairs
 import           Testing.CurlRunnings.Internal.Parser
@@ -92,12 +91,12 @@
   it "arrayGet should handle positive and negative indexes correctly" $ do
     let a = [1, 2, 3]
         b = [] :: [Int]
-    (arrayGet a 0) `shouldBe` Just 1
-    (arrayGet a 1) `shouldBe` Just 2
-    (arrayGet a 2) `shouldBe` Just 3
-    (arrayGet a (-1)) `shouldBe` Just 3
-    (arrayGet a (-2)) `shouldBe` Just 2
-    (arrayGet a (-3)) `shouldBe` Just 1
+    (arrayGet a 0) `shouldBe` Just (1 :: Integer)
+    (arrayGet a 1) `shouldBe` Just (2 :: Integer)
+    (arrayGet a 2) `shouldBe` Just (3 :: Integer)
+    (arrayGet a (-1)) `shouldBe` Just (3 :: Integer)
+    (arrayGet a (-2)) `shouldBe` Just (2 :: Integer)
+    (arrayGet a (-3)) `shouldBe` Just (1 :: Integer)
     (arrayGet a (-4)) `shouldBe` Nothing
     (arrayGet a 3) `shouldBe` Nothing
     (arrayGet b 0) `shouldBe` Nothing
@@ -156,16 +155,10 @@
   let expectedHeaders = Right . HeaderSet $ uncurry Header <$> expected in
     actual `shouldBe` expectedHeaders
 
-shouldBeKeyValuePairs :: ByteString -> [(T.Text, T.Text)] -> Expectation
-shouldBeKeyValuePairs json expected = actual `shouldBe` expectedKeyValuePairs where
-  actual = eitherDecodeStrict json
+shouldBeKeyValuePairs :: ByteString -> [(A.KeyType, T.Text)] -> Expectation
+shouldBeKeyValuePairs j expected = actual `shouldBe` expectedKeyValuePairs where
+  actual = eitherDecodeStrict j
   expectedKeyValuePairs = Right . KeyValuePairs $ uncurry KeyValuePair <$> expected
-
-deriving instance Eq KeyValuePair
-
--- KeyValuePairs should be considered equal if they contain the same elements.
-instance Eq KeyValuePairs where
-  (==) (KeyValuePairs x) (KeyValuePairs y) = null (x \\ y) && null (y \\ x)
 
 isURLEncoded :: Either String Payload -> Bool
 isURLEncoded (Right (URLEncoded _)) = True
