diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Revision history for lsp-test
 
+## 0.15.0.1
+
+* Adds helper functions to resolve code lens, code actions, and completion items.
+
 ## 0.15.0.0
 
 * Support `lsp-types-2.0.0.0` and `lsp-2.0.0.0`.
diff --git a/bench/SimpleBench.hs b/bench/SimpleBench.hs
--- a/bench/SimpleBench.hs
+++ b/bench/SimpleBench.hs
@@ -35,7 +35,7 @@
   { onConfigurationChange = const $ const $ Right ()
   , defaultConfig = ()
   , doInitialize = \env _req -> pure $ Right env
-  , staticHandlers = handlers
+  , staticHandlers = \_caps -> handlers
   , interpretHandler = \env -> Iso (runLspT env) liftIO
   , options = defaultOptions
   }
diff --git a/func-test/FuncTest.hs b/func-test/FuncTest.hs
--- a/func-test/FuncTest.hs
+++ b/func-test/FuncTest.hs
@@ -35,7 +35,7 @@
             { onConfigurationChange = const $ const $ Right ()
             , defaultConfig = ()
             , doInitialize = \env _req -> pure $ Right env
-            , staticHandlers = handlers killVar
+            , staticHandlers = \_caps -> handlers killVar
             , interpretHandler = \env -> Iso (runLspT env) liftIO
             , options = defaultOptions
             }
@@ -82,7 +82,7 @@
             { onConfigurationChange = const $ const $ Right ()
             , defaultConfig = ()
             , doInitialize = \env _req -> pure $ Right env
-            , staticHandlers = handlers
+            , staticHandlers = \_caps -> handlers
             , interpretHandler = \env -> Iso (runLspT env) liftIO
             , options = defaultOptions
             }
diff --git a/lsp-test.cabal b/lsp-test.cabal
--- a/lsp-test.cabal
+++ b/lsp-test.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               lsp-test
-version:            0.15.0.0
+version:            0.15.0.1
 synopsis:           Functional test framework for LSP servers.
 description:
   A test framework for writing tests against
@@ -59,7 +59,7 @@
     , filepath
     , Glob                  >=0.9   && <0.11
     , lens
-    , lsp                   ^>=2.0
+    , lsp                   ^>=2.1
     , lsp-types             ^>=2.0
     , mtl                   <2.4
     , parser-combinators    >=1.2
@@ -102,7 +102,7 @@
     , filepath
     , hspec
     , lens
-    , lsp           ^>=2.0
+    , lsp           ^>=2.1
     , lsp-test
     , mtl           <2.4
     , parser-combinators
diff --git a/src/Language/LSP/Test.hs b/src/Language/LSP/Test.hs
--- a/src/Language/LSP/Test.hs
+++ b/src/Language/LSP/Test.hs
@@ -7,6 +7,7 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE LambdaCase #-}
 
 {-|
 Module      : Language.LSP.Test
@@ -69,10 +70,14 @@
   , executeCommand
   -- ** Code Actions
   , getCodeActions
+  , getAndResolveCodeActions
   , getAllCodeActions
   , executeCodeAction
+  , resolveCodeAction
+  , resolveAndExecuteCodeAction
   -- ** Completions
   , getCompletions
+  , getAndResolveCompletions
   -- ** References
   , getReferences
   -- ** Definitions
@@ -93,6 +98,8 @@
   , applyEdit
   -- ** Code lenses
   , getCodeLenses
+  , getAndResolveCodeLenses
+  , resolveCodeLens
   -- ** Call hierarchy
   , prepareCallHierarchy
   , incomingCalls
@@ -135,6 +142,7 @@
 import System.Process (ProcessHandle, CreateProcess)
 import qualified System.FilePath.Glob as Glob
 import Control.Monad.State (execState)
+import Data.Traversable (for)
 
 -- | Starts a new session.
 --
@@ -530,6 +538,16 @@
     Right (InR _) -> return []
     Left error -> throw (UnexpectedResponseError (SomeLspId $ fromJust $ rsp ^. L.id) error)
 
+-- | Returns the code actions in the specified range, resolving any with 
+-- a non empty _data_ field.
+getAndResolveCodeActions :: TextDocumentIdentifier -> Range -> Session [Command |? CodeAction]
+getAndResolveCodeActions doc range = do
+  items <- getCodeActions doc range
+  for items $ \case 
+    l@(InL _) -> pure l
+    (InR r) | isJust (r ^. L.data_) ->  InR <$> resolveCodeAction r
+    r@(InR _) -> pure r
+
 -- | Returns all the code actions in a document by
 -- querying the code actions at each of the current
 -- diagnostics' positions.
@@ -605,6 +623,22 @@
           let req = TRequestMessage "" (IdInt 0) SMethod_WorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing e)
             in updateState (FromServerMess SMethod_WorkspaceApplyEdit req)
 
