packages feed

telegram-api 0.2.1.0 → 0.2.1.1

raw patch · 7 files changed

+243/−189 lines, 7 files

Files

src/Web/Telegram/API/Bot/API.hs view
@@ -54,7 +54,7 @@   toText (Token x) = x
 
 instance FromText Token where
-  fromText x = Just (Token (x))
+  fromText x = Just $ Token x
 
 -- | Type for token
 type TelegramToken = Capture ":token" Token
@@ -152,7 +152,6 @@   :<|> answerInlineQuery_ =
       client api
           (BaseUrl Https "api.telegram.org" 443)
-          --(BaseUrl Http "localhost" 8888)
 -- | A simple method for testing your bot's auth token. Requires no parameters.
 --   Returns basic information about the bot in form of a 'User' object.
 getMe :: Token -> IO (Either ServantError GetMeResponse)
@@ -160,47 +159,47 @@ 
 -- | Use this method to send text messages. On success, the sent 'Message' is returned.
 sendMessage :: Token -> SendMessageRequest -> IO (Either ServantError MessageResponse)
-sendMessage token request = runEitherT $ sendMessage_ token request
+sendMessage = run sendMessage_
 
 -- | Use this method to forward messages of any kind. On success, the sent 'Message' is returned.
 forwardMessage :: Token -> ForwardMessageRequest -> IO (Either ServantError MessageResponse)
-forwardMessage token request = runEitherT $ forwardMessage_ token request
+forwardMessage = run forwardMessage_
 
 -- | Use this method to send photos. On success, the sent 'Message' is returned.
 sendPhoto :: Token -> SendPhotoRequest -> IO (Either ServantError MessageResponse)
-sendPhoto token request = runEitherT $ sendPhoto_ token request
+sendPhoto = run sendPhoto_
 
 -- | Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .mp3 format. On success, the sent 'Message' is returned. Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
 --
 --       For backward compatibility, when the fields __title__ and __performer__ are both empty and the mime-type of the file to be sent is not _audio/mpeg_, the file will be sent as a playable voice message. For this to work, the audio must be in an .ogg file encoded with OPUS. This behavior will be phased out in the future. For sending voice messages, use the 'sendVoice' method instead.
 sendAudio :: Token -> SendAudioRequest -> IO (Either ServantError MessageResponse)
-sendAudio token request = runEitherT $ sendAudio_ token request
+sendAudio = run sendAudio_
 
 -- | Use this method to send general files. On success, the sent 'Message' is returned. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
 sendDocument :: Token -> SendDocumentRequest -> IO (Either ServantError MessageResponse)
-sendDocument token request = runEitherT $ sendDocument_ token request
+sendDocument = run sendDocument_
 
 -- | Use this method to send .webp stickers. On success, the sent 'Message' is returned.
 sendSticker :: Token -> SendStickerRequest -> IO (Either ServantError MessageResponse)
-sendSticker token request = runEitherT $ sendSticker_ token request
+sendSticker = run sendSticker_
 
 -- | Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as 'Document'). On success, the sent 'Message' is returned. Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
 sendVideo :: Token -> SendVideoRequest -> IO (Either ServantError MessageResponse)
-sendVideo token request = runEitherT $ sendVideo_ token request
+sendVideo = run sendVideo_
 
 -- | Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as 'Audio' or 'Document'). On success, the sent 'Message' is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
 sendVoice :: Token -> SendVoiceRequest -> IO (Either ServantError MessageResponse)
-sendVoice token request = runEitherT $ sendVoice_ token request
+sendVoice = run sendVoice_
 
 -- | Use this method to send point on the map. On success, the sent 'Message' is returned.
 sendLocation :: Token -> SendLocationRequest -> IO (Either ServantError MessageResponse)
-sendLocation token request = runEitherT $ sendLocation_ token request
+sendLocation = run sendLocation_
 
 -- | Use this method when you need to tell the user that something is happening on the bot's side.
 --   The status is set for 5 seconds or less (when a message arrives from your bot,
 --   Telegram clients clear its typing status).
 sendChatAction :: Token -> SendChatActionRequest -> IO (Either ServantError ChatActionResponse)
