|
7 | 7 | [eca.handlers :as handlers] |
8 | 8 | [eca.models :as models] |
9 | 9 | [eca.test-helper :as h] |
| 10 | + [matcher-combinators.matchers :as m] |
10 | 11 | [matcher-combinators.test :refer [match?]])) |
11 | 12 |
|
12 | 13 | (h/reset-components-before-test) |
|
259 | 260 | (is (match? {:config-updated [{:chat {:variants ["high" "medium"] |
260 | 261 | :select-variant "high"}}]} |
261 | 262 | (h/messages))))) |
| 263 | + |
| 264 | +(defn ^:private seed-chats! |
| 265 | + "Seed the test db with a map of chats keyed by id." |
| 266 | + [chats] |
| 267 | + (swap! (h/db*) assoc :chats chats)) |
| 268 | + |
| 269 | +(deftest chat-list-test |
| 270 | + (testing "Returns empty list when db has no chats" |
| 271 | + (h/reset-components!) |
| 272 | + (is (match? {:chats []} |
| 273 | + (handlers/chat-list (h/components) {})))) |
| 274 | + |
| 275 | + (testing "Returns summary of all non-subagent chats" |
| 276 | + (h/reset-components!) |
| 277 | + (seed-chats! |
| 278 | + {"a" {:id "a" :title "First" :status :idle |
| 279 | + :created-at 100 :updated-at 300 :model "anthropic/claude" |
| 280 | + :messages [{:role "user" :content "hi"} |
| 281 | + {:role "assistant" :content "hello"}]} |
| 282 | + "b" {:id "b" :title "Second" :status :idle |
| 283 | + :created-at 200 :updated-at 400 |
| 284 | + :messages []}}) |
| 285 | + (is (match? {:chats (m/in-any-order |
| 286 | + [{:id "b" :title "Second" :status :idle |
| 287 | + :created-at 200 :updated-at 400 :message-count 0} |
| 288 | + {:id "a" :title "First" :status :idle |
| 289 | + :created-at 100 :updated-at 300 |
| 290 | + :model "anthropic/claude" :message-count 2}])} |
| 291 | + (handlers/chat-list (h/components) {})))) |
| 292 | + |
| 293 | + (testing "Subagent chats are excluded" |
| 294 | + (h/reset-components!) |
| 295 | + (seed-chats! |
| 296 | + {"visible" {:id "visible" :title "Normal" :status :idle |
| 297 | + :created-at 100 :updated-at 100 :messages []} |
| 298 | + "hidden" {:id "hidden" :title "Sub" :status :idle |
| 299 | + :created-at 200 :updated-at 200 :messages [] |
| 300 | + :subagent true :parent-chat-id "visible"}}) |
| 301 | + (let [{:keys [chats]} (handlers/chat-list (h/components) {})] |
| 302 | + (is (= 1 (count chats))) |
| 303 | + (is (= "visible" (:id (first chats)))))) |
| 304 | + |
| 305 | + (testing "Sorted by :updated-at descending by default" |
| 306 | + (h/reset-components!) |
| 307 | + (seed-chats! |
| 308 | + {"old" {:id "old" :status :idle :created-at 10 :updated-at 100 :messages []} |
| 309 | + "mid" {:id "mid" :status :idle :created-at 20 :updated-at 200 :messages []} |
| 310 | + "new" {:id "new" :status :idle :created-at 30 :updated-at 300 :messages []}}) |
| 311 | + (is (= ["new" "mid" "old"] |
| 312 | + (mapv :id (:chats (handlers/chat-list (h/components) {})))))) |
| 313 | + |
| 314 | + (testing "`limit` caps the number of returned chats after sorting" |
| 315 | + (h/reset-components!) |
| 316 | + (seed-chats! |
| 317 | + {"a" {:id "a" :status :idle :created-at 10 :updated-at 100 :messages []} |
| 318 | + "b" {:id "b" :status :idle :created-at 20 :updated-at 200 :messages []} |
| 319 | + "c" {:id "c" :status :idle :created-at 30 :updated-at 300 :messages []}}) |
| 320 | + (is (= ["c" "b"] |
| 321 | + (mapv :id (:chats (handlers/chat-list (h/components) {:limit 2})))))) |
| 322 | + |
| 323 | + (testing "`sort-by :created-at` switches the sort key" |
| 324 | + (h/reset-components!) |
| 325 | + (seed-chats! |
| 326 | + {"x" {:id "x" :status :idle :created-at 30 :updated-at 100 :messages []} |
| 327 | + "y" {:id "y" :status :idle :created-at 20 :updated-at 200 :messages []} |
| 328 | + "z" {:id "z" :status :idle :created-at 10 :updated-at 300 :messages []}}) |
| 329 | + (is (= ["x" "y" "z"] |
| 330 | + (mapv :id (:chats (handlers/chat-list (h/components) |
| 331 | + {:sort-by :created-at}))))))) |
| 332 | + |
| 333 | +(deftest chat-open-test |
| 334 | + (testing "Unknown chat returns {:found? false} and emits no messages" |
| 335 | + (h/reset-components!) |
| 336 | + (is (match? {:found? false} |
| 337 | + (handlers/chat-open (h/components) {:chat-id "missing"}))) |
| 338 | + (is (nil? (:chat-opened (h/messages))))) |
| 339 | + |
| 340 | + (testing "Subagent chat is treated as not found" |
| 341 | + (h/reset-components!) |
| 342 | + (seed-chats! |
| 343 | + {"sub" {:id "sub" :status :idle :subagent true :parent-chat-id "main" |
| 344 | + :messages [] :created-at 1 :updated-at 1}}) |
| 345 | + (is (match? {:found? false} |
| 346 | + (handlers/chat-open (h/components) {:chat-id "sub"}))) |
| 347 | + (is (nil? (:chat-opened (h/messages))))) |
| 348 | + |
| 349 | + (testing "Known chat emits chat/cleared + chat/opened and returns found? true" |
| 350 | + (h/reset-components!) |
| 351 | + (seed-chats! |
| 352 | + {"c1" {:id "c1" :title "Hello world" :status :idle |
| 353 | + :created-at 10 :updated-at 20 |
| 354 | + :messages [{:role "user" :content [{:type :text :text "hi"}]}]}}) |
| 355 | + (let [result (handlers/chat-open (h/components) {:chat-id "c1"})] |
| 356 | + (is (match? {:found? true |
| 357 | + :chat-id "c1" |
| 358 | + :title "Hello world"} |
| 359 | + result)) |
| 360 | + (is (match? {:chat-clear [{:chat-id "c1" :messages true}] |
| 361 | + :chat-opened [{:chat-id "c1" :title "Hello world"}]} |
| 362 | + (h/messages)))))) |
0 commit comments