Files
noise/test/noise-conversation-test.el
jbrechtel 71691a5261 ui: align chat list and conversation buffer with mockups
Chat list (*signal*):
- Fringe ● now uses warning face (yellow), matching mockup's
  unread indicator color
- Modeline trailing dashes extended for visual balance

Conversation buffer (*signal:NAME*):
- Compose prompt > changed from bold to link face (blue),
  matching mockup's signal-blue prompt
- Attachment rendering: [attachment: ...] → [photo: ...]
- Modeline: (Signal Chat) → (Signal Chat Fill)
- Added header-line with key hints (RET send, M-RET newline,
  C-c C-g refresh), matching mockup's discoverability goal
2026-06-14 13:00:29 -04:00

156 lines
6.8 KiB
EmacsLisp

;;; noise-conversation-test.el --- Tests for noise-conversation -*- lexical-binding: t; -*-
(require 'ert)
(require 'noise-conversation)
(defvar noise-conversation-test--db
(expand-file-name "noise-conversation-test.db" temporary-file-directory))
(defmacro noise-conversation-test--with-db (&rest body)
"Run BODY with a fresh test database and clean up conversation buffers."
`(let ((noise-db-file noise-conversation-test--db))
(unwind-protect
(progn
(when (file-exists-p noise-db-file)
(delete-file noise-db-file))
(noise-db-init)
,@body)
(noise-db--close)
(when (file-exists-p noise-conversation-test--db)
(delete-file noise-conversation-test--db))
(dolist (buf (buffer-list))
(when (string-prefix-p "*signal:" (buffer-name buf))
(kill-buffer buf))))))
(defun noise-conversation-test--seed ()
"Insert a direct conversation with Sarah and two messages."
(noise-db-upsert-contact "+1" :name "Sarah")
(noise-db-upsert-conversation "+1" :type "direct" :name "Sarah"
:members '("+1"))
(noise-db-insert-message "+1" :timestamp 1717930000.0
:source "Sarah" :body "are you coming?")
(noise-db-insert-message "+1" :timestamp 1717930100.0
:source "me" :body "yes, leaving now"
:receipt-state "delivered"))
(ert-deftest noise-conversation-open-renders-history ()
"Opening a conversation renders messages, a day separator, and the prompt."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(with-current-buffer (noise-conversation-open "+1")
(let ((text (buffer-substring-no-properties (point-min) (point-max))))
(should (string-match-p "Sarah> are you coming\\?" text))
(should (string-match-p "me> yes, leaving now" text))
;; day separator present
(should (string-match-p "─── .* ───" text))
;; delivered receipt
(should (string-match-p "✓✓" text))
;; compose prompt at the bottom
(should (string-match-p "^> " text))))))
(ert-deftest noise-conversation-open-marks-read ()
"Opening a conversation resets its unread count."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(noise-db-upsert-conversation "+1" :unread-count 4)
(noise-conversation-open "+1")
(should (= 0 (gethash "unread_count" (noise-db-get-conversation "+1"))))))
(ert-deftest noise-conversation-history-is-read-only ()
"Typing into the history region should fail; the prompt is editable."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(with-current-buffer (noise-conversation-open "+1")
(goto-char (point-min))
(should-error (insert "x"))
(goto-char (point-max))
(insert "hello")
(should (string= "hello" (noise-conversation--current-input))))))
(ert-deftest noise-conversation-send-stores-and-clears ()
"Sending stores the message with the server timestamp and clears input."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(with-current-buffer (noise-conversation-open "+1")
(goto-char (point-max))
(insert "on my way")
(let (sent-params)
(cl-letf (((symbol-function 'noise-rpc-call-for-account)
(lambda (method &rest params)
(should (string= "send" method))
(setq sent-params params)
(let ((ht (make-hash-table :test 'equal)))
(puthash "timestamp" 1717930200123 ht)
ht))))
(noise-conversation-send))
(should (equal ["+1"] (plist-get sent-params :recipient)))
(should (string= "on my way" (plist-get sent-params :message))))
;; input cleared, message rendered
(should (string= "" (noise-conversation--current-input)))
(let ((msgs (noise-db-get-messages "+1")))
(should (= 3 (length msgs)))
(let ((last (car (last msgs))))
(should (string= "me" (gethash "source" last)))
(should (string= "on my way" (gethash "body" last)))
(should (string= "sent" (gethash "receipt_state" last)))
(should (= 1717930200.123 (gethash "timestamp" last))))))))
(ert-deftest noise-conversation-send-group-uses-group-id ()
"Sending in a group conversation uses the groupId parameter."
(noise-conversation-test--with-db
(noise-db-upsert-conversation "grp1" :type "group" :name "cycling crew")
(with-current-buffer (noise-conversation-open "grp1")
(goto-char (point-max))
(insert "saturday 7am?")
(let (sent-params)
(cl-letf (((symbol-function 'noise-rpc-call-for-account)
(lambda (_method &rest params)
(setq sent-params params)
nil)))
(noise-conversation-send))
(should (string= "grp1" (plist-get sent-params :groupId)))
(should-not (plist-get sent-params :recipient))))))
(ert-deftest noise-conversation-send-empty-does-nothing ()
"Sending with no input should not call signal-cli."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(with-current-buffer (noise-conversation-open "+1")
(cl-letf (((symbol-function 'noise-rpc-call-for-account)
(lambda (&rest _) (error "Should not be called"))))
(noise-conversation-send))
(should (= 2 (length (noise-db-get-messages "+1")))))))
(ert-deftest noise-conversation-render-preserves-input ()
"Re-rendering keeps text already typed at the prompt."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(with-current-buffer (noise-conversation-open "+1")
(goto-char (point-max))
(insert "draft text")
(noise-conversation--render)
(should (string= "draft text" (noise-conversation--current-input))))))
(ert-deftest noise-conversation-format-attachment ()
"Attachment messages render the [photo: ...] hint."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(noise-db-insert-message "+1" :timestamp 1717930300.0
:source "Sarah" :body ""
:has-attachment t
:attachment-path "IMG_2041.jpg")
(with-current-buffer (noise-conversation-open "+1")
(should (string-match-p "\\[photo: IMG_2041\\.jpg — RET to view\\]"
(buffer-string))))))
(ert-deftest noise-conversation-typing-indicator ()
"Typing STARTED/STOPPED toggles the modeline indicator."
(noise-conversation-test--with-db
(noise-conversation-test--seed)
(with-current-buffer (noise-conversation-open "+1")
(noise-conversation-set-typing "+1" "Sarah" "STARTED")
(should (string= "Sarah" noise-conversation--typing))
(should (string-match-p "Sarah is typing…" mode-line-format))
(noise-conversation-set-typing "+1" "Sarah" "STOPPED")
(should-not noise-conversation--typing))))