-sendChatAction token request = runEitherT $ sendChatAction_ token request
+sendChatAction = run sendChatAction_
 
 -- | Use this method to receive incoming updates using long polling. An Array of 'Update' objects is returned.
 getUpdates :: Token -> Maybe Int -> Maybe Int -> Maybe Int -> IO (Either ServantError UpdatesResponse)
@@ -208,7 +207,7 @@ 
 -- | Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can download files of up to 20MB in size. On success, a 'File' object is returned. The file can then be downloaded via the link @https://api.telegram.org/file/bot<token>/<file_path>@, where @<file_path>@ is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling getFile again.
 getFile :: Token -> Text -> IO (Either ServantError FileResponse)
-getFile token file_id = runEitherT $ getFile_ token (Just file_id)
+getFile token file_id = runEitherT $ getFile_ token $ Just file_id
 
 -- | Use this method to get a list of profile pictures for a user. Returns a 'UserProfilePhotos' object.
 getUserProfilePhotos :: Token -> Int -> Maybe Int -> Maybe Int -> IO (Either ServantError UserProfilePhotosResponse)
@@ -223,4 +222,7 @@ setWebhook token url = runEitherT $ setWebhook_ token url
 
 answerInlineQuery :: Token -> AnswerInlineQueryRequest -> IO (Either ServantError InlineQueryResponse)
-answerInlineQuery token request = runEitherT $ answerInlineQuery_ token request+answerInlineQuery = run answerInlineQuery_
+
+run :: (Token -> a -> EitherT ServantError IO b) -> Token -> a -> IO (Either ServantError b)
+run e t r = runEitherT $ e t r
src/Web/Telegram/API/Bot/Data.hs view
@@ -325,7 +325,7 @@ inlineQueryJSONOptions = defaultOptions {
     fieldLabelModifier     = drop 7
   , omitNothingFields      = True
-  , sumEncoding            = TaggedObject { tagFieldName = "type" }
+  , sumEncoding            = TaggedObject { tagFieldName = "type", contentsFieldName = undefined }
   , constructorTagModifier = tagModifier
   }
 
src/Web/Telegram/API/Bot/Requests.hs view
@@ -196,7 +196,7 @@   toJSON UploadVideo    = "upload_video"
   toJSON RecordAudio    = "record_audio"
   toJSON UploadAudio    = "upload_audio"
-  toJSON UploadDocument = "upload_cocument"
+  toJSON UploadDocument = "upload_document"
   toJSON FindLocation   = "find_location"
 
 instance FromJSON ChatAction where
@@ -206,7 +206,7 @@   parseJSON "upload_video"    = pure UploadVideo
   parseJSON "record_audio"    = pure RecordAudio
   parseJSON "upload_audio"    = pure UploadAudio
-  parseJSON "upload_cocument" = pure UploadDocument
+  parseJSON "upload_document" = pure UploadDocument
   parseJSON "find_location"   = pure FindLocation
 
 -- | This object represents request for 'sendChatAction'
@@ -264,4 +264,4 @@   toJSON = toJsonDrop 6
 
 instance FromJSON ReplyKeyboard where
-  parseJSON = parseJsonDrop 6+  parseJSON = parseJsonDrop 6
telegram-api.cabal view
@@ -1,5 +1,5 @@ name:                telegram-api
-version:             0.2.1.0
+version:             0.2.1.1
 synopsis:            Telegram Bot API bindings
 description:         High-level bindings to the Telegram Bot API
 homepage:            http://github.com/klappvisor/haskell-telegram-api#readme
@@ -36,6 +36,8 @@   type:                exitcode-stdio-1.0
   hs-source-dirs:      test
   main-is:             Spec.hs
+  other-modules:       MainSpec
+                     , InlineSpec
   build-depends:       base
                      , text
                      , hspec
