Files
integreat/test/clj/auto_ap/query_params_test.clj
Bryce e99ac6e978 fix(ssr): stop parse-sort leaking a render fn into wizard snapshots
Sorting a grid before opening a bulk wizard 500'd the submit with
"No reader function for tag object".

parse-sort returned the grid's whole :matching-header map, which carries a
:render fn. That sort rides along in :query-params, which the bulk wizards
copy verbatim into their form snapshot (bulk_code.clj:88, invoices.clj:1437).
The snapshot is serialized with pr-str into a hidden field and read back with
clojure.edn/read-string on submit; a fn pr-strs as #object[...], which edn has
no reader for, so wrap-decode-multi-form-state threw before the handler ran.

:matching-header was only ever read inside parse-sort itself - nothing
downstream consumes it, and apply-toggle-sort in this same namespace already
builds entries without it. Keep it as a local binding to derive :name and to
drop unknown columns, and leave it out of the result.

Fixes transaction bulk-code (11 production 500s over 2026-08-10/11) and the
same latent bug in invoice bulk-edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:10:26 -07:00

41 lines
2.0 KiB
Clojure

(ns auto-ap.query-params-test
(:require
[auto-ap.query-params :as sut]
[auto-ap.ssr.invoices :as invoices]
[auto-ap.ssr.transaction.common :as transaction]
[clojure.edn :as edn]
[clojure.test :refer [deftest is testing]]))
(defn- sortable-keys [grid]
(->> (:headers grid) (keep :sort-key)))
(deftest parse-sort-round-trips-through-edn
;; The bulk wizards copy :query-params into their form snapshot, serialize it with
;; pr-str into a hidden field, and read it back with clojure.edn/read-string on
;; submit. Anything parse-sort puts in :query-params has to survive that trip --
;; a bare fn or other unprintable object pr-strs as #object[...], which edn cannot
;; read, and the submit 500s before the handler ever runs.
(doseq [[label grid] [["transactions" transaction/grid-page]
["invoices" invoices/grid-page]]
sort-key (sortable-keys grid)
direction ["asc" "desc"]]
(testing (str label " sorted by " sort-key ":" direction)
(let [parsed (sut/parse-sort grid (str sort-key ":" direction))]
(is (seq parsed) "should produce a sort entry")
(is (= parsed (edn/read-string (pr-str parsed)))
"parsed sort must survive a pr-str / edn round trip")))))
(deftest parse-sort-behaviour
(testing "Unknown columns are dropped"
(is (= [] (sut/parse-sort transaction/grid-page "not-a-column:asc"))))
(testing "An empty sort query yields no sort"
(is (= [] (sut/parse-sort transaction/grid-page ""))))
(testing "Multiple sort keys are preserved in order"
(is (= ["client" "vendor"]
(mapv :sort-key (sut/parse-sort transaction/grid-page "client:asc,vendor:desc")))))
(testing "Direction is parsed per key"
(is (= [true false]
(mapv :asc (sut/parse-sort transaction/grid-page "client:asc,vendor:desc")))))
(testing "The display name is carried over from the matching header"
(is (= "Date" (:name (first (sut/parse-sort transaction/grid-page "date:asc")))))))