diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-pearl-saved-query-sync.el | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/tests/test-pearl-saved-query-sync.el b/tests/test-pearl-saved-query-sync.el index 8c98539..e237108 100644 --- a/tests/test-pearl-saved-query-sync.el +++ b/tests/test-pearl-saved-query-sync.el @@ -110,6 +110,60 @@ (< apple-pos mango-pos) (< mango-pos zebra-pos))))) +;;; pearl--sync-scope-label + +(ert-deftest test-pearl-sync-scope-label-personal-ignores-shared () + "Personal scope always renders the personal label regardless of SHARED. +A `Personal + shared' combination is meaningless on Linear (there's no +team to share with), so the label collapses to the only sensible +phrasing." + (should (equal "[ Personal, only I see it ]" + (pearl--sync-scope-label "Personal" nil))) + (should (equal "[ Personal, only I see it ]" + (pearl--sync-scope-label "Personal" t)))) + +(ert-deftest test-pearl-sync-scope-label-team-renders-shared-or-private () + "A team scope renders the shared or private variant per SHARED." + (should (equal "[ Team: Engineering, visible to the team ]" + (pearl--sync-scope-label "Engineering" t))) + (should (equal "[ Team: Engineering, only I see it ]" + (pearl--sync-scope-label "Engineering" nil)))) + +(ert-deftest test-pearl-sync-saved-query-pick-scope-returns-display-plist-pair () + "`pick-scope' returns the chosen candidate's (DISPLAY . PLIST) pair, not +just the plist. The caller uses the display string for the success +message without rebuilding the candidate list to look it up." + (cl-letf (((symbol-function 'pearl--all-teams) + (lambda () '(((id . "t1") (key . "ENG") (name . "Engineering"))))) + ((symbol-function 'completing-read) + (lambda (&rest _) "[ Team: Engineering, visible to the team ]"))) + (let ((pair (pearl--sync-saved-query-pick-scope '(:team "ENG")))) + (should (consp pair)) + (should (equal "[ Team: Engineering, visible to the team ]" + (car pair))) + (should (equal "t1" (plist-get (cdr pair) :team-id))) + (should (eq t (plist-get (cdr pair) :shared)))))) + +(ert-deftest test-pearl-sync-saved-query-pick-scope-returns-personal-pair () + "Picking the Personal row returns the personal pair: display = the personal +label, plist team-id nil + team-name \"Personal\" + shared nil." + (cl-letf (((symbol-function 'pearl--all-teams) (lambda () '())) + ((symbol-function 'completing-read) + (lambda (&rest _) "[ Personal, only I see it ]"))) + (let ((pair (pearl--sync-saved-query-pick-scope '()))) + (should (consp pair)) + (should (equal "[ Personal, only I see it ]" (car pair))) + (should (null (plist-get (cdr pair) :team-id))) + (should (equal "Personal" (plist-get (cdr pair) :team-name))) + (should (null (plist-get (cdr pair) :shared)))))) + +(ert-deftest test-pearl-sync-saved-query-pick-scope-returns-nil-on-cancel () + "Picking the cancel sentinel returns nil so the caller can short-circuit." + (cl-letf (((symbol-function 'pearl--all-teams) (lambda () '())) + ((symbol-function 'completing-read) + (lambda (&rest _) pearl--filter-cancel))) + (should (null (pearl--sync-saved-query-pick-scope '()))))) + ;;; pearl--find-view-by-name-in-scope (ert-deftest test-pearl-find-view-by-name-in-scope-matches-team-shared () @@ -418,16 +472,20 @@ erased on every re-sync." ;;; pearl-sync-saved-query-to-linear — empty filter refusal (ert-deftest test-pearl-sync-empty-filter-refuses-before-scope-prompt () - "A saved query whose filter compiles to nil signals a clear user-error -before any scope prompt fires. Without the guard, the sync would pass -filterData=null to Linear, which rejects with an opaque error after the + "A first-time-sync saved query whose filter compiles to nil signals a clear +user-error before any scope prompt fires. Without the guard, the sync would +pass filterData=null to Linear, which rejects with an opaque error after the user has already clicked through the scope picker." (let ((pearl-saved-queries (copy-tree '(("EmptyFilter" :filter nil)))) (scope-prompt-fired nil) (api-called nil)) (cl-letf (((symbol-function 'pearl--sync-saved-query-pick-scope) (lambda (&rest _) (setq scope-prompt-fired t) - (list :team-id nil :team-name "Personal" :shared nil))) + ;; Pick-scope returns (DISPLAY . PLIST); the empty-filter + ;; guard fires before this is consumed, but the stub + ;; shape should still match production. + (cons "[ Personal, only I see it ]" + (list :team-id nil :team-name "Personal" :shared nil)))) ((symbol-function 'pearl--customview-create-async) (lambda (&rest _) (setq api-called t)))) (should-error (pearl-sync-saved-query-to-linear "EmptyFilter") @@ -435,6 +493,23 @@ user has already clicked through the scope picker." (should-not scope-prompt-fired) (should-not api-called)))) +(ert-deftest test-pearl-sync-empty-filter-refuses-resync-too () + "A re-sync (entry already has `:linear-view-id') whose filter has been +edited down to nil takes the same empty-filter guard, refusing without +calling customViewUpdate. Guards against a future refactor accidentally +hoisting the guard into the create-only branch." + (let ((pearl-saved-queries + (copy-tree '(("EmptyFilter" :filter nil + :linear-view-id "existing-view-uuid" + :linear-view-team-id nil + :linear-view-shared :json-false)))) + (update-called nil)) + (cl-letf (((symbol-function 'pearl--customview-update-async) + (lambda (&rest _) (setq update-called t)))) + (should-error (pearl-sync-saved-query-to-linear "EmptyFilter") + :type 'user-error) + (should-not update-called)))) + ;;; pearl-publish-current-source (defmacro test-pearl-publish--in-buffer (source-form &rest body) |