+ test/InlineSpec.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE DataKinds         #-}
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE DeriveAnyClass    #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeOperators     #-}
+{-# LANGUAGE TemplateHaskell   #-}
+
+module InlineSpec (spec) where
+
+import           Control.Monad
+import           Web.Telegram.API.Bot
+import           Test.Hspec
+import           Data.Text (Text)
+import qualified Data.Text as T
+import           Servant.Client
+import           Servant.API
+import           Network.HTTP.Types.Status
+import           System.Environment
+
+spec :: Token -> Text -> Spec
+spec token chatId = do
+  let inline_query_id = ""
+  describe "/answerInlineQuery" $ do
+    it "should answer with article" $ do
+      Right InlineQueryResponse { query_result = res } <-
+        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_article] Nothing Nothing Nothing)
+      res `shouldBe` True
+    it "should answer with photo" $ do
+      Right InlineQueryResponse { query_result = res } <-
+        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_photo] Nothing Nothing Nothing)
+      res `shouldBe` True
+    it "should answer with gif" $ do
+      Right InlineQueryResponse { query_result = res } <-
+        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_gif] Nothing Nothing Nothing)
+      res `shouldBe` True
+    it "should answer with mpeg gif" $ do
+      Right InlineQueryResponse { query_result = res } <-
+        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_mpeg] Nothing Nothing Nothing)
+      res `shouldBe` True
+    it "should answer with video" $ do
+      Right InlineQueryResponse { query_result = res } <-
+        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_video] Nothing Nothing Nothing)
+      res `shouldBe` True
+
+  describe "/answerInlineQuery" $ do
+    it "should get updates and answer" $ do
+      Right UpdatesResponse { update_result = updates} <-
+        getUpdates token Nothing Nothing Nothing
+      Update { inline_query = Just (InlineQuery { query_id = id } ) } <- pure (last updates)
+      e <-
+        answerInlineQuery token (AnswerInlineQueryRequest id [inline_video] Nothing Nothing Nothing)
+      putStrLn (show e)
+
+inline_article = InlineQueryResultArticle "2131341" (Just "text article content") Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
+inline_photo = InlineQueryResultPhoto "1430810" "http://vignette3.wikia.nocookie.net/victorious/images/f/f8/NyanCat.jpg" Nothing Nothing (Just "http://vignette3.wikia.nocookie.net/victorious/images/f/f8/NyanCat.jpg") Nothing Nothing Nothing Nothing Nothing Nothing
+inline_gif = InlineQueryResultGif "131231234" "https://media.giphy.com/media/zEO5eq3ZsEwbS/giphy.gif" Nothing Nothing (Just "https://media.giphy.com/media/zEO5eq3ZsEwbS/100.gif") Nothing Nothing Nothing Nothing Nothing
+inline_mpeg = InlineQueryResultMpeg4Gif "131251234" "https://media.giphy.com/media/zEO5eq3ZsEwbS/giphy.gif" Nothing Nothing (Just "https://media.giphy.com/media/zEO5eq3ZsEwbS/100.gif") Nothing Nothing Nothing Nothing Nothing
+inline_video = InlineQueryResultVideo "123413542" "https://www.youtube.com/embed/TBKN7_vx2xo" "text/html" (Just "Enjoykin — Nyash Myash") Nothing Nothing Nothing Nothing Nothing (Just "https://i.ytimg.com/vi_webp/TBKN7_vx2xo/mqdefault.webp") (Just "Enjoykin — Nyash Myash") Nothing
+ test/MainSpec.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE DataKinds         #-}
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE DeriveAnyClass    #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeOperators     #-}
+{-# LANGUAGE TemplateHaskell   #-}
+
+module MainSpec (spec) where
+
+import           Control.Monad
+import           Web.Telegram.API.Bot
+import           Test.Hspec
+import           Data.Text (Text)
+import qualified Data.Text as T
+import           Servant.Client
+import           Servant.API
+import           Network.HTTP.Types.Status
+import           System.Environment
+
+spec :: Token -> Text -> Spec
+spec token chatId = do
+  describe "/getMe" $ do
+    it "responds with correct bot's name" $ do
+      Right GetMeResponse { user_result = u } <-
+        getMe token
+      (user_first_name u) `shouldBe` "TelegramAPIBot"
+
+  describe "/sendMessage" $ do
+    it "should send message" $ do
+      Right MessageResponse { message_result = m } <-
+        sendMessage token (SendMessageRequest chatId "test message" Nothing Nothing Nothing Nothing)
+      (text m) `shouldBe` (Just "test message")
+
+    it "should return error message" $ do
+      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
+        sendMessage token (SendMessageRequest "" "test message" Nothing Nothing Nothing Nothing)
+      msg `shouldBe` "Bad Request"
+
+    it "should send message markdown" $ do
+      Right MessageResponse { message_result = m } <-
+        sendMessage token (SendMessageRequest chatId "text *bold* _italic_ [github](github.com/klappvisor/telegram-api)" (Just Markdown) Nothing Nothing Nothing)
+      (text m) `shouldBe` (Just "text bold italic github")
+
+    it "should set keyboard" $ do
+      Right MessageResponse { message_result = m } <-
+        sendMessage token (SendMessageRequest chatId "set keyboard" Nothing Nothing Nothing (Just (ReplyKeyboardMarkup [["A", "B"], ["C"]] Nothing Nothing Nothing)))
+      (text m) `shouldBe` (Just "set keyboard")
+
+    it "should remove keyboard" $ do
+      Right MessageResponse { message_result = m } <-
+        sendMessage token (SendMessageRequest chatId "remove keyboard" Nothing Nothing Nothing (Just (ReplyKeyboardHide True Nothing)))
+      (text m) `shouldBe` (Just "remove keyboard")
+
+    it "should force reply" $ do
+      Right MessageResponse { message_result = m } <-
+        sendMessage token (SendMessageRequest chatId "force reply" Nothing Nothing Nothing (Just (ForceReply True Nothing)))
+      (text m) `shouldBe` (Just "force reply")
+
+  describe "/forwardMessage" $ do
+    it "should forward message" $ do
+      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
+        forwardMessage token (ForwardMessageRequest chatId chatId 123)
+      msg `shouldBe` "Bad Request"
+
+  describe "/sendPhoto" $ do
+    it "should return error message" $ do
+      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
+        sendPhoto token (SendPhotoRequest "" "photo_id" (Just "photo caption") Nothing Nothing)
+      msg `shouldBe` "Bad Request"
+    it "should send photo" $ do
+      Right MessageResponse { message_result = Message { caption = Just cpt } } <-
+        sendPhoto token (SendPhotoRequest chatId "AgADBAADv6cxGybVMgABtZ_EOpBSdxYD5xwZAAQ4ElUVMAsbbBqFAAIC" (Just "photo caption") Nothing Nothing)
+      cpt `shouldBe` "photo caption"
+
+  describe "/sendAudio" $ do
+    it "should return error message" $ do
+      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
+        sendAudio token (SendAudioRequest "" "audio_id" Nothing (Just "performer") (Just "title") Nothing Nothing)
+      msg `shouldBe` "Bad Request"
+--         it "should send audio" $ do
+--           Right MessageResponse { message_result = Message { audio = Just Audio { audio_title = Just title } } } <-
+--             sendAudio token (SendAudioRequest chatId "audio_id" Nothing (Just "performer") (Just "my title 1") Nothing)
+--           title `shouldBe` "my title 1"
+
+  describe "/sendSticker" $ do
+    it "should send sticker" $ do
+      Right MessageResponse { message_result = Message { sticker = Just sticker } } <-
+        sendSticker token (SendStickerRequest chatId "BQADAgADGgADkWgMAAGXlYGBiM_d2wI" Nothing Nothing)
+      (sticker_file_id sticker) `shouldBe` "BQADAgADGgADkWgMAAGXlYGBiM_d2wI"
+
+  describe "/sendLocation" $ do
+    it "should send location" $ do
+      Right MessageResponse { message_result = Message { location = Just loc } } <-
+        sendLocation token (SendLocationRequest chatId 52.38 4.9 Nothing Nothing)
+      (latitude loc) `shouldSatisfy` (liftM2 (&&) (> 52) (< 52.4))
+      (longitude loc) `shouldSatisfy` (liftM2 (&&) (> 4.89) (< 5))
+
+  describe "/sendChatAction" $ do
+    it "should set typing action" $ do
+      Right ChatActionResponse { action_result = res} <-
+        sendChatAction token (SendChatActionRequest chatId Typing)
+      res `shouldBe` True
+    it "should set find location action" $ do
+      Right ChatActionResponse { action_result = res} <-
+        sendChatAction token (SendChatActionRequest chatId FindLocation)
+      res `shouldBe` True
+    it "should set upload photo action" $ do
+      Right ChatActionResponse { action_result = res} <-
+        sendChatAction token (SendChatActionRequest chatId UploadPhoto)
+      res `shouldBe` True
+
+  describe "/getUpdates" $ do
+    it "should get all messages" $ do
+      Right UpdatesResponse { update_result = updates} <-
+        getUpdates token Nothing Nothing Nothing
+      (length updates) `shouldSatisfy` (>= 0)
+
+  describe "/getFile" $ do
+    it "should get file" $ do
+      Right FileResponse { file_result = file } <-
+        getFile token "AAQEABMXDZEwAARC0Kj3twkzNcMkAAIC"
+      (fmap (T.take 10) (file_path file)) `shouldBe` (Just "thumb/file")
+
+    it "should return error" $ do
+      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
+        getFile token "AAQEABMXDZEwAARC0Kj3twkzNcMkAmm"
+      msg `shouldBe` "Bad Request"
+
+  describe "/getUserProfilePhotos" $ do
+    it "should get user profile photos" $ do
+      Right UserProfilePhotosResponse { photos_result = photos } <-
+        getUserProfilePhotos token (read (T.unpack chatId)) Nothing Nothing
+      (total_count photos) `shouldSatisfy` (> 0)
+
+  describe "/setWebhook" $ do
+    it "should set webhook" $ do
+      Right SetWebhookResponse { webhook_result = res } <-
+        setWebhook token (Just "https://example.com/secret_token")
+      res `shouldBe` True
+
+    it "should remove webhook" $ do
+      Right SetWebhookResponse { webhook_result = res } <-
+        setWebhook token Nothing
+      res `shouldBe` True
test/Spec.hs view
@@ -16,179 +16,27 @@ import           Servant.API
 import           Network.HTTP.Types.Status
 import           System.Environment
+import qualified MainSpec
+import qualified InlineSpec
 
 main :: IO ()
 main = do
-    [token, chatId] <- getArgs
-    withArgs [] $ hspec (spec (Token (T.pack token)) (T.pack chatId))
-
-spec :: Token -> Text -> Spec
-spec token chatId = do
-  describe "/getMe" $ do
-    it "responds with correct bot's name" $ do
-      Right GetMeResponse { user_result = u } <-
-        getMe token
-      (user_first_name u) `shouldBe` "TelegramAPIBot"
-
-  describe "/sendMessage" $ do
-    it "should send message" $ do
-      Right MessageResponse { message_result = m } <-
-        sendMessage token (SendMessageRequest chatId "test message" Nothing Nothing Nothing Nothing)
-      (text m) `shouldBe` (Just "test message")
-
-    it "should return error message" $ do
-      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
-        sendMessage token (SendMessageRequest "" "test message" Nothing Nothing Nothing Nothing)
-      msg `shouldBe` "Bad Request"
-
-    it "should send message markdown" $ do
-      Right MessageResponse { message_result = m } <-
-        sendMessage token (SendMessageRequest chatId "text *bold* _italic_ [github](github.com/klappvisor/telegram-api)" (Just Markdown) Nothing Nothing Nothing)
-      (text m) `shouldBe` (Just "text bold italic github")
-
-    it "should set keyboard" $ do
-      Right MessageResponse { message_result = m } <-
-        sendMessage token (SendMessageRequest chatId "set keyboard" Nothing Nothing Nothing (Just (ReplyKeyboardMarkup [["A", "B"], ["C"]] Nothing Nothing Nothing)))
-      (text m) `shouldBe` (Just "set keyboard")
-
-    it "should remove keyboard" $ do
-      Right MessageResponse { message_result = m } <-
-        sendMessage token (SendMessageRequest chatId "remove keyboard" Nothing Nothing Nothing (Just (ReplyKeyboardHide True Nothing)))
-      (text m) `shouldBe` (Just "remove keyboard")
-
-    it "should force reply" $ do
-      Right MessageResponse { message_result = m } <-
-        sendMessage token (SendMessageRequest chatId "force reply" Nothing Nothing Nothing (Just (ForceReply True Nothing)))
-      (text m) `shouldBe` (Just "force reply")
-
-  describe "/forwardMessage" $ do
-    it "should forward message" $ do
-      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
-        forwardMessage token (ForwardMessageRequest chatId chatId 123)
-      msg `shouldBe` "Bad Request"
-
-  describe "/sendPhoto" $ do
-    it "should return error message" $ do
-      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
-        sendPhoto token (SendPhotoRequest "" "photo_id" (Just "photo caption") Nothing Nothing)
-      msg `shouldBe` "Bad Request"
-    it "should send photo" $ do
-      Right MessageResponse { message_result = Message { caption = Just cpt } } <-
-        sendPhoto token (SendPhotoRequest chatId "AgADBAADv6cxGybVMgABtZ_EOpBSdxYD5xwZAAQ4ElUVMAsbbBqFAAIC" (Just "photo caption") Nothing Nothing)
-      cpt `shouldBe` "photo caption"
-
-  describe "/sendAudio" $ do
-    it "should return error message" $ do
-      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
-        sendAudio token (SendAudioRequest "" "audio_id" Nothing (Just "performer") (Just "title") Nothing Nothing)
-      msg `shouldBe` "Bad Request"
---         it "should send audio" $ do
---           Right MessageResponse { message_result = Message { audio = Just Audio { audio_title = Just title } } } <-
---             sendAudio token (SendAudioRequest chatId "audio_id" Nothing (Just "performer") (Just "my title 1") Nothing)
---           title `shouldBe` "my title 1"
-
-  describe "/sendSticker" $ do
-    it "should send sticker" $ do
-      Right MessageResponse { message_result = Message { sticker = Just sticker } } <-
-        sendSticker token (SendStickerRequest chatId "BQADAgADGgADkWgMAAGXlYGBiM_d2wI" Nothing Nothing)
-      (sticker_file_id sticker) `shouldBe` "BQADAgADGgADkWgMAAGXlYGBiM_d2wI"
-
-  describe "/sendLocation" $ do
-    it "should send location" $ do
-      Right MessageResponse { message_result = Message { location = Just loc } } <-
-        sendLocation token (SendLocationRequest chatId 52.38 4.9 Nothing Nothing)
-      (latitude loc) `shouldSatisfy` (liftM2 (&&) (> 52) (< 52.4))
-      (longitude loc) `shouldSatisfy` (liftM2 (&&) (> 4.89) (< 5))
-
-  describe "/sendChatAction" $ do
-    it "should set typing action" $ do
-      Right ChatActionResponse { action_result = res} <-
-        sendChatAction token (SendChatActionRequest chatId Typing)
-      res `shouldBe` True
-    it "should set find location action" $ do
-      Right ChatActionResponse { action_result = res} <-
-        sendChatAction token (SendChatActionRequest chatId FindLocation)
-      res `shouldBe` True
-    it "should set upload photo action" $ do
-      Right ChatActionResponse { action_result = res} <-
-        sendChatAction token (SendChatActionRequest chatId UploadPhoto)
-      res `shouldBe` True
-
-  describe "/getUpdates" $ do
-    it "should get all messages" $ do
-      Right UpdatesResponse { update_result = updates} <-
-        getUpdates token Nothing Nothing Nothing
-      (length updates) `shouldSatisfy` (>= 0)
-
-  describe "/getFile" $ do
-    it "should get file" $ do
-      Right FileResponse { file_result = file } <-
-        getFile token "AAQEABMXDZEwAARC0Kj3twkzNcMkAAIC"
-      (fmap (T.take 10) (file_path file)) `shouldBe` (Just "thumb/file")
-
-    it "should return error" $ do
-      Left FailureResponse { responseStatus = Status { statusMessage = msg } } <-
-        getFile token "AAQEABMXDZEwAARC0Kj3twkzNcMkAmm"
-      msg `shouldBe` "Bad Request"
-
-  describe "/getUserProfilePhotos" $ do
-    it "should get user profile photos" $ do
-      Right UserProfilePhotosResponse { photos_result = photos } <-
-        getUserProfilePhotos token (read (T.unpack chatId)) Nothing Nothing
-      (total_count photos) `shouldSatisfy` (> 0)
-
-  describe "/setWebhook" $ do
-    it "should set webhook" $ do
-      Right SetWebhookResponse { webhook_result = res } <-
-        setWebhook token (Just "https://example.com/secret_token")
-      res `shouldBe` True
+    args <- getArgs
+    withArgs [] $ hspec (runSpec args)
 
-    it "should remove webhook" $ do
-      Right SetWebhookResponse { webhook_result = res } <-
-        setWebhook token Nothing
-      res `shouldBe` True
+-- Don't run integration tests if no token and chat id provided
+runSpec :: [String] -> SpecWith ()
+runSpec [] = do
+  describe "NoTests" $ do
+    it "Does not run integration tests if no token and chat id provided" $ do
+      pending
 
---  describe "/answerInlineQuery" $ do
---    it "should answer with article" $ do
---      Right InlineQueryResponse { query_result = res } <-
---        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_article] Nothing Nothing Nothing)
---      res `shouldBe` True
---    it "should answer with photo" $ do
---      --Right InlineQueryResponse { query_result = res } <-
---      e <-
---        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_photo] Nothing Nothing Nothing)
---      --res `shouldBe` True
---      putStrLn (show e)
---    it "should answer with gif" $ do
---      --Right InlineQueryResponse { query_result = res } <-
---      e <-
---        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_gif] Nothing Nothing Nothing)
---      --res `shouldBe` True
---      putStrLn (show e)
---    it "should answer with mpeg gif" $ do
---      --Right InlineQueryResponse { query_result = res } <-
---      e <-
---        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_mpeg] Nothing Nothing Nothing)
---      --res `shouldBe` True
---      putStrLn (show e)
---    it "should answer with video" $ do
---      --Right InlineQueryResponse { query_result = res } <-
---      e <-
---        answerInlineQuery token (AnswerInlineQueryRequest inline_query_id [inline_video] Nothing Nothing Nothing)
---      --res `shouldBe` True
---      putStrLn (show e)
---
---  describe "/answerInlineQuery" $ do
---    it "should get updates and answer" $ do
---      Right UpdatesResponse { update_result = updates} <-
---        getUpdates token Nothing Nothing Nothing
---      Update { inline_query = Just (InlineQuery { query_id = id } ) } <- pure (last updates)
---      e <-
---        answerInlineQuery token (AnswerInlineQueryRequest id [inline_video] Nothing Nothing Nothing)
---      putStrLn (show e)
+runSpec [tkn,cId] = do
+    let token = Token (T.pack tkn)
+    let chatId = T.pack cId
+    runSpec' token chatId
 