+-- |Resolves the provided code action.
+resolveCodeAction :: CodeAction -> Session CodeAction
+resolveCodeAction ca = do
+  rsp <- request SMethod_CodeActionResolve ca
+  case rsp ^. L.result of
+    Right ca -> return ca
+    Left er -> throw (UnexpectedResponseError (SomeLspId $ fromJust $ rsp ^. L.id) er)
+
+-- |If a code action contains a _data_ field: resolves the code action, then 
+-- executes it. Otherwise, just executes it.
+resolveAndExecuteCodeAction :: CodeAction -> Session ()
+resolveAndExecuteCodeAction ca@CodeAction{_data_=Just _} = do
+  caRsp <- resolveCodeAction ca
+  executeCodeAction caRsp
+resolveAndExecuteCodeAction ca = executeCodeAction ca
+
 -- | Adds the current version to the document, as tracked by the session.
 getVersionedDoc :: TextDocumentIdentifier -> Session VersionedTextDocumentIdentifier
 getVersionedDoc (TextDocumentIdentifier uri) = do
@@ -648,6 +682,21 @@
     InR (InL c) -> return $ c ^. L.items
     InR (InR _) -> return []
 
+-- | Returns the completions for the position in the document, resolving any with 
+-- a non empty _data_ field.
+getAndResolveCompletions :: TextDocumentIdentifier -> Position -> Session [CompletionItem]
+getAndResolveCompletions doc pos = do
+  items <- getCompletions doc pos
+  for items $ \item -> if isJust (item ^. L.data_) then resolveCompletion item else pure item
+
+-- |Resolves the provided completion item.
+resolveCompletion :: CompletionItem -> Session CompletionItem
+resolveCompletion ci = do
+  rsp <- request SMethod_CompletionItemResolve ci
+  case rsp ^. L.result of
+    Right ci -> return ci
+    Left error -> throw (UnexpectedResponseError (SomeLspId $ fromJust $ rsp ^. L.id) error)
+
 -- | Returns the references for the position in the document.
 getReferences :: TextDocumentIdentifier -- ^ The document to lookup in.
               -> Position -- ^ The position to lookup.
@@ -748,6 +797,21 @@
 getCodeLenses tId = do
     rsp <- request SMethod_TextDocumentCodeLens (CodeLensParams Nothing Nothing tId)
     pure $ absorbNull $ getResponseResult rsp
+
+-- | Returns the code lenses for the specified document, resolving any with 
+-- a non empty _data_ field.
+getAndResolveCodeLenses :: TextDocumentIdentifier -> Session [CodeLens]
+getAndResolveCodeLenses tId = do
+    codeLenses <- getCodeLenses tId
+    for codeLenses $ \codeLens -> if isJust (codeLens ^. L.data_) then resolveCodeLens codeLens else pure codeLens
+
+-- |Resolves the provided code lens.
+resolveCodeLens :: CodeLens -> Session CodeLens
+resolveCodeLens cl = do
+  rsp <- request SMethod_CodeLensResolve cl
+  case rsp ^. L.result of
+    Right cl -> return cl
+    Left error -> throw (UnexpectedResponseError (SomeLspId $ fromJust $ rsp ^. L.id) error)
 
 -- | Pass a param and return the response from `prepareCallHierarchy`
 prepareCallHierarchy :: CallHierarchyPrepareParams -> Session [CallHierarchyItem]
diff --git a/test/DummyServer.hs b/test/DummyServer.hs
--- a/test/DummyServer.hs
+++ b/test/DummyServer.hs
@@ -31,7 +31,7 @@
         { doInitialize = \env _req -> pure $ Right env
         , defaultConfig = ()
         , onConfigurationChange = const $ pure $ Right ()
-        , staticHandlers = handlers
+        , staticHandlers = \_caps -> handlers
         , interpretHandler = \env ->
             Iso (\m -> runLspT env (runReaderT m handlerEnv)) liftIO
         , options = defaultOptions {optExecuteCommandCommands = Just ["doAnEdit"]}
