todoist-sdk-0.1.2.1: integration-test/SectionIntegrationSpec.hs
{-# LANGUAGE DisambiguateRecordFields #-}
module SectionIntegrationSpec (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.Function (($))
import Data.Functor (Functor (..))
import Data.List (elem)
import Data.Maybe (Maybe (..))
import Data.Monoid (Monoid (..), (<>))
import Data.Text (Text, pack)
import Helpers
( assertSucceeds
, generateUniqueName
, getTestConfig
, liftTodoist
)
import System.IO (IO, putStrLn)
import Test.Hspec (Spec, describe, it, pendingWith, runIO, shouldBe)
import Text.Show (show)
import qualified Web.Todoist.Domain.Project as P
import Web.Todoist.Domain.Section
( Section (..)
, SectionId (..)
, SectionParam (..)
, addSection
, deleteSection
, getSection
, getSections
, newSectionBuilder
, updateSection
, updateSectionBuilder
)
import Web.Todoist.Domain.Types (Name (..), ProjectId (..))
import Web.Todoist.Internal.Error (TodoistError)
import Web.Todoist.Runner (todoist)
import Web.Todoist.Runner.IO (TodoistConfig)
import Web.Todoist.Util.Builder (runBuilder, withName)
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
sectionLifecycleSpec config
getSectionsSpec config
updateSectionSpec config
sectionLifecycleSpec :: TodoistConfig -> Spec
sectionLifecycleSpec config =
describe "Section CRUD lifecycle" $ do
it "creates, retrieves, and deletes a section" $ do
projectName <- pack <$> generateUniqueName "IntegTest-Section-Project"
sectionName <- pack <$> generateUniqueName "IntegTest-Section"
withTestProjectAndSection config projectName sectionName $ \projectId sectionId -> do
-- Get section and verify fields
section <- liftTodoist config (getSection sectionId)
let Section {_name = secName, _project_id = secProjectId} = section
liftIO $ secName `shouldBe` Name sectionName
liftIO $ secProjectId `shouldBe` projectId
-- Delete section
liftTodoist config (deleteSection sectionId)
-- Verify deletion by checking section is not in active sections list
let params = SectionParam {project_id = Just projectId, cursor = Nothing, limit = Nothing}
sections <- liftTodoist config (getSections params)
let sectionIds = fmap (\(Section {_id = sid}) -> sid) sections
liftIO $ sectionId `elem` sectionIds `shouldBe` False
getSectionsSpec :: TodoistConfig -> Spec
getSectionsSpec config =
describe "Get multiple sections" $ do
it "creates multiple sections and retrieves them with getSections" $ do
projectName <- pack <$> generateUniqueName "IntegTest-GetSections-Project"
withTestProject config projectName $ \projectId -> do
let ProjectId {getProjectId = projId} = projectId
-- Create 3 sections
section1Name <- pack <$> liftIO (generateUniqueName "Section1")
section2Name <- pack <$> liftIO (generateUniqueName "Section2")
section3Name <- pack <$> liftIO (generateUniqueName "Section3")
sectionId1 <- liftTodoist config (addSection $ runBuilder (newSectionBuilder section1Name projId) mempty)
sectionId2 <- liftTodoist config (addSection $ runBuilder (newSectionBuilder section2Name projId) mempty)
sectionId3 <- liftTodoist config (addSection $ runBuilder (newSectionBuilder section3Name projId) mempty)
-- Get sections for project
let params = SectionParam {project_id = Just projectId, cursor = Nothing, limit = Nothing}
sections <- liftTodoist config (getSections params)
-- Verify count and names
let sectionNames = fmap (\(Section {_name = n}) -> n) sections
liftIO $ Name section1Name `elem` sectionNames `shouldBe` True
liftIO $ Name section2Name `elem` sectionNames `shouldBe` True
liftIO $ Name section3Name `elem` sectionNames `shouldBe` True
-- Cleanup
liftTodoist config (deleteSection sectionId1)
liftTodoist config (deleteSection sectionId2)
liftTodoist config (deleteSection sectionId3)
updateSectionSpec :: TodoistConfig -> Spec
updateSectionSpec config =
describe "Update section" $ do
it "updates a section name" $ do
projectName <- pack <$> generateUniqueName "IntegTest-Update-Project"
sectionName <- pack <$> generateUniqueName "IntegTest-Update-Section"
withTestProjectAndSection config projectName sectionName $ \_ sectionId -> do
-- Update section name
let newName = sectionName <> "-Updated"
update = runBuilder updateSectionBuilder (withName newName)
updatedSection <- liftTodoist config (updateSection update sectionId)
-- Verify update
let Section {_name = updatedName, _id = updatedId} = updatedSection
liftIO $ updatedName `shouldBe` Name newName
liftIO $ updatedId `shouldBe` sectionId
-- | Bracket helper for creating test project
withTestProject :: TodoistConfig -> Text -> (ProjectId -> ExceptT TodoistError IO a) -> IO ()
withTestProject config projectName action = do
let createProject = do
liftIO $ putStrLn $ "Creating test project: " <> show projectName
liftTodoist config (P.addProject $ runBuilder (P.createProjectBuilder projectName) mempty)
let deleteProject' projectId = do
liftIO $ putStrLn $ "Cleaning up test project: " <> show projectName
void $ todoist config (P.deleteProject projectId)
let runAction projectId = void $ assertSucceeds $ action projectId
bracket (assertSucceeds createProject) deleteProject' runAction
-- | Bracket helper for creating test project and section
withTestProjectAndSection ::
TodoistConfig ->
Text ->
Text ->
(ProjectId -> SectionId -> ExceptT TodoistError IO a) ->
IO ()
withTestProjectAndSection config projectName sectionName action = do
let createResources = do
liftIO $
putStrLn $
"Creating test project and section: " <> show projectName <> " / " <> show sectionName
projectId <- liftTodoist config (P.addProject $ runBuilder (P.createProjectBuilder projectName) mempty)
let ProjectId {getProjectId = projId} = projectId
sectionCreate = runBuilder (newSectionBuilder sectionName projId) mempty
sectionId <- liftTodoist config (addSection sectionCreate)
pure (projectId, sectionId)
let deleteResources (projectId, sectionId) = do
liftIO $
putStrLn $
"Cleaning up test section and project: " <> show sectionName <> " / " <> show projectName
void $ todoist config (deleteSection sectionId)
void $ todoist config (P.deleteProject projectId)
let runAction (projectId, sectionId) = void $ assertSucceeds $ action projectId sectionId
bracket (assertSucceeds createResources) deleteResources runAction