71691a5261
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
156 lines
6.8 KiB
EmacsLisp
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))))
|