Skip to content

Commit c6ea62b

Browse files
committed
Ensure CLI e2e mutations verify state via readback
1 parent 87bc9f5 commit c6ea62b

6 files changed

Lines changed: 392 additions & 17 deletions

File tree

e2e/cli_tests/account_user_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ func TestAccountSettingsUpdateWithCurrentName(t *testing.T) {
1818
t.Skip("account show returned no name")
1919
}
2020
assertOK(t, h.Run("account", "settings-update", "--name", currentName))
21+
show = h.Run("account", "show")
22+
assertOK(t, show)
23+
if got := show.GetDataString("name"); got != currentName {
24+
t.Fatalf("expected account name %q after settings-update, got %q", currentName, got)
25+
}
2126
}
2227

2328
func TestAccountEntropyWithCurrentValue(t *testing.T) {
@@ -29,6 +34,11 @@ func TestAccountEntropyWithCurrentValue(t *testing.T) {
2934
days = 7
3035
}
3136
assertOK(t, h.Run("account", "entropy", "--auto_postpone_period_in_days", strconv.Itoa(days)))
37+
show = h.Run("account", "show")
38+
assertOK(t, show)
39+
if got := show.GetDataInt("auto_postpone_period_in_days"); got != days {
40+
t.Fatalf("expected auto_postpone_period_in_days=%d, got %d", days, got)
41+
}
3242
}
3343

3444
func TestAccountJoinCodeShow(t *testing.T) {
@@ -74,6 +84,11 @@ func TestUserShowAndUpdateOwnProfile(t *testing.T) {
7484
t.Skip("user show returned no name")
7585
}
7686
assertOK(t, h.Run("user", "update", userID, "--name", currentName))
87+
show = h.Run("user", "show", userID)
88+
assertOK(t, show)
89+
if got := show.GetDataString("name"); got != currentName {
90+
t.Fatalf("expected user name %q after update, got %q", currentName, got)
91+
}
7792
}
7893

