focalboard/server/integrationtests/cards_test.go
Doug Lauder 4652a15bab
Card APIs (#3760)
* cards apis wip

* create card API

* validate cards when creating

* create card fixes

* patch card wip

* wip

* unit test for createCard; CardPatch2BlockPatch

* unit test for PatchCard

* more APIs

* unit tests for GetCardByID

* register GetCard API

* Set FOCALBOARD_UNIT_TESTING for integration tests

* integration tests for CreateCard

* more integration tests for CreateCard

* integtration tests for PatchCard

* fix integration tests for PatchCard

* integration tests for GetCard

* GetCards API wip

* fix merge conflict

* GetCards API and unit tests

* fix linter issues

* fix flaky unit test for mySQL

* Update server/api/api.go

Co-authored-by: Miguel de la Cruz <mgdelacroix@gmail.com>

* Update server/api/api.go

Co-authored-by: Miguel de la Cruz <mgdelacroix@gmail.com>

* address review comments

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@gmail.com>
2022-09-08 13:01:33 +02:00

289 lines
7.3 KiB
Go

package integrationtests
import (
"fmt"
"strconv"
"testing"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/focalboard/server/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCreateCard(t *testing.T) {
t.Run("a non authenticated user should be rejected", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
board := th.CreateBoard(testTeamID, model.BoardTypeOpen)
th.Logout(th.Client)
card := &model.Card{
Title: "basic card",
}
cardNew, resp := th.Client.CreateCard(board.ID, card, false)
th.CheckUnauthorized(resp)
require.Nil(t, cardNew)
})
t.Run("good", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
board := th.CreateBoard(testTeamID, model.BoardTypeOpen)
contentOrder := []string{utils.NewID(utils.IDTypeBlock), utils.NewID(utils.IDTypeBlock), utils.NewID(utils.IDTypeBlock)}
card := &model.Card{
Title: "test card 1",
Icon: "😱",
ContentOrder: contentOrder,
}
cardNew, resp := th.Client.CreateCard(board.ID, card, false)
require.NoError(t, resp.Error)
th.CheckOK(resp)
require.NotNil(t, cardNew)
require.Equal(t, board.ID, cardNew.BoardID)
require.Equal(t, "test card 1", cardNew.Title)
require.Equal(t, "😱", cardNew.Icon)
require.Equal(t, contentOrder, cardNew.ContentOrder)
})
t.Run("invalid card", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
board := th.CreateBoard(testTeamID, model.BoardTypeOpen)
card := &model.Card{
Title: "too many emoji's",
Icon: "😱😱😱😱",
}
cardNew, resp := th.Client.CreateCard(board.ID, card, false)
require.Error(t, resp.Error)
require.Nil(t, cardNew)
})
}
func TestGetCards(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
board := th.CreateBoard(testTeamID, model.BoardTypeOpen)
userID := th.GetUser1().ID
const cardCount = 25
// make some cards with content
for i := 0; i < cardCount; i++ {
card := &model.Card{
BoardID: board.ID,
CreatedBy: userID,
ModifiedBy: userID,
Title: fmt.Sprintf("%d", i),
}
cardNew, resp := th.Client.CreateCard(board.ID, card, true)
th.CheckOK(resp)
blocks := make([]model.Block, 0, 3)
for j := 0; j < 3; j++ {
now := model.GetMillis()
block := model.Block{
ID: utils.NewID(utils.IDTypeBlock),
ParentID: cardNew.ID,
CreatedBy: userID,
ModifiedBy: userID,
CreateAt: now,
UpdateAt: now,
Schema: 1,
Type: model.TypeText,
Title: fmt.Sprintf("text %d for card %d", j, i),
BoardID: board.ID,
}
blocks = append(blocks, block)
}
_, resp = th.Client.InsertBlocks(board.ID, blocks, true)
th.CheckOK(resp)
}
t.Run("fetch all cards", func(t *testing.T) {
cards, resp := th.Client.GetCards(board.ID, 0, -1)
th.CheckOK(resp)
assert.Len(t, cards, cardCount)
})
t.Run("fetch with pagination", func(t *testing.T) {
cardNums := make(map[int]struct{})
// return first 10
cards, resp := th.Client.GetCards(board.ID, 0, 10)
th.CheckOK(resp)
assert.Len(t, cards, 10)
for _, card := range cards {
cardNum, err := strconv.Atoi(card.Title)
require.NoError(t, err)
cardNums[cardNum] = struct{}{}
}
// return second 10
cards, resp = th.Client.GetCards(board.ID, 1, 10)
th.CheckOK(resp)
assert.Len(t, cards, 10)
for _, card := range cards {
cardNum, err := strconv.Atoi(card.Title)
require.NoError(t, err)
cardNums[cardNum] = struct{}{}
}
// return remaining 5
cards, resp = th.Client.GetCards(board.ID, 2, 10)
th.CheckOK(resp)
assert.Len(t, cards, 5)
for _, card := range cards {
cardNum, err := strconv.Atoi(card.Title)
require.NoError(t, err)
cardNums[cardNum] = struct{}{}
}
// make sure all card numbers were returned
assert.Len(t, cardNums, cardCount)
for i := 0; i < cardCount; i++ {
_, ok := cardNums[i]
assert.True(t, ok)
}
})
t.Run("a non authenticated user should be rejected", func(t *testing.T) {
th.Logout(th.Client)
cards, resp := th.Client.GetCards(board.ID, 0, 10)
th.CheckUnauthorized(resp)
require.Nil(t, cards)
})
}
func TestPatchCard(t *testing.T) {
t.Run("a non authenticated user should be rejected", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
_, cards := th.CreateBoardAndCards(testTeamID, model.BoardTypeOpen, 1)
card := cards[0]
th.Logout(th.Client)
newTitle := "another title"
patch := &model.CardPatch{
Title: &newTitle,
}
patchedCard, resp := th.Client.PatchCard(card.ID, patch, false)
th.CheckUnauthorized(resp)
require.Nil(t, patchedCard)
})
t.Run("good", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
board, cards := th.CreateBoardAndCards(testTeamID, model.BoardTypeOpen, 1)
card := cards[0]
// Patch the card
newTitle := "another title"
newIcon := "🐿"
newContentOrder := reverse(card.ContentOrder)
updatedProps := modifyCardProps(card.Properties)
patch := &model.CardPatch{
Title: &newTitle,
Icon: &newIcon,
ContentOrder: &newContentOrder,
UpdatedProperties: updatedProps,
}
patchedCard, resp := th.Client.PatchCard(card.ID, patch, false)
th.CheckOK(resp)
require.NotNil(t, patchedCard)
require.Equal(t, board.ID, patchedCard.BoardID)
require.Equal(t, newTitle, patchedCard.Title)
require.Equal(t, newIcon, patchedCard.Icon)
require.NotEqual(t, card.ContentOrder, patchedCard.ContentOrder)
require.ElementsMatch(t, card.ContentOrder, patchedCard.ContentOrder)
require.EqualValues(t, updatedProps, patchedCard.Properties)
})
t.Run("invalid card patch", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
_, cards := th.CreateBoardAndCards(testTeamID, model.BoardTypeOpen, 1)
card := cards[0]
// Bad patch (too many emoji)
newIcon := "🐿🐿🐿"
patch := &model.CardPatch{
Icon: &newIcon,
}
cardNew, resp := th.Client.PatchCard(card.ID, patch, false)
require.Error(t, resp.Error)
require.Nil(t, cardNew)
})
}
func TestGetCard(t *testing.T) {
t.Run("a non authenticated user should be rejected", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
_, cards := th.CreateBoardAndCards(testTeamID, model.BoardTypeOpen, 1)
card := cards[0]
th.Logout(th.Client)
cardFetched, resp := th.Client.GetCard(card.ID)
th.CheckUnauthorized(resp)
require.Nil(t, cardFetched)
})
t.Run("good", func(t *testing.T) {
th := SetupTestHelper(t).InitBasic()
defer th.TearDown()
board, cards := th.CreateBoardAndCards(testTeamID, model.BoardTypeOpen, 1)
card := cards[0]
cardFetched, resp := th.Client.GetCard(card.ID)
th.CheckOK(resp)
require.NotNil(t, cardFetched)
require.Equal(t, board.ID, cardFetched.BoardID)
require.Equal(t, card.Title, cardFetched.Title)
require.Equal(t, card.Icon, cardFetched.Icon)
require.Equal(t, card.ContentOrder, cardFetched.ContentOrder)
require.EqualValues(t, card.Properties, cardFetched.Properties)
})
}
//
// Helpers.
//
func reverse(src []string) []string {
out := make([]string, 0, len(src))
for i := len(src) - 1; i >= 0; i-- {
out = append(out, src[i])
}
return out
}
func modifyCardProps(m map[string]any) map[string]any {
out := make(map[string]any)
for k := range m {
out[k] = utils.NewID(utils.IDTypeBlock)
}
return out
}