4652a15bab
* 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>
289 lines
7.3 KiB
Go
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
|
|
}
|