Files
Synapse/clj-e2e/test/logseq/e2e/cmdk_scroll_basic_test.clj
Dasemu 40631362b3 Initial import of LogDarioSeq baseline
Establishes version control for the personal Logseq DB fork before
starting the server-client architecture migration and domain features
described in docs/agent-guide and the approved implementation plan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 15:32:15 +02:00

164 lines
6.8 KiB
Clojure
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(ns logseq.e2e.cmdk-scroll-basic-test
"E2E tests for Cmd+K scroll & highlight behavior."
(:require
[clojure.test :refer [deftest testing is use-fixtures]]
[logseq.e2e.fixtures :as fixtures]
[logseq.e2e.keyboard :as k]
[logseq.e2e.page :as p]
[logseq.e2e.util :as util]
[wally.main :as w]))
(use-fixtures :once fixtures/open-page)
(use-fixtures :each fixtures/new-logseq-page fixtures/validate-graph)
(def ^:private scroll-container ".cp__cmdk .overflow-y-auto")
(def ^:private kbd-highlight (str scroll-container " [data-kb-highlighted]"))
(def ^:private mouse-item (str scroll-container " .transition-colors.cursor-pointer"))
(defn- setup-search
"Creates `n` pages with `prefix` and `suffix`, opens cmdk and types the `prefix`."
([prefix n] (setup-search prefix n ""))
([prefix n suffix]
[prefix n suffix]
(dotimes [i n] (p/new-page (str prefix i suffix)))
(util/search prefix)
(util/wait-timeout 500)))
(defn- simulate-mouse-move-into-results!
"Dispatches a synthetic mousemove with non-zero movementX/Y on a result item.
Playwright's CDP mouse.move does not populate movementX/Y, so we must
construct the event in JS and patch those read-only fields."
[]
(w/eval-js
(str "(() => {
const c = document.querySelector('" scroll-container "');
if (!c) return;
const items = c.querySelectorAll('.transition-colors');
const target = items[2] || items[0] || c;
const rect = target.getBoundingClientRect();
const evt = new MouseEvent('mousemove', {
bubbles: true, cancelable: true,
clientX: rect.x + rect.width / 2,
clientY: rect.y + rect.height / 2
});
Object.defineProperty(evt, 'movementX', {value: 5});
Object.defineProperty(evt, 'movementY', {value: 3});
target.dispatchEvent(evt);
})()")))
(defn- kbd-highlight-in-viewport?
"Returns true when the keyboard-highlighted element is fully within
the visible scroll area. Allows ±5 px tolerance for borders/padding."
[]
(w/eval-js
(str "(() => {
const el = document.querySelector('" kbd-highlight "');
if (!el) return false;
const c = document.querySelector('" scroll-container "');
const cr = c.getBoundingClientRect();
const er = el.getBoundingClientRect();
return er.top >= cr.top - 5 && er.bottom <= cr.bottom + 5;
})()")))
(deftest cmdk-keeps-results-visible-while-searching
(testing "typing and deleting do not clear the visible results before the debounced search finishes"
(let [prefix (str "cmdkflicker" (random-uuid))
result-selector (format "[data-testid^='%s']" prefix)]
(setup-search prefix 2 "a")
(let [result-count (util/count-elements result-selector)]
(is (pos? result-count) "initial search results are visible")
(util/press-seq "a")
(is (= result-count (util/count-elements result-selector))
"typing keeps the previous results visible")
(util/wait-timeout 400)
(is (= result-count (util/count-elements result-selector))
"matching results remain visible after search settles")
(k/press "Backspace")
(is (= result-count (util/count-elements result-selector))
"deleting keeps the previous results visible")
(util/wait-timeout 400)
(is (= result-count (util/count-elements result-selector))
"matching results remain visible after deletion search settles")))))
;; ---------------------------------------------------------------------------
;; Highlight mode switching
;;
;; Cycles keyboard → mouse → keyboard → mouse and verifies:
;; • keyboard mode: [data-kb-highlighted] = 1, mouse-item count = 0
;; • mouse mode: [data-kb-highlighted] = 0, mouse-item count > 0
;; ---------------------------------------------------------------------------
(deftest cmdk-highlight-mode-switching
(testing "keyboard & mouse highlight mode toggles correctly"
(setup-search "cmdkhighlight" 8)
(dotimes [_ 3] (k/arrow-down))
(util/wait-timeout 100)
(is (= 1 (util/count-elements kbd-highlight))
"keyboard mode → keyboard-highlight = 1")
(is (= 0 (util/count-elements mouse-item))
"keyboard mode → mouse-mode items = 0")
(simulate-mouse-move-into-results!)
(util/wait-timeout 200)
(is (= 0 (util/count-elements kbd-highlight))
"mouse mode → keyboard-highlight = 0")
(is (pos? (util/count-elements mouse-item))
"mouse mode → mouse-mode items > 0")
(k/arrow-down)
(util/wait-timeout 100)
(is (= 1 (util/count-elements kbd-highlight))
"keyboard mode again → keyboard-highlight = 1")
(is (= 0 (util/count-elements mouse-item))
"keyboard mode again → mouse-mode items = 0")
(simulate-mouse-move-into-results!)
(util/wait-timeout 200)
(is (= 0 (util/count-elements kbd-highlight))
"mouse mode again → keyboard-highlight = 0")
(is (pos? (util/count-elements mouse-item))
"mouse mode again → mouse-mode items > 0")))
;; ---------------------------------------------------------------------------
;; Lazy-visible keyboard scroll verification
;;
;; Goal:
;; Verify that keyboard navigation scrolls correctly through :nodes items
;; that are wrapped in lazy-visible (always active for :nodes group).
;; This exercises the data-item-index wrapper-div DOM query path in
;; move-highlight, which finds the wrapper even when the inner list-item
;; has not yet been mounted by IntersectionObserver.
;;
;; Layout:
;; viewport_height = 65dvh × 720 px (Playwright default) = 468 px
;; item_height ≈ 32 px, group_header = 32 px
;; Create (32) + nodes header (32) + 30 nodes items (30 × 32 = 960)
;; = 1024 px total — significantly exceeds viewport
;; Navigating 20 items → top ≈ 32 + 32 + 20×32 = 704 px
;; → far below viewport bottom (468 px), deep into lazy territory
;; ---------------------------------------------------------------------------
(deftest cmdk-lazy-visible-keyboard-scroll
(testing "keyboard navigation scrolls through lazy-visible :nodes items"
(setup-search "cmdklazy" 30)
;; Expand :nodes group — sets :show :more.
(k/arrow-down)
(util/wait-timeout 100)
(k/press "ControlOrMeta+ArrowDown")
(util/wait-timeout 300)
;; Navigate down 20 steps — well past the viewport into lazy items.
(k/press (vec (repeat 20 "ArrowDown")) {:delay 30})
(util/wait-timeout 300)
;; Verify keyboard highlight exists.
(is (= 1 (util/count-elements kbd-highlight))
"keyboard highlight present after navigating through lazy items")
;; Verify the highlighted element is within the visible scroll area.
(is (kbd-highlight-in-viewport?) "highlight is in viewport after navigating through lazy-visible items")))