todoist-sdk-0.1.2.1: integration-test/LabelIntegrationSpec.hs
{-# LANGUAGE DisambiguateRecordFields #-}
module LabelIntegrationSpec (spec) where
import Control.Applicative (Applicative (pure), (<$>))
import Control.Exception (bracket)
import Control.Monad (void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except (ExceptT)
import Data.Bool (Bool (..))
import Data.Foldable (traverse_)
import Data.Function (($), (.))
import Data.Functor (Functor (..))
import Data.List (elem, length)
import Data.Maybe (Maybe (..))
import Data.Monoid (Monoid (..), (<>))
import Data.Ord ((>=))
import Data.Text (Text, pack)
import Data.Traversable (traverse)
import Helpers
( assertSucceeds
, generateUniqueName
, getTestConfig
, liftTodoist
)
import System.IO (IO, putStrLn)
import Test.Hspec (Spec, describe, it, pendingWith, runIO, shouldBe, shouldSatisfy)
import Text.Show (show)
import Web.Todoist.Domain.Label
( Label (..)
, LabelId (..)
, LabelParam (..)
, SharedLabelParam (..)
, mkSharedLabelRemove
, mkSharedLabelRename
, addLabel
, deleteLabel
, getLabel
, getLabels
, getSharedLabels
, createLabelBuilder
, removeSharedLabels
, renameSharedLabels
, updateLabel
, updateLabelBuilder
)
import Web.Todoist.Domain.Types (Color (..), IsFavorite (..), Name (..))
import Web.Todoist.Internal.Error (TodoistError)
import Web.Todoist.Runner (todoist)
import Web.Todoist.Runner.IO (TodoistConfig)
import Web.Todoist.Util.Builder (runBuilder, withName, withColor, withIsFavorite)
spec :: Spec
spec = do
maybeConfig <- runIO getTestConfig
case maybeConfig of
Nothing ->
it "requires TODOIST_TEST_API_TOKEN" $
pendingWith "TODOIST_TEST_API_TOKEN not set"
Just config -> do
labelLifecycleSpec config
getLabelsSpec config
updateLabelSpec config
sharedLabelsSpec config
labelLifecycleSpec :: TodoistConfig -> Spec
labelLifecycleSpec config =
describe "Label CRUD lifecycle" $ do
it "creates, retrieves, and deletes a label" $ do
labelName <- pack <$> generateUniqueName "IntegTest-Label"
withTestLabel config labelName $ \labelId -> do
-- Get label and verify fields
label <- liftTodoist config (getLabel labelId)
let Label {_name = labName} = label
liftIO $ labName `shouldBe` Name labelName
-- Delete label
liftTodoist config (deleteLabel labelId)
-- Verify deletion by checking label is not in active labels list
let params = LabelParam {cursor = Nothing, limit = Nothing}
labels <- liftTodoist config (getLabels params)
let labelIds = fmap (\(Label {_id = lid}) -> lid) labels
liftIO $ labelId `elem` labelIds `shouldBe` False
getLabelsSpec :: TodoistConfig -> Spec
getLabelsSpec config =
describe "Get multiple labels" $ do
it "creates multiple labels and retrieves them with getLabels" $ do
-- Create 3 labels
label1Name <- pack <$> generateUniqueName "Label1"
label2Name <- pack <$> generateUniqueName "Label2"
label3Name <- pack <$> generateUniqueName "Label3"
withMultipleTestLabels config [label1Name, label2Name, label3Name] $ \_ -> do
-- Get labels
let params = LabelParam {cursor = Nothing, limit = Nothing}
labels <- liftTodoist config (getLabels params)
-- Verify count and names
let labelNames = fmap (\(Label {_name = n}) -> n) labels
liftIO $ Name label1Name `elem` labelNames `shouldBe` True
liftIO $ Name label2Name `elem` labelNames `shouldBe` True
liftIO $ Name label3Name `elem` labelNames `shouldBe` True
updateLabelSpec :: TodoistConfig -> Spec
updateLabelSpec config =
describe "Update label" $ do
it "updates a label name and color" $ do
labelName <- pack <$> generateUniqueName "IntegTest-Update-Label"
withTestLabel config labelName $ \labelId -> do
-- Update label name and favorite status
let newName = labelName <> "-Updated"
update = runBuilder updateLabelBuilder (withName newName <> withColor "berry_red" <> withIsFavorite True)
updatedLabel <- liftTodoist config (updateLabel update labelId)
-- Verify update
let Label {_name = updatedName, _id = updatedId, _color = updatedColor, _is_favorite = updatedFav} = updatedLabel
liftIO $ updatedName `shouldBe` Name newName
liftIO $ updatedId `shouldBe` labelId
liftIO $ updatedColor `shouldBe` Color "berry_red"
liftIO $ updatedFav `shouldBe` IsFavorite True
sharedLabelsSpec :: TodoistConfig -> Spec
sharedLabelsSpec config =
describe "Shared labels operations" $ do
it "gets shared labels" $ do
let params = SharedLabelParam {omit_personal = Nothing, cursor = Nothing, limit = Just 10}
sharedLabels <- assertSucceeds $ liftTodoist config (getSharedLabels params)
-- Just verify we can call the endpoint without errors
-- Actual content depends on user's account
liftIO $ length sharedLabels `shouldSatisfy` (>= 0)
it "renames and removes shared labels" $ do
-- Create a label to work with
labelName <- pack <$> generateUniqueName "SharedTest"
withTestLabel config labelName $ \_ -> do
-- Rename shared label
let renameReq = mkSharedLabelRename labelName (labelName <> "-Renamed")
liftTodoist config (renameSharedLabels renameReq)
-- Remove shared label
let removeReq = mkSharedLabelRemove (labelName <> "-Renamed")
liftTodoist config (removeSharedLabels removeReq)
-- If we got here without errors, operations succeeded
pure ()
-- | Bracket helper for creating test label
withTestLabel :: TodoistConfig -> Text -> (LabelId -> ExceptT TodoistError IO a) -> IO ()
withTestLabel config labelName action = do
let createLabel = do
liftIO $ putStrLn $ "Creating test label: " <> show labelName
liftTodoist config (addLabel $ runBuilder (createLabelBuilder labelName) mempty)
let deleteLabel' labelId = do
liftIO $ putStrLn $ "Cleaning up test label: " <> show labelName
void $ todoist config (deleteLabel labelId)
let runAction labelId = void $ assertSucceeds $ action labelId
bracket (assertSucceeds createLabel) deleteLabel' runAction
-- | Bracket helper for creating multiple test labels
withMultipleTestLabels ::
TodoistConfig -> [Text] -> ([LabelId] -> ExceptT TodoistError IO a) -> IO ()
withMultipleTestLabels config labelNames action = do
let createLabels = do
liftIO $ putStrLn $ "Creating test labels: " <> show labelNames
liftTodoist config $ traverse (\name -> addLabel $ runBuilder (createLabelBuilder name) mempty) labelNames
let deleteLabels' labelIds = do
liftIO $ putStrLn $ "Cleaning up test labels: " <> show labelNames
traverse_ (void . todoist config . deleteLabel) labelIds
let runAction labelIds = void $ assertSucceeds $ action labelIds
bracket (assertSucceeds createLabels) deleteLabels' runAction