7994
func TestUserAvatarUpdateAndRemove(t *testing.T) {

e2e/cli_tests/crud_board_test.go

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,43 +40,105 @@ func TestBoardShowNotFound(t *testing.T) {
4040
func TestBoardCreateUpdateDelete(t *testing.T) {
4141
h := newHarness(t)
4242
boardID := createBoard(t, h)
43-
result := h.Run("board", "update", boardID, "--name", fmt.Sprintf("Updated Board %d", time.Now().UnixNano()))
43+
updatedName := fmt.Sprintf("Updated Board %d", time.Now().UnixNano())
44+
result := h.Run("board", "update", boardID, "--name", updatedName)
4445
assertOK(t, result)
4546

47+
show := h.Run("board", "show", boardID)
48+
assertOK(t, show)
49+
if got := show.GetDataString("name"); got != updatedName {
50+
t.Fatalf("expected updated board name %q, got %q", updatedName, got)
51+
}
52+
4653
deleteResult := h.Run("board", "delete", boardID)
4754
assertOK(t, deleteResult)
4855
if !deleteResult.GetDataBool("deleted") {
4956
t.Fatal("expected deleted=true")
5057
}
58+
assertResult(t, h.Run("board", "show", boardID), harness.ExitNotFound)
5159
}
5260

5361
func TestBoardPublishUnpublish(t *testing.T) {
5462
h := newHarness(t)
5563
boardID := createBoard(t, h)
5664
publish := h.Run("board", "publish", boardID)
5765
assertOK(t, publish)
58-
if publish.GetDataString("public_url") == "" {
66+
publicURL := publish.GetDataString("public_url")
67+
if publicURL == "" {
5968
t.Fatal("expected public_url in publish response")
6069
}
70+
71+
showPublished := h.Run("board", "show", boardID)
72+
assertOK(t, showPublished)
73+
if got := showPublished.GetDataString("public_url"); got != publicURL {
74+
t.Fatalf("expected published board public_url %q, got %q", publicURL, got)
75+
}
76+
6177
assertOK(t, h.Run("board", "unpublish", boardID))
78+
showUnpublished := h.Run("board", "show", boardID)
79+
assertOK(t, showUnpublished)
80+
if got := showUnpublished.GetDataString("public_url"); got != "" {
81+
t.Fatalf("expected public_url to be cleared after unpublish, got %q", got)
82+
}
6283
}
6384

6485
func TestBoardEntropy(t *testing.T) {
6586
h := newHarness(t)
6687
boardID := createBoard(t, h)
67-
assertOK(t, h.Run("board", "entropy", boardID, "--auto_postpone_period_in_days", "7"))
88+
show := h.Run("board", "show", boardID)
89+
assertOK(t, show)
90+
currentDays := show.GetDataInt("auto_postpone_period_in_days")
91+
if currentDays == 0 {
92+
currentDays = 30
93+
}
94+
assertOK(t, h.Run("board", "entropy", boardID, "--auto_postpone_period_in_days", fmt.Sprintf("%d", currentDays)))
95+
show = h.Run("board", "show", boardID)
96+
assertOK(t, show)
97+
if got := show.GetDataInt("auto_postpone_period_in_days"); got != currentDays {
98+
t.Fatalf("expected auto_postpone_period_in_days=%d, got %d", currentDays, got)
99+
}
68100
}
69101

70102
func TestBoardViews(t *testing.T) {
71103
h := newHarness(t)
72-
assertOK(t, h.Run("board", "closed", "--board", fixture.BoardID))
73-
assertOK(t, h.Run("board", "postponed", "--board", fixture.BoardID))
74-
assertOK(t, h.Run("board", "stream", "--board", fixture.BoardID))
104+
boardID := createBoard(t, h)
105+
106+
streamCard := createCard(t, h, boardID)
107+
closedCard := createCard(t, h, boardID)
108+
postponedCard := createCard(t, h, boardID)
109+
assertOK(t, h.Run("card", "close", fmt.Sprintf("%d", closedCard)))
110+
assertOK(t, h.Run("card", "postpone", fmt.Sprintf("%d", postponedCard)))
111+
112+
stream := h.Run("board", "stream", "--board", boardID)
113+
assertOK(t, stream)
114+
if listMapByNumber(stream.GetDataArray(), streamCard) == nil {
115+
t.Fatalf("expected stream view to include card #%d", streamCard)
116+
}
117+
if listMapByNumber(stream.GetDataArray(), closedCard) != nil {
118+
t.Fatalf("expected stream view to exclude closed card #%d", closedCard)
119+
}
120+
if listMapByNumber(stream.GetDataArray(), postponedCard) != nil {
121+
t.Fatalf("expected stream view to exclude postponed card #%d", postponedCard)
122+
}
123+
124+
closed := h.Run("board", "closed", "--board", boardID)
125+
assertOK(t, closed)
126+
if listMapByNumber(closed.GetDataArray(), closedCard) == nil {
127+
t.Fatalf("expected closed view to include card #%d", closedCard)
128+
}
129+
130+
postponed := h.Run("board", "postponed", "--board", boardID)
131+
assertOK(t, postponed)
132+
if listMapByNumber(postponed.GetDataArray(), postponedCard) == nil {
133+
t.Fatalf("expected postponed view to include card #%d", postponedCard)
134+
}
75135
}
76136

77137
func TestBoardInvolvement(t *testing.T) {
78138
h := newHarness(t)
79139
boardID := createBoard(t, h)
140+
// There is currently no CLI command that reads back board involvement, so this
141+
// remains a command-contract check until the CLI exposes that state.
80142
assertOK(t, h.Run("board", "involvement", boardID, "--involvement", "watching"))
81143
assertOK(t, h.Run("board", "involvement", boardID, "--involvement", "access_only"))
82144
}

e2e/cli_tests/crud_card_test.go

Lines changed: 112 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,112 @@ func TestCardLifecycle(t *testing.T) {
3636
h := newHarness(t)
3737
num := createCard(t, h, fixture.BoardID)
3838
numStr := strconv.Itoa(num)
39+
currentUser := currentUserID(t, h)
40+
updatedTitle := "Updated Card"
41+
tagTitle := "cli-test"
42+
43+
assertOK(t, h.Run("card", "update", numStr, "--title", updatedTitle))
44+
show := h.Run("card", "show", numStr)
45+
assertOK(t, show)
46+
if got := show.GetDataString("title"); got != updatedTitle {
47+
t.Fatalf("expected updated title %q, got %q", updatedTitle, got)
48+
}
3949

40-
assertOK(t, h.Run("card", "update", numStr, "--title", "Updated Card"))
4150
assertOK(t, h.Run("card", "column", numStr, "--column", fixture.ColumnID))
51+
show = h.Run("card", "show", numStr)
52+
assertOK(t, show)
53+
if got := mapValueString(asMap(show.GetDataMap()["column"]), "id"); got != fixture.ColumnID {
54+
t.Fatalf("expected card column %q, got %q", fixture.ColumnID, got)
55+
}
56+
57+
// Watch/unwatch currently have no CLI readback path on card show/list.
4258
assertOK(t, h.Run("card", "watch", numStr))
4359
assertOK(t, h.Run("card", "unwatch", numStr))
60+
61+
// Mark-read/mark-unread likewise have no card-scoped CLI readback state today.
4462
assertOK(t, h.Run("card", "mark-read", numStr))
4563
assertOK(t, h.Run("card", "mark-unread", numStr))
64+
4665
assertOK(t, h.Run("card", "pin", numStr))
66+
pins := h.Run("pin", "list")
67+
assertOK(t, pins)
68+
if listMapByNumber(pins.GetDataArray(), num) == nil {
69+
t.Fatalf("expected pin list to include card #%d after pin", num)
70+
}
4771
assertOK(t, h.Run("card", "unpin", numStr))
72+
pins = h.Run("pin", "list")
73+
assertOK(t, pins)
74+
if listMapByNumber(pins.GetDataArray(), num) != nil {
75+
t.Fatalf("expected pin list to exclude card #%d after unpin", num)
76+
}
77+
4878
assertOK(t, h.Run("card", "golden", numStr))
79+
show = h.Run("card", "show", numStr)
80+
assertOK(t, show)
81+
if !show.GetDataBool("golden") {
82+
t.Fatal("expected card to be golden after golden command")
83+
}
4984
assertOK(t, h.Run("card", "ungolden", numStr))
50-
assertOK(t, h.Run("card", "tag", numStr, "--tag", "cli-test"))
85+
show = h.Run("card", "show", numStr)
86+
assertOK(t, show)
87+
if show.GetDataBool("golden") {
88+
t.Fatal("expected card to no longer be golden after ungolden command")
89+
}
90+
91+
assertOK(t, h.Run("card", "tag", numStr, "--tag", tagTitle))
92+
tags := h.Run("tag", "list")
93+
assertOK(t, tags)
94+
var tagID string
95+
for _, item := range tags.GetDataArray() {
96+
m := asMap(item)
97+
if mapValueString(m, "title") == tagTitle {
98+
tagID = mapValueString(m, "id")
99+
break
100+
}
101+
}
102+
if tagID == "" {
103+
t.Fatalf("expected tag list to include %q", tagTitle)
104+
}
105+
taggedCards := h.Run("card", "list", "--tag", tagID)
106+
assertOK(t, taggedCards)
107+
if listMapByNumber(taggedCards.GetDataArray(), num) == nil {
108+
t.Fatalf("expected card list for tag %q to include card #%d", tagTitle, num)
109+
}
110+
51111
assertOK(t, h.Run("card", "self-assign", numStr))
112+
show = h.Run("card", "show", numStr)
113+
assertOK(t, show)
114+
if listMapByID(asSlice(show.GetDataMap()["assignees"]), currentUser) == nil {
115+
t.Fatalf("expected assignees to include current user %q", currentUser)
116+
}
117+
52118
assertOK(t, h.Run("card", "close", numStr))
119+
show = h.Run("card", "show", numStr)
120+
assertOK(t, show)
121+
if !show.GetDataBool("closed") {
122+
t.Fatal("expected card to be closed after close command")
123+
}
124+
53125
assertOK(t, h.Run("card", "reopen", numStr))
126+
show = h.Run("card", "show", numStr)
127+
assertOK(t, show)
128+
if show.GetDataBool("closed") {
129+
t.Fatal("expected card to be open after reopen command")
130+
}
131+
54132
assertOK(t, h.Run("card", "postpone", numStr))
133+
show = h.Run("card", "show", numStr)
134+
assertOK(t, show)
135+
if !show.GetDataBool("postponed") {
136+
t.Fatal("expected card to be postponed after postpone command")
137+
}
138+
55139
assertOK(t, h.Run("card", "untriage", numStr))
140+
show = h.Run("card", "show", numStr)
141+
assertOK(t, show)
142+
if show.GetDataBool("postponed") {
143+
t.Fatal("expected card to no longer be postponed after untriage command")
144+
}
56145
}
57146

58147
func TestCardAssignToCurrentUser(t *testing.T) {
@@ -115,6 +204,11 @@ func TestCardMoveBetweenBoards(t *testing.T) {
115204
destinationBoardID := createBoard(t, h)
116205
num := createCard(t, h, fixture.BoardID)
117206
assertOK(t, h.Run("card", "move", strconv.Itoa(num), "--to", destinationBoardID))
207+
show := h.Run("card", "show", strconv.Itoa(num))
208+
assertOK(t, show)
209+
if got := mapValueString(asMap(show.GetDataMap()["board"]), "id"); got != destinationBoardID {
210+
t.Fatalf("expected moved card board %q, got %q", destinationBoardID, got)
211+
}
118212
}
119213

120214
func TestCardAttachmentsShow(t *testing.T) {
@@ -124,7 +218,12 @@ func TestCardAttachmentsShow(t *testing.T) {
124218
func TestCardDelete(t *testing.T) {
125219
h := newHarness(t)
126220
num := createCard(t, h, fixture.BoardID)
127-
assertOK(t, h.Run("card", "delete", strconv.Itoa(num)))
221+
deleteResult := h.Run("card", "delete", strconv.Itoa(num))
222+
assertOK(t, deleteResult)
223+
if !deleteResult.GetDataBool("deleted") {
224+
t.Fatal("expected deleted=true")
225+
}
226+
assertResult(t, h.Run("card", "show", strconv.Itoa(num)), harness.ExitNotFound)
128227
}
129228

130229
func TestCardCreateRoundTrip(t *testing.T) {
@@ -141,8 +240,11 @@ func TestCardCreateRoundTrip(t *testing.T) {
141240
t.Cleanup(func() { newHarness(t).Run("card", "delete", strconv.Itoa(num)) })
142241
show := h.Run("card", "show", strconv.Itoa(num))
143242
assertOK(t, show)
144-
if title := show.GetDataString("title"); title == "" {
145-
t.Fatal("expected title in card show response")
243+
if got := show.GetDataString("title"); got != "Round Trip Card" {
244+
t.Fatalf("expected card title %q, got %q", "Round Trip Card", got)
245+
}
246+
if got := mapValueString(asMap(show.GetDataMap()["board"]), "id"); got != fixture.BoardID {
247+
t.Fatalf("expected card board %q, got %q", fixture.BoardID, got)
146248
}
147249
}
148250

@@ -159,4 +261,9 @@ func TestCardCreateWithUniqueTitle(t *testing.T) {
159261
t.Fatal("no card number in create response")
160262
}
161263
t.Cleanup(func() { newHarness(t).Run("card", "delete", strconv.Itoa(num)) })
264+
show := h.Run("card", "show", strconv.Itoa(num))
265+
assertOK(t, show)
266+
if got := show.GetDataString("title"); got != title {
267+
t.Fatalf("expected card title %q, got %q", title, got)
268+
}
162269
}

0 commit comments

Comments
 (0)