diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e90f4ca..0663ea002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ ### Bugs fixed +- Fix `cider-log-kill-appender`'s confirmation message, which had the appender and framework names swapped. - [#4066](https://github.com/clojure-emacs/cider/pull/4066): Jump to the actual source when clicking a stack frame for a top-level anonymous function (the `deftest` shape), instead of landing in `clojure.core/fn` ([#3157](https://github.com/clojure-emacs/cider/issues/3157)). - [#4058](https://github.com/clojure-emacs/cider/pull/4058): Signal a helpful error when `cider-javadoc` gets an unresolvable (non-absolute) Javadoc URL from the middleware, instead of silently doing nothing ([#2969](https://github.com/clojure-emacs/cider/issues/2969)). - [#4054](https://github.com/clojure-emacs/cider/pull/4054): Interrupt every REPL an evaluation is dispatched to. In a `.cljc` buffer `cider-interrupt` previously interrupted only one of the two REPLs ([#4036](https://github.com/clojure-emacs/cider/issues/4036)). @@ -64,6 +65,7 @@ - Bump the injected `cider-nrepl` to 0.62.0-alpha2, which carries the hardened content-type/slurp middleware backing the rich-content revival below (and no longer double-sends `value` alongside content-typed responses). - Enable rich content in the REPL by default (`cider-repl-use-content-types` is now t): image results render inline, and results naming external content (files, URLs) render a `[show content]` button that fetches and renders it on demand. The automatic fetching that got the feature disabled back in 0.25 ([#2825](https://github.com/clojure-emacs/cider/issues/2825)) is gone - nothing is transferred until the button is pressed - and the server side is hardened in `cider-nrepl` 0.62 (URL-scheme allowlist, size caps, graceful fetch errors). +- Rename `cider-log-buffer-clear-p` to `cider-log-buffer-has-content-p` - the old name read as the opposite of its behavior; it remains as an obsolete alias. - Bump the default `cider-repl-history-size` from 500 to 5000. - Rename the REPL history browser from `cider-repl-history` to `cider-history` (command, mode and options), so its names no longer clash with the REPL's unrelated input-history settings (`cider-repl-history-file`, `cider-repl-history-size`); the old names keep working as obsolete aliases. - Color the nREPL messages buffer with theme-aware faces (`nrepl-message-faces`, eight faces inheriting from standard font-lock faces) instead of a hardcoded color list; `nrepl-message-colors` is now obsolete, but still takes precedence when customized. diff --git a/lisp/cider-log.el b/lisp/cider-log.el index af3325c77..34f45a011 100644 --- a/lisp/cider-log.el +++ b/lisp/cider-log.el @@ -161,10 +161,11 @@ It will not be used if the package hasn't been installed." "Return S with a bold face." (when s (propertize (format "%s" s) 'face 'bold))) -(defun cider-log-buffer-clear-p (&optional buffer) +(defun cider-log-buffer-has-content-p (&optional buffer) "Return non-nil if BUFFER is not empty, otherwise nil." (when-let* ((buffer (get-buffer (or buffer cider-log-buffer)))) (> (buffer-size buffer) 0))) +(define-obsolete-function-alias 'cider-log-buffer-clear-p 'cider-log-buffer-has-content-p "2.0.0") (defun cider-log--description-clear-events-buffer () "Return the description for the clear-events-buffer action." @@ -221,7 +222,7 @@ It will not be used if the package hasn't been installed." (cider-nrepl-send-request callback))) (defun cider-sync-request:log-update-consumer (framework appender consumer) - "Add CONSUMER to the APPENDER of FRAMEWORK and call CALLBACK on log events." + "Update CONSUMER of the APPENDER of FRAMEWORK." (thread-first `("op" "cider/log-update-consumer" "framework" ,(cider-log-framework-id framework) "appender" ,(cider-log-appender-id appender) @@ -769,7 +770,7 @@ The KEYS are used to lookup the values and are joined by SEPARATOR." consumer)) (defun cider-log--event-options () - "Return the current log consumer." + "Return the filter and pagination options for a log event search." (nrepl-dict "filters" (cider-log--filters) "limit" cider-log-pagination-limit "offset" cider-log-pagination-offset)) @@ -1086,8 +1087,8 @@ the CIDER Inspector and the CIDER stacktrace mode. (cider-sync-request:log-remove-appender framework appender) (setq-local cider-log-consumer nil) (message "Log appender %s removed from the %s framework." - (cider-log-framework-display-name framework) - (cider-log-appender-display-name appender))) + (cider-log-appender-display-name appender) + (cider-log-framework-display-name framework))) (transient-define-suffix cider-log--do-add-appender (framework appender) "Add the APPENDER to the log FRAMEWORK." @@ -1173,7 +1174,7 @@ You can jump to functions and methods directly from the printed stacktrace now." (transient-define-suffix cider-log-clear-event-buffer (buffer) "Clear the Cider log events in BUFFER." :description #'cider-log--description-clear-events-buffer - :inapt-if-not #'cider-log-buffer-clear-p + :inapt-if-not #'cider-log-buffer-has-content-p (interactive (list cider-log-buffer)) (when (get-buffer buffer) (with-current-buffer buffer diff --git a/test/cider-log-tests.el b/test/cider-log-tests.el index d38c8db0a..58387ec5f 100644 --- a/test/cider-log-tests.el +++ b/test/cider-log-tests.el @@ -139,3 +139,321 @@ (expect (nrepl-dict-get filters "level") :to-equal "INFO") (expect (nrepl-dict-get filters "pattern") :to-equal "foo") (expect (nrepl-dict-get filters "threads") :to-be nil))))) + +(describe "cider-log--set-filters" + (it "sets the filter variables from the filters dict" + (let (cider-log--end-time-filter + cider-log--exceptions-filter + cider-log--level-filter + cider-log--loggers-filter + cider-log--pattern-filter + cider-log--start-time-filter + cider-log--threads-filter) + (cider-log--set-filters (nrepl-dict "level" "INFO" + "pattern" "foo" + "threads" '("main"))) + (expect cider-log--level-filter :to-equal "INFO") + (expect cider-log--pattern-filter :to-equal "foo") + (expect cider-log--threads-filter :to-equal '("main")) + (expect cider-log--loggers-filter :to-be nil))) + + (it "leaves the filter variables alone when the filters are nil" + (let ((cider-log--level-filter "WARN")) + (cider-log--set-filters nil) + (expect cider-log--level-filter :to-equal "WARN")))) + +(describe "cider-log--bold" + (it "returns nil for nil" + (expect (cider-log--bold nil) :to-be nil)) + (it "renders any value with a bold face" + (let ((s (cider-log--bold 42))) + (expect (substring-no-properties s) :to-equal "42") + (expect (get-text-property 0 'face s) :to-equal 'bold)))) + +(describe "cider-log-buffer-has-content-p" + (it "returns nil when the buffer doesn't exist" + (expect (cider-log-buffer-has-content-p "*cider-log-tests-no-such-buffer*") + :to-be nil)) + (it "returns nil for an empty buffer and non-nil once it has content" + (with-temp-buffer + (expect (cider-log-buffer-has-content-p (current-buffer)) :to-be nil) + (insert "an event") + (expect (cider-log-buffer-has-content-p (current-buffer)) :to-be-truthy)))) + +(describe "cider-log transient descriptions" + (it "shows the current framework name, or n/a" + (let ((cider-log-framework-name "Logback")) + (expect (substring-no-properties (cider-log--description-set-framework)) + :to-equal "Select framework Logback")) + (let ((cider-log-framework-name nil)) + (expect (substring-no-properties (cider-log--description-set-framework)) + :to-equal "Select framework n/a"))) + (it "shows the current log buffer, or n/a" + (let ((cider-log-buffer "*cider-log*")) + (expect (substring-no-properties (cider-log--description-set-buffer)) + :to-equal "Select buffer *cider-log*")) + (let ((cider-log-buffer nil)) + (expect (substring-no-properties (cider-log--description-set-buffer)) + :to-equal "Select buffer n/a"))) + (it "describes clearing the current log buffer" + (let ((cider-log-buffer "*cider-log*")) + (expect (substring-no-properties (cider-log--description-clear-events-buffer)) + :to-equal "Clear *cider-log* buffer")))) + +(defun cider-log-tests--request-get (request key) + "Return the value following KEY in the nREPL REQUEST list." + (cadr (member key request))) + +(describe "cider-log nREPL request construction" + :var (framework appender event) + (before-each + (setq framework (nrepl-dict "id" "logback" "name" "Logback") + appender (nrepl-dict "id" "my-appender" + "filters" (nrepl-dict "level" "INFO") + "size" 100 + "threshold" 10) + event (nrepl-dict "id" "ev-42"))) + + (it "cider-sync-request:log-add-appender sends the appender settings" + (spy-on 'cider-nrepl-sync-request + :and-return-value (nrepl-dict "cider/log-add-appender" appender)) + (expect (cider-sync-request:log-add-appender framework appender) + :to-equal appender) + (let ((request (car (spy-calls-args-for 'cider-nrepl-sync-request 0)))) + (expect (cider-log-tests--request-get request "op") + :to-equal "cider/log-add-appender") + (expect (cider-log-tests--request-get request "framework") :to-equal "logback") + (expect (cider-log-tests--request-get request "appender") :to-equal "my-appender") + (expect (cider-log-tests--request-get request "size") :to-equal 100) + (expect (cider-log-tests--request-get request "threshold") :to-equal 10) + (expect (nrepl-dict-get (cider-log-tests--request-get request "filters") "level") + :to-equal "INFO"))) + + (it "cider-sync-request:log-clear sends the clear-appender op" + (spy-on 'cider-nrepl-sync-request :and-return-value (nrepl-dict)) + (cider-sync-request:log-clear framework appender) + (let ((request (car (spy-calls-args-for 'cider-nrepl-sync-request 0)))) + (expect (cider-log-tests--request-get request "op") + :to-equal "cider/log-clear-appender") + (expect (cider-log-tests--request-get request "framework") :to-equal "logback") + (expect (cider-log-tests--request-get request "appender") :to-equal "my-appender"))) + + (it "cider-sync-request:log-search sends the filters and pagination" + (spy-on 'cider-nrepl-sync-request + :and-return-value (nrepl-dict "cider/log-search" (list event))) + (let ((filters (nrepl-dict "pattern" "foo"))) + (expect (cider-sync-request:log-search framework appender + :filters filters :limit 25 :offset 5) + :to-equal (list event)) + (let ((request (car (spy-calls-args-for 'cider-nrepl-sync-request 0)))) + (expect (cider-log-tests--request-get request "op") + :to-equal "cider/log-search") + (expect (cider-log-tests--request-get request "filters") :to-equal filters) + (expect (cider-log-tests--request-get request "limit") :to-equal 25) + (expect (cider-log-tests--request-get request "offset") :to-equal 5)))) + + (it "cider-sync-request:log-inspect-event asks for the event by id" + (spy-on 'cider-nrepl-sync-request + :and-return-value (nrepl-dict "value" "inspected")) + (expect (cider-sync-request:log-inspect-event framework appender event) + :to-equal "inspected") + (let ((request (car (spy-calls-args-for 'cider-nrepl-sync-request 0)))) + (expect (cider-log-tests--request-get request "op") + :to-equal "cider/log-inspect-event") + (expect (cider-log-tests--request-get request "event") :to-equal "ev-42"))) + + (it "cider-sync-request:log-format-event includes the print options" + (spy-on 'cider-nrepl-sync-request + :and-return-value (nrepl-dict "cider/log-format-event" "formatted")) + (expect (cider-sync-request:log-format-event framework appender event) + :to-equal "formatted") + (let ((request (car (spy-calls-args-for 'cider-nrepl-sync-request 0)))) + (expect (cider-log-tests--request-get request "op") + :to-equal "cider/log-format-event") + (expect (cider-log-tests--request-get request "event") :to-equal "ev-42") + (expect (cider-log-tests--request-get request "nrepl.middleware.print/stream?") + :to-equal "1"))) + + (it "cider-request:log-add-consumer sends the consumer's filters and the callback" + (spy-on 'cider-nrepl-send-request) + (let ((consumer (nrepl-dict "filters" (nrepl-dict "level" "INFO")))) + (cider-request:log-add-consumer framework appender consumer #'ignore) + (let ((args (spy-calls-args-for 'cider-nrepl-send-request 0))) + (expect (cider-log-tests--request-get (car args) "op") + :to-equal "cider/log-add-consumer") + (expect (cider-log-tests--request-get (car args) "framework") :to-equal "logback") + (expect (cider-log-tests--request-get (car args) "appender") :to-equal "my-appender") + (expect (nrepl-dict-get (cider-log-tests--request-get (car args) "filters") "level") + :to-equal "INFO") + (expect (cadr args) :to-be #'ignore)))) + + (it "cider-sync-request:log-remove-consumer identifies the consumer by id" + (spy-on 'cider-nrepl-sync-request :and-return-value (nrepl-dict)) + (cider-sync-request:log-remove-consumer + framework appender (nrepl-dict "id" "my-consumer")) + (let ((request (car (spy-calls-args-for 'cider-nrepl-sync-request 0)))) + (expect (cider-log-tests--request-get request "op") + :to-equal "cider/log-remove-consumer") + (expect (cider-log-tests--request-get request "consumer") :to-equal "my-consumer")))) + +(describe "cider-log appender and consumer accessors" + (it "reads the appender size, threshold, filters and consumers" + (let* ((consumers (list (nrepl-dict "id" "c1"))) + (filters (nrepl-dict "level" "INFO")) + (appender (nrepl-dict "id" "a1" "size" 100 "threshold" 10 + "filters" filters "consumers" consumers))) + (expect (cider-log-appender-size appender) :to-equal 100) + (expect (cider-log-appender-threshold appender) :to-equal 10) + (expect (cider-log-appender-filters appender) :to-equal filters) + (expect (cider-log-appender-consumers appender) :to-equal consumers))) + + (it "finds a consumer of an appender by its id" + (let ((appender (nrepl-dict "consumers" (list (nrepl-dict "id" "c1") + (nrepl-dict "id" "c2"))))) + (expect (cider-log-consumer-id + (cider-log-appender-consumer appender (nrepl-dict "id" "c2"))) + :to-equal "c2") + (expect (cider-log-appender-consumer appender (nrepl-dict "id" "nope")) + :to-be nil))) + + (it "reads the consumer id and filters" + (let* ((filters (nrepl-dict "pattern" "foo")) + (consumer (nrepl-dict "id" "c1" "filters" filters))) + (expect (cider-log-consumer-id consumer) :to-equal "c1") + (expect (cider-log-consumer-filters consumer) :to-equal filters))) + + (it "finds the buffers whose local consumer matches" + (let ((consumer (nrepl-dict "id" "c1"))) + (with-temp-buffer + (setq-local cider-log-consumer (nrepl-dict "id" "c1")) + (let ((match (current-buffer))) + (with-temp-buffer + (setq-local cider-log-consumer (nrepl-dict "id" "other")) + (expect (cider-log-consumer-buffers consumer) + :to-equal (list match)))))))) + +(describe "cider-log--appender" + (it "builds the appender dict from the current settings and filters" + (let ((cider-log-appender-id "my-appender") + (cider-log-appender-size 50) + (cider-log-appender-threshold 20) + (cider-log--level-filter "INFO") + (cider-log--end-time-filter nil) + (cider-log--exceptions-filter nil) + (cider-log--loggers-filter nil) + (cider-log--pattern-filter nil) + (cider-log--start-time-filter nil) + (cider-log--threads-filter nil)) + (let ((appender (cider-log--appender))) + (expect (nrepl-dict-get appender "id") :to-equal "my-appender") + (expect (nrepl-dict-get appender "size") :to-equal 50) + (expect (nrepl-dict-get appender "threshold") :to-equal 20) + (expect (nrepl-dict-get (nrepl-dict-get appender "filters") "level") + :to-equal "INFO")))) + (it "returns nil without an appender id" + (let ((cider-log-appender-id nil)) + (expect (cider-log--appender) :to-be nil)))) + +(describe "cider-log--consumer" + (it "includes the current consumer's id when there is one" + (with-temp-buffer + (setq-local cider-log-consumer (nrepl-dict "id" "c1")) + (expect (nrepl-dict-get (cider-log--consumer) "id") :to-equal "c1"))) + (it "builds a consumer with only filters otherwise" + (with-temp-buffer + (setq-local cider-log-consumer nil) + (let ((consumer (cider-log--consumer))) + (expect (nrepl-dict-get consumer "id") :to-be nil) + (expect (nrepl-dict-p (nrepl-dict-get consumer "filters")) :to-be-truthy))))) + +(describe "cider-log--event-options" + (it "includes the filters and the pagination settings" + (let ((cider-log-pagination-limit 100) + (cider-log-pagination-offset 5) + (cider-log--level-filter "INFO") + (cider-log--end-time-filter nil) + (cider-log--exceptions-filter nil) + (cider-log--loggers-filter nil) + (cider-log--pattern-filter nil) + (cider-log--start-time-filter nil) + (cider-log--threads-filter nil)) + (let ((options (cider-log--event-options))) + (expect (nrepl-dict-get options "limit") :to-equal 100) + (expect (nrepl-dict-get options "offset") :to-equal 5) + (expect (nrepl-dict-get (nrepl-dict-get options "filters") "level") + :to-equal "INFO"))))) + +(describe "cider-log--insert-events" + (it "appends formatted events carrying the event as a text property" + (with-temp-buffer + (let ((event1 (nrepl-dict "id" "e1" "level" "info" "logger" "l" + "message" "one" "thread" "t" "timestamp" "ts1")) + (event2 (nrepl-dict "id" "e2" "level" "warn" "logger" "l" + "message" "two" "thread" "t" "timestamp" "ts2"))) + (cider-log--insert-events (current-buffer) (list event1 event2)) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "ts1 [t] INFO l - one\nts2 [t] WARN l - two\n") + (goto-char (point-min)) + (expect (cider-log-event-at-point) :to-equal event1) + (forward-line 1) + (expect (cider-log-event-at-point) :to-equal event2))))) + +(describe "cider-log-event--pretty-print" + :var (framework appender event) + (before-each + (setq framework (nrepl-dict "id" "logback") + appender (nrepl-dict "id" "my-appender") + event (nrepl-dict "id" "ev-42"))) + + (it "shows the formatted event in the log event popup buffer" + (let ((cider-log-event-buffer "*cider-log-event-test*")) + (spy-on 'cider-sync-request:log-format-event + :and-return-value "{:formatted :event}") + (spy-on 'cider-popup-buffer :and-call-fake + (lambda (name &rest _) (get-buffer-create name))) + (unwind-protect + (progn + (cider-log-event--pretty-print framework appender event) + (with-current-buffer cider-log-event-buffer + (expect (buffer-string) :to-equal "{:formatted :event}") + (expect (point) :to-equal (point-min)))) + (kill-buffer "*cider-log-event-test*")))) + + (it "doesn't pop up a buffer when the event can't be formatted" + (spy-on 'cider-sync-request:log-format-event :and-return-value nil) + (spy-on 'cider-popup-buffer) + (cider-log-event--pretty-print framework appender event) + (expect 'cider-popup-buffer :not :to-have-been-called))) + +(describe "cider-log-event--inspect" + (it "renders the inspected event value in the inspector" + (spy-on 'cider-sync-request:log-inspect-event :and-return-value "inspected") + (spy-on 'cider-inspector--render-value) + (cider-log-event--inspect (nrepl-dict "id" "logback") + (nrepl-dict "id" "my-appender") + (nrepl-dict "id" "ev-42")) + (expect 'cider-inspector--render-value :to-have-been-called-with "inspected"))) + +(describe "cider-log--completion-extra-properties" + (it "annotates completion candidates with the given keys, whitespace collapsed" + (let* ((props (cider-log--completion-extra-properties '("name"))) + (annotate (plist-get props :annotation-function)) + (minibuffer-completion-table + (list (list "logback" (nrepl-dict "name" "The Logback\n framework"))))) + (expect (substring-no-properties (funcall annotate "logback")) + :to-equal " - The Logback framework") + (expect (funcall annotate "unknown") :to-be nil)))) + +(describe "cider-log-info" + (it "summarizes the buffer, framework, appender and consumer" + (spy-on 'message) + (with-temp-buffer + (setq-local cider-log-consumer (nrepl-dict "id" "c1")) + (let ((cider-log-buffer "*cider-log*") + (cider-log-framework-name "Logback") + (cider-log-appender-id "my-appender")) + (cider-log-info))) + (expect (substring-no-properties + (apply #'format (spy-calls-args-for 'message 0))) + :to-equal + "Buffer: *cider-log* Framework: Logback Appender: my-appender Consumer: c1"))) diff --git a/test/cider-repl-tests.el b/test/cider-repl-tests.el index 8a01b6e72..366c3587c 100644 --- a/test/cider-repl-tests.el +++ b/test/cider-repl-tests.el @@ -116,6 +116,29 @@ ;; Clojure 1.8.0, Java 1.8.0_31 ")))) +(describe "cider-repl--banner" + (before-each + (setq nrepl-endpoint (list :host "localhost" :port "12345")) + (spy-on 'cider--version :and-return-value "2.0.0")) + + (it "uses the Babashka banner when only a Babashka version is available" + (spy-on 'cider--clojure-version :and-return-value nil) + (spy-on 'cider--babashka-version :and-return-value "1.3.190") + (spy-on 'cider--babashka-nrepl-version :and-return-value "0.0.6") + (expect (cider-repl--banner) :to-equal + ";; Connected to nREPL server - nrepl://localhost:12345 +;; CIDER 2.0.0, babashka.nrepl 0.0.6 +;; Babashka 1.3.190 +")) + + (it "falls back to the basic banner without any version info" + (spy-on 'cider--clojure-version :and-return-value nil) + (spy-on 'cider--babashka-version :and-return-value nil) + (expect (cider-repl--banner) :to-equal + ";; Connected to nREPL server - nrepl://localhost:12345 +;; CIDER 2.0.0 +"))) + (defvar cider-testing-ansi-colors-vector ["black" "red3" "green3" "yellow3" "blue2" "magenta3" "cyan3" "gray90"] @@ -666,3 +689,94 @@ PROPERTY should be a symbol of either 'text, 'ansi-context or (current-buffer) "") :to-be-truthy) (expect rendered :to-be nil))))) + +(describe "cider-repl--emit-verbatim" + (it "inserts the text into the output area with a trailing newline" + (with-temp-buffer + (cider-repl-reset-markers) + (cider-repl--emit-verbatim (current-buffer) "hello") + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "hello\n") + ;; the output-end marker has advanced past the inserted text + (expect (marker-position cider-repl-output-end) :to-equal (point-max)))) + + (it "doesn't add a second newline when the text already ends in one" + (with-temp-buffer + (cider-repl-reset-markers) + (cider-repl--emit-verbatim (current-buffer) "hello\n") + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "hello\n"))) + + (it "preserves the text properties of the inserted string" + (with-temp-buffer + (cider-repl-reset-markers) + (cider-repl--emit-verbatim (current-buffer) (propertize "styled" 'face 'bold)) + (expect (get-text-property (point-min) 'face) :to-equal 'bold))) + + (it "starts on a fresh line when BOL is requested mid-line" + (with-temp-buffer + (insert "mid") + (cider-repl-reset-markers) + (cider-repl--emit-verbatim (current-buffer) "text" nil t) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "mid\ntext\n"))) + + (it "inserts the result prefix when SHOW-PREFIX is non-nil" + (with-temp-buffer + (cider-repl-reset-markers) + (let ((cider-repl-result-prefix "=> ")) + (cider-repl--emit-verbatim (current-buffer) "res" t)) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "=> res\n")))) + +(describe "cider-repl-handle-html" + (it "emits the rendered HTML verbatim and allows the prompt" + (spy-on 'cider--render-html-string + :and-return-value (propertize "rendered" 'face 'bold)) + (with-temp-buffer + (cider-repl-reset-markers) + (expect (cider-repl-handle-html "text/html" (current-buffer) "raw") + :to-be t) + (expect 'cider--render-html-string :to-have-been-called-with "raw") + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "rendered\n") + ;; the faces produced by the HTML renderer survive + (expect (get-text-property (point-min) 'face) :to-equal 'bold)))) + +(describe "cider-repl--display-external-body" + (it "inserts the URL as a browse-url button plus a fetch button" + (with-temp-buffer + (cider-repl-reset-markers) + (expect (cider-repl--display-external-body (current-buffer) "file:/tmp/x.html") + :to-be t) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "file:/tmp/x.html [show content]") + ;; activating the URL button opens it in the browser + (spy-on 'browse-url) + (funcall (get-text-property (point-min) 'action) nil) + (expect 'browse-url :to-have-been-called-with "file:/tmp/x.html") + ;; activating [show content] triggers the slurp fetch + (spy-on 'cider-repl--fetch-external-body) + (goto-char (point-min)) + (search-forward "[show content]") + (funcall (get-text-property (match-beginning 0) 'action) nil) + (expect 'cider-repl--fetch-external-body + :to-have-been-called-with (current-buffer) "file:/tmp/x.html")))) + +(describe "cider-repl--fetch-external-body" + (it "requests the URL's content via the cider/slurp op" + (spy-on 'cider-nrepl-send-request) + (spy-on 'cider-repl-handler :and-return-value #'ignore) + (cider-repl--fetch-external-body (current-buffer) "file:/tmp/x.html") + (expect 'cider-repl-handler :to-have-been-called-with (current-buffer)) + (expect 'cider-nrepl-send-request :to-have-been-called-with + '("op" "cider/slurp" "url" "file:/tmp/x.html") #'ignore))) + +(describe "cider-repl-content-type-handler-alist" + (it "maps the supported content types to defined handler functions" + (expect (mapcar #'car cider-repl-content-type-handler-alist) + :to-have-same-items-as + '("message/external-body" "image/jpeg" "image/png" + "image/svg+xml" "text/html")) + (dolist (entry cider-repl-content-type-handler-alist) + (expect (functionp (cdr entry)) :to-be-truthy)))) diff --git a/test/integration/integration-tests.el b/test/integration/integration-tests.el index 472fafdbb..769d38b52 100644 --- a/test/integration/integration-tests.el +++ b/test/integration/integration-tests.el @@ -377,7 +377,7 @@ If CLI-COMMAND is nil, then use the default." (cider-itu-poll-until (not (eq (process-status nrepl-proc) 'run)) 5) (expect (member (process-status nrepl-proc) '(exit signal)))))))))) - (xit "to shadow" ;; disabled: shadow-cljs 2.20.13 incompatible with nREPL 1.6 + (it "to shadow" ;; shadow asks user whether they want to open a browser, force to no (spy-on 'y-or-n-p) @@ -391,9 +391,9 @@ If CLI-COMMAND is nil, then use the default." (write-region "{:deps true, :nrepl {:middleware [ikappaki.nrepl-mdlw-log/middleware]}}" nil shadow-cljs-edn) (write-region "{:deps {ikappaki/nrepl-mdlw-log {:git/sha \"d00fecf9f299ffde90b413751f28c1d2e7b56d17\" :git/url \"https://github.com/ikappaki/nrepl-mdlw-log.git\"} - thheller/shadow-cljs {:mvn/version \"2.20.13\"}}}" + thheller/shadow-cljs {:mvn/version \"3.4.11\"}}}" nil deps-edn) - (write-region "{\"dependencies\":{\"shadow-cljs\": \"^2.20.13\"}}" nil package-json) + (write-region "{\"dependencies\":{\"shadow-cljs\": \"^3.4.11\"}}" nil package-json) (let ((default-directory project-dir)) (message ":npm-install...") (shell-command "npm install")