Skip to content

Commit 79992d2

Browse files
committed
Add regression test for campfire message ordering
Verifies that chat messages sends sort=created_at&direction=desc to the API, respects --limit for truncation, and renders the response in chronological order (oldest to newest).
1 parent fa14e91 commit 79992d2

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

internal/commands/chat_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,3 +1231,69 @@ func TestChatRoomShorthandFlag(t *testing.T) {
12311231
require.Len(t, envelope.Data, 1)
12321232
assert.Equal(t, "Engineering", envelope.Data[0]["title"])
12331233
}
1234+
1235+
// mockChatMessagesTransport captures the lines request and returns messages
1236+
// in desc order (as the API would with sort=created_at&direction=desc).
1237+
type mockChatMessagesTransport struct {
1238+
capturedQuery map[string]string
1239+
}
1240+
1241+
func (t *mockChatMessagesTransport) RoundTrip(req *http.Request) (*http.Response, error) {
1242+
header := make(http.Header)
1243+
header.Set("Content-Type", "application/json")
1244+
1245+
var body string
1246+
switch {
1247+
case strings.Contains(req.URL.Path, "/projects.json"):
1248+
body = `[{"id": 123, "name": "Test Project"}]`
1249+
case strings.Contains(req.URL.Path, "/projects/123"):
1250+
body = `{"id": 123, "dock": [{"name": "chat", "id": 789, "enabled": true}]}`
1251+
case strings.Contains(req.URL.Path, "/lines.json"):
1252+
t.capturedQuery = map[string]string{
1253+
"sort": req.URL.Query().Get("sort"),
1254+
"direction": req.URL.Query().Get("direction"),
1255+
}
1256+
// Return 3 messages in desc order (newest first), as the API does
1257+
body = `[
1258+
{"id": 3, "content": "Third", "created_at": "2026-03-24T12:00:00Z", "status": "active", "visible_to_clients": false, "inherits_status": true, "type": "Chat::Lines::Text", "url": "https://example.com", "app_url": "https://example.com"},
1259+
{"id": 2, "content": "Second", "created_at": "2026-03-24T11:00:00Z", "status": "active", "visible_to_clients": false, "inherits_status": true, "type": "Chat::Lines::Text", "url": "https://example.com", "app_url": "https://example.com"},
1260+
{"id": 1, "content": "First", "created_at": "2026-03-24T10:00:00Z", "status": "active", "visible_to_clients": false, "inherits_status": true, "type": "Chat::Lines::Text", "url": "https://example.com", "app_url": "https://example.com"}
1261+
]`
1262+
default:
1263+
body = `{}`
1264+
}
1265+
1266+
return &http.Response{
1267+
StatusCode: 200,
1268+
Body: io.NopCloser(strings.NewReader(body)),
1269+
Header: header,
1270+
}, nil
1271+
}
1272+
1273+
// TestChatMessagesReturnsNewestInChronologicalOrder verifies that
1274+
// `chat messages` requests newest-first from the API (sort/direction params),
1275+
// respects --limit to truncate the result, and renders in chronological order.
1276+
func TestChatMessagesReturnsNewestInChronologicalOrder(t *testing.T) {
1277+
transport := &mockChatMessagesTransport{}
1278+
app, buf := newTestAppWithTransport(t, transport)
1279+
1280+
cmd := NewChatCmd()
1281+
// --limit 2: the mock returns 3 messages; only the 2 newest should appear
1282+
err := executeChatCommand(cmd, app, "messages", "--room", "789", "--in", "123", "--limit", "2")
1283+
require.NoError(t, err)
1284+
1285+
// Verify sort params were sent to the API
1286+
assert.Equal(t, "created_at", transport.capturedQuery["sort"])
1287+
assert.Equal(t, "desc", transport.capturedQuery["direction"])
1288+
1289+
// Verify limit is respected (2 of 3 returned) and output is chronological
1290+
var envelope struct {
1291+
Data []struct {
1292+
ID int64 `json:"id"`
1293+
} `json:"data"`
1294+
}
1295+
require.NoError(t, json.Unmarshal(buf.Bytes(), &envelope))
1296+
require.Len(t, envelope.Data, 2, "should return only 2 messages per --limit")
1297+
assert.Equal(t, int64(2), envelope.Data[0].ID, "first displayed should be older of the two")
1298+
assert.Equal(t, int64(3), envelope.Data[1].ID, "last displayed should be newest")
1299+
}

0 commit comments

Comments
 (0)