aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-capture-config-popup-window.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-org-capture-config-popup-window.el')
-rw-r--r--tests/test-org-capture-config-popup-window.el195
1 files changed, 195 insertions, 0 deletions
diff --git a/tests/test-org-capture-config-popup-window.el b/tests/test-org-capture-config-popup-window.el
new file mode 100644
index 000000000..671d55ab9
--- /dev/null
+++ b/tests/test-org-capture-config-popup-window.el
@@ -0,0 +1,195 @@
+;;; test-org-capture-config-popup-window.el --- Quick-capture popup tests -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the Hyprland Super+Shift+N quick-capture popup. The popup opens an
+;; emacsclient frame named "org-capture" and runs `cj/quick-capture', which
+;; captures a single Task into the global inbox with no template menu. Covered
+;; here: the sole-window predicate and display action (the CAPTURE-* buffer
+;; fills the frame), the single-Task template builder, frame discovery and focus
+;; (the emacsclient focus race), and frame cleanup on every exit path.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'org)
+(require 'org-capture) ; makes `org-capture-templates' a real special var
+(require 'user-constants)
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'org-capture-config)
+
+;;; cj/org-capture--popup-sole-window-p
+
+(ert-deftest test-org-capture-config-popup-sole-window-p-select-menu ()
+ "Normal: the *Org Select* menu in the popup frame wants the sole window."
+ (should (cj/org-capture--popup-sole-window-p "org-capture" "*Org Select*")))
+
+(ert-deftest test-org-capture-config-popup-sole-window-p-capture-buffer ()
+ "Normal: a CAPTURE-* buffer in the popup frame wants the sole window."
+ (should (cj/org-capture--popup-sole-window-p "org-capture" "CAPTURE-todo.org")))
+
+(ert-deftest test-org-capture-config-popup-sole-window-p-capture-prefix-only ()
+ "Boundary: the bare \"CAPTURE-\" prefix still matches."
+ (should (cj/org-capture--popup-sole-window-p "org-capture" "CAPTURE-")))
+
+(ert-deftest test-org-capture-config-popup-sole-window-p-other-frame ()
+ "Boundary: the same menu in a normal frame is left alone."
+ (should-not (cj/org-capture--popup-sole-window-p "emacs" "*Org Select*"))
+ (should-not (cj/org-capture--popup-sole-window-p nil "CAPTURE-todo.org")))
+
+(ert-deftest test-org-capture-config-popup-sole-window-p-other-buffer ()
+ "Boundary: an unrelated buffer in the popup frame is left alone."
+ (should-not (cj/org-capture--popup-sole-window-p "org-capture" "todo.org"))
+ (should-not (cj/org-capture--popup-sole-window-p "org-capture" "*scratch*")))
+
+(ert-deftest test-org-capture-config-popup-sole-window-p-nil-buffer ()
+ "Error: a nil or non-string buffer name returns nil without raising."
+ (should-not (cj/org-capture--popup-sole-window-p "org-capture" nil))
+ (should-not (cj/org-capture--popup-sole-window-p "org-capture" 42)))
+
+;;; Integration: the display-buffer-alist entry routes to a sole window
+
+(ert-deftest test-integration-org-capture-popup-display-sole-window ()
+ "Integration: in an \"org-capture\"-named frame, displaying a CAPTURE-*
+buffer fills the frame's sole window via the registered display-buffer-alist
+entry, instead of splitting.
+
+Components integrated:
+- cj/org-capture--popup-display-condition (real)
+- cj/org-capture--display-sole-window (real)
+- display-buffer / display-buffer-alist (real)
+
+Validates the popup frame ends with one window showing the CAPTURE buffer."
+ (let ((buf (get-buffer-create "CAPTURE-itest")))
+ (unwind-protect
+ (progn
+ (set-frame-parameter nil 'name "org-capture")
+ (delete-other-windows)
+ (display-buffer buf)
+ (should (= (length (window-list)) 1))
+ (should (eq (window-buffer (selected-window)) buf)))
+ (set-frame-parameter nil 'name nil)
+ (when (buffer-live-p buf) (kill-buffer buf)))))
+
+;;; cj/--quick-capture-template (single Task into the inbox)
+
+(ert-deftest test-org-capture-config-quick-capture-template ()
+ "Normal: the quick-capture template is a single Task into INBOX's Inbox."
+ (let* ((tmpl (cj/--quick-capture-template "/inbox.org"))
+ (task (assoc "t" tmpl)))
+ (should (equal (mapcar #'car tmpl) '("t")))
+ (should (equal (nth 1 task) "Task"))
+ (should (eq (nth 2 task) 'entry))
+ (should (equal (nth 3 task) '(file+headline "/inbox.org" "Inbox")))
+ (should (equal (nth 4 task) "* TODO %?"))
+ (should (memq :prepend task))))
+
+;;; cj/quick-capture (single Task; stubbed org-capture)
+
+(ert-deftest test-integration-org-capture-quick-capture-binds-task-only ()
+ "Integration: cj/quick-capture runs org-capture with a single Task template
+targeting the inbox, dispatched by key.
+
+Components integrated:
+- cj/quick-capture (real)
+- cj/--quick-capture-template (real)
+- org-capture (MOCKED — records the bound templates and dispatch key)"
+ (let (captured key)
+ (cl-letf (((symbol-function 'org-capture)
+ (lambda (&optional _goto k) (setq captured org-capture-templates key k))))
+ (cj/quick-capture))
+ (should (equal (mapcar #'car captured) '("t")))
+ (should (equal (nth 3 (assoc "t" captured)) (list 'file+headline inbox-file "Inbox")))
+ (should (equal (nth 4 (assoc "t" captured)) "* TODO %?"))
+ (should (equal key "t"))))
+
+(ert-deftest test-integration-org-capture-quick-capture-closes-frame-on-abort ()
+ "Integration: when capture aborts (org-capture signals), cj/quick-capture
+deletes the popup frame instead of leaving it orphaned.
+
+Components integrated:
+- cj/quick-capture (real)
+- org-capture (MOCKED — signals user-error \"Abort\")
+- cj/org-capture--delete-popup-frame (MOCKED — records the call)"
+ (let ((deleted 0))
+ (cl-letf (((symbol-function 'org-capture)
+ (lambda (&rest _) (user-error "Abort")))
+ ((symbol-function 'cj/org-capture--delete-popup-frame)
+ (lambda () (cl-incf deleted))))
+ (cj/quick-capture))
+ (should (= deleted 1))))
+
+(ert-deftest test-integration-org-capture-quick-capture-closes-frame-on-quit ()
+ "Integration: a C-g (quit) during capture also closes the popup frame."
+ (let ((deleted 0))
+ (cl-letf (((symbol-function 'org-capture)
+ (lambda (&rest _) (signal 'quit nil)))
+ ((symbol-function 'cj/org-capture--delete-popup-frame)
+ (lambda () (cl-incf deleted))))
+ (cj/quick-capture))
+ (should (= deleted 1))))
+
+(ert-deftest test-integration-org-capture-quick-capture-keeps-frame-on-success ()
+ "Integration: a successful capture (no signal) does NOT delete the frame —
+the finalize hook owns that."
+ (let ((deleted 0))
+ (cl-letf (((symbol-function 'org-capture) (lambda (&rest _) nil))
+ ((symbol-function 'cj/org-capture--delete-popup-frame)
+ (lambda () (cl-incf deleted))))
+ (cj/quick-capture))
+ (should (= deleted 0))))
+
+;;; cj/org-capture--popup-frame-p
+
+(ert-deftest test-org-capture-config-popup-frame-p ()
+ "Normal/Boundary: true only when the selected frame is named \"org-capture\"."
+ (cl-letf (((symbol-function 'frame-parameter) (lambda (&rest _) "org-capture")))
+ (should (cj/org-capture--popup-frame-p)))
+ (cl-letf (((symbol-function 'frame-parameter) (lambda (&rest _) "emacs")))
+ (should-not (cj/org-capture--popup-frame-p))))
+
+;;; cj/org-capture--popup-frame (find the popup frame by name)
+
+(ert-deftest test-org-capture-config-popup-frame-found ()
+ "Normal: returns the live frame whose name is \"org-capture\"."
+ (cl-letf (((symbol-function 'frame-list) (lambda () '(fa fb fc)))
+ ((symbol-function 'frame-live-p) (lambda (_f) t))
+ ((symbol-function 'frame-parameter)
+ (lambda (f _p) (if (eq f 'fb) "org-capture" "other"))))
+ (should (eq (cj/org-capture--popup-frame) 'fb))))
+
+(ert-deftest test-org-capture-config-popup-frame-none ()
+ "Boundary: no popup frame present yields nil."
+ (cl-letf (((symbol-function 'frame-list) (lambda () '(fa fc)))
+ ((symbol-function 'frame-live-p) (lambda (_f) t))
+ ((symbol-function 'frame-parameter) (lambda (_f _p) "other")))
+ (should-not (cj/org-capture--popup-frame))))
+
+;;; cj/quick-capture targets the popup frame
+
+(ert-deftest test-integration-org-capture-quick-capture-selects-named-frame ()
+ "Integration: cj/quick-capture selects the \"org-capture\" frame found by name,
+not whatever frame happens to be selected (the emacsclient -c focus race)."
+ (let ((focused nil))
+ (cl-letf (((symbol-function 'cj/org-capture--popup-frame) (lambda () 'popup-frame))
+ ((symbol-function 'select-frame-set-input-focus)
+ (lambda (f &rest _) (setq focused f)))
+ ((symbol-function 'org-capture) (lambda (&rest _) nil)))
+ (cj/quick-capture))
+ (should (eq focused 'popup-frame))))
+
+(ert-deftest test-integration-org-capture-quick-capture-no-frame-still-captures ()
+ "Integration: when no popup frame is found, cj/quick-capture skips the focus
+call and still runs the capture (no error)."
+ (let ((focused 'unset)
+ (captured nil))
+ (cl-letf (((symbol-function 'cj/org-capture--popup-frame) (lambda () nil))
+ ((symbol-function 'select-frame-set-input-focus)
+ (lambda (f &rest _) (setq focused f)))
+ ((symbol-function 'org-capture) (lambda (&rest _) (setq captured t))))
+ (cj/quick-capture))
+ (should (eq focused 'unset))
+ (should captured)))
+
+(provide 'test-org-capture-config-popup-window)
+;;; test-org-capture-config-popup-window.el ends here