---inline_article = InlineQueryResultArticle "2131341" (Just "text article content") Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
---inline_photo = InlineQueryResultPhoto "1430810" "http://vignette3.wikia.nocookie.net/victorious/images/f/f8/NyanCat.jpg" Nothing Nothing (Just "http://vignette3.wikia.nocookie.net/victorious/images/f/f8/NyanCat.jpg") Nothing Nothing Nothing Nothing Nothing Nothing
---inline_gif = InlineQueryResultGif "131231234" "https://media.giphy.com/media/zEO5eq3ZsEwbS/giphy.gif" Nothing Nothing (Just "https://media.giphy.com/media/zEO5eq3ZsEwbS/100.gif") Nothing Nothing Nothing Nothing Nothing
---inline_mpeg = InlineQueryResultMpeg4Gif "131251234" "https://media.giphy.com/media/zEO5eq3ZsEwbS/giphy.gif" Nothing Nothing (Just "https://media.giphy.com/media/zEO5eq3ZsEwbS/100.gif") Nothing Nothing Nothing Nothing Nothing
---inline_video = InlineQueryResultVideo "123413542" "https://www.youtube.com/embed/TBKN7_vx2xo" "text/html" (Just "Enjoykin — Nyash Myash") Nothing Nothing Nothing Nothing Nothing (Just "https://i.ytimg.com/vi_webp/TBKN7_vx2xo/mqdefault.webp") (Just "Enjoykin — Nyash Myash") Nothing+runSpec' :: Token -> Text -> SpecWith ()
+runSpec' token chatId = do
+    describe "Main" $ MainSpec.spec token chatId
+    --describe "Inline" $ InlineSpec.spec token chatId