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 }