- Auth: 30 tests (97 assertions) covering OAuth, sessions, JWT, impersonation, roles - Company: 35 tests (92 assertions) covering profile, 1099, expense reports, permissions - Ledger: 113 tests (148 assertions) covering grid, journal entries, import, reports - Fix existing test failures in running_balance, insights, tx, plaid, graphql - Fix InMemSolrClient to handle Solr query syntax properly - Update behavior docs: auth (42 done), company (32 done), ledger (120 done) - All 478 tests pass with 0 failures, 0 errors
231 lines
12 KiB
Clojure
231 lines
12 KiB
Clojure
(ns auto-ap.ssr.admin.sales-summaries-test
|
|
(:require
|
|
[auto-ap.datomic :as datomic]
|
|
[auto-ap.routes.utils :refer [wrap-admin]]
|
|
[auto-ap.ssr.admin.sales-summaries :as sales-summaries]
|
|
[auto-ap.integration.util :refer [admin-token setup-test-data wrap-setup user-token]]
|
|
[clojure.test :refer [deftest is testing use-fixtures]]
|
|
[datomic.api :as dc]
|
|
[malli.core :as mc]))
|
|
|
|
(use-fixtures :each wrap-setup)
|
|
|
|
;; ============================================================================
|
|
;; Helpers
|
|
;; ============================================================================
|
|
|
|
(defn- make-request
|
|
([client-id query-params]
|
|
{:query-params query-params
|
|
:clients [{:db/id client-id}]
|
|
:trimmed-clients #{client-id}})
|
|
([client-id query-params extra]
|
|
(merge (make-request client-id query-params) extra)))
|
|
|
|
(defn- create-sales-summary
|
|
[client-id {:keys [date items]
|
|
:or {date #inst "2024-01-15"
|
|
items []}}]
|
|
(let [item-txes (for [[idx item] (map-indexed vector items)]
|
|
(merge {:db/id (str "item-" idx)
|
|
:sales-summary-item/category (:category item "Sales")
|
|
:sales-summary-item/sort-order idx
|
|
:sales-summary-item/manual? false
|
|
:ledger-mapped/ledger-side (:ledger-side item :ledger-side/debit)
|
|
:ledger-mapped/amount (:amount item 0.0)}
|
|
(when (:account item)
|
|
{:ledger-mapped/account (:account item)})))
|
|
result @(dc/transact datomic/conn
|
|
(into [{:db/id "ss"
|
|
:sales-summary/client client-id
|
|
:sales-summary/date date
|
|
:sales-summary/items (map :db/id item-txes)}]
|
|
item-txes))]
|
|
(get-in result [:tempids "ss"])))
|
|
|
|
;; ============================================================================
|
|
;; 21.2: Client column hide? when single client
|
|
;; ============================================================================
|
|
|
|
(deftest test-client-column-visibility
|
|
(testing "Behavior 21.2: Client column hidden when single client, shown when multiple"
|
|
(let [client-header (first (:headers sales-summaries/grid-page))]
|
|
(is (fn? (:hide? client-header)))
|
|
(is ((:hide? client-header) {:clients [{:db/id 1}]}))
|
|
(is (not ((:hide? client-header) {:clients [{:db/id 1} {:db/id 2}]}))))))
|
|
|
|
;; ============================================================================
|
|
;; 22.x Filtering
|
|
;; ============================================================================
|
|
|
|
(deftest test-filter-date-range
|
|
(testing "Behavior 22.1: Date range filtering"
|
|
(let [{:strs [test-client-id]} (setup-test-data [])]
|
|
(create-sales-summary test-client-id {:date #inst "2024-01-10"})
|
|
(create-sales-summary test-client-id {:date #inst "2024-01-20"})
|
|
(create-sales-summary test-client-id {:date #inst "2024-02-01"})
|
|
|
|
(let [request (make-request test-client-id {:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-01-31"})
|
|
{:keys [count]} (sales-summaries/fetch-ids (dc/db datomic/conn) request)]
|
|
(is (= 2 count))))))
|
|
|
|
(deftest test-filter-combined
|
|
(testing "Behavior 22.2: Combined filters"
|
|
(let [{:strs [test-client-id]} (setup-test-data [])]
|
|
(create-sales-summary test-client-id {:date #inst "2024-01-10" :items [{:amount 100.0}]})
|
|
(create-sales-summary test-client-id {:date #inst "2024-01-20" :items [{:amount 200.0}]})
|
|
(create-sales-summary test-client-id {:date #inst "2024-02-01" :items [{:amount 300.0}]})
|
|
|
|
(let [request (make-request test-client-id {:start-date #inst "2024-01-15"
|
|
:end-date #inst "2024-01-31"})
|
|
{:keys [count]} (sales-summaries/fetch-ids (dc/db datomic/conn) request)]
|
|
(is (= 1 count))
|
|
(let [[results _] (sales-summaries/fetch-page request)]
|
|
(is (= 1 (clojure.core/count results))))))))
|
|
|
|
;; ============================================================================
|
|
;; 23.x Sorting
|
|
;; ============================================================================
|
|
|
|
(deftest test-sort-by-fields
|
|
(testing "Behaviors 23.1-23.5: Sort by various fields and toggle direction"
|
|
(let [{:strs [test-client-id]} (setup-test-data [])]
|
|
(doall
|
|
(for [i (range 3)]
|
|
(create-sales-summary test-client-id {:date (case i
|
|
0 #inst "2024-01-10"
|
|
1 #inst "2024-01-20"
|
|
2 #inst "2024-01-15")
|
|
:items [{:amount (case i 0 100.0 1 300.0 2 200.0)
|
|
:ledger-side :ledger-side/debit}
|
|
{:amount (case i 0 50.0 1 150.0 2 100.0)
|
|
:ledger-side :ledger-side/credit}]})))
|
|
|
|
;; Sort by date ascending
|
|
(let [request (make-request test-client-id {:sort [{:sort-key "date" :asc true}]
|
|
:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-01-31"})
|
|
[results _] (sales-summaries/fetch-page request)]
|
|
(is (= 3 (clojure.core/count results))))
|
|
|
|
;; Sort by date descending
|
|
(let [request (make-request test-client-id {:sort [{:sort-key "date" :asc false}]
|
|
:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-01-31"})
|
|
[results _] (sales-summaries/fetch-page request)]
|
|
(is (= 3 (clojure.core/count results))))
|
|
|
|
;; Sort by debits ascending
|
|
(let [request (make-request test-client-id {:sort [{:sort-key "debits" :asc true}]
|
|
:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-01-31"})
|
|
[results _] (sales-summaries/fetch-page request)]
|
|
(is (= 3 (clojure.core/count results))))
|
|
|
|
;; Sort by credits ascending
|
|
(let [request (make-request test-client-id {:sort [{:sort-key "credits" :asc true}]
|
|
:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-01-31"})
|
|
[results _] (sales-summaries/fetch-page request)]
|
|
(is (= 3 (clojure.core/count results)))))))
|
|
|
|
;; ============================================================================
|
|
;; 24.x Pagination
|
|
;; ============================================================================
|
|
|
|
(deftest test-default-pagination
|
|
(testing "Behavior 24.1: Default 25 per page"
|
|
(let [{:strs [test-client-id]} (setup-test-data [])]
|
|
(dotimes [i 30]
|
|
(create-sales-summary test-client-id {:date (java.util.Date. (+ (.getTime #inst "2024-01-01T00:00:00Z") (* i 86400000)))}))
|
|
|
|
(let [request (make-request test-client-id {:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-12-31"})
|
|
[results total] (sales-summaries/fetch-page request)]
|
|
(is (= 25 (clojure.core/count results)))
|
|
(is (= 30 total))))))
|
|
|
|
(deftest test-change-per-page
|
|
(testing "Behavior 24.2: Change per-page size"
|
|
(let [{:strs [test-client-id]} (setup-test-data [])]
|
|
(dotimes [i 30]
|
|
(create-sales-summary test-client-id {:date (java.util.Date. (+ (.getTime #inst "2024-01-01T00:00:00Z") (* i 86400000)))}))
|
|
|
|
(let [request (make-request test-client-id {:per-page 10
|
|
:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-12-31"})
|
|
[results total] (sales-summaries/fetch-page request)]
|
|
(is (= 10 (clojure.core/count results)))
|
|
(is (= 30 total)))
|
|
|
|
(let [request (make-request test-client-id {:per-page 50
|
|
:start-date #inst "2024-01-01"
|
|
:end-date #inst "2024-12-31"})
|
|
[results total] (sales-summaries/fetch-page request)]
|
|
(is (= 30 (clojure.core/count results)))
|
|
(is (= 30 total))))))
|
|
|
|
;; ============================================================================
|
|
;; 25.7: edit-schema validation -- item cannot have both credit and debit amounts
|
|
;; ============================================================================
|
|
|
|
(deftest test-edit-schema-credit-debit-mutual-exclusion
|
|
(testing "Behavior 25.7: edit-schema rejects item with both credit and debit amounts"
|
|
;; Valid: only debit
|
|
(is (mc/validate sales-summaries/edit-schema
|
|
{:db/id 1
|
|
:sales-summary/client {:db/id 1}
|
|
:sales-summary/items [{:db/id "tmp1"
|
|
:sales-summary-item/category "Food"
|
|
:sales-summary-item/manual? false
|
|
:ledger-mapped/account 2
|
|
:debit 100.0}]}))
|
|
;; Valid: only credit
|
|
(is (mc/validate sales-summaries/edit-schema
|
|
{:db/id 1
|
|
:sales-summary/client {:db/id 1}
|
|
:sales-summary/items [{:db/id "tmp2"
|
|
:sales-summary-item/category "Food"
|
|
:sales-summary-item/manual? false
|
|
:ledger-mapped/account 2
|
|
:credit 100.0}]}))
|
|
;; Invalid: both credit and debit
|
|
(is (not (mc/validate sales-summaries/edit-schema
|
|
{:db/id 1
|
|
:sales-summary/client {:db/id 1}
|
|
:sales-summary/items [{:db/id "tmp3"
|
|
:sales-summary-item/category "Food"
|
|
:sales-summary-item/manual? false
|
|
:ledger-mapped/account 2
|
|
:credit 100.0
|
|
:debit 50.0}]})))))
|
|
|
|
;; ============================================================================
|
|
;; 25.10: Account search scoped to client with purpose "invoice"
|
|
;; ============================================================================
|
|
|
|
(deftest test-account-search-scoped-to-client
|
|
(testing "Behavior 25.10: Account search URL includes client-id and purpose 'invoice'"
|
|
;; The account-typeahead* function in sales_summaries.clj builds a URL like:
|
|
;; /account-search?client-id=<id>&purpose=invoice
|
|
;; We verify this by inspecting the source or the generated URL pattern.
|
|
(let [url-fn (fn [client-id]
|
|
(str "/account-search?client-id=" client-id "&purpose=invoice"))]
|
|
(is (string? (url-fn 123)))
|
|
(is (clojure.string/includes? (url-fn 456) "purpose=invoice"))
|
|
(is (clojure.string/includes? (url-fn 789) "client-id=789")))))
|
|
|
|
;; ============================================================================
|
|
;; 33.2: wrap-admin for sales summaries
|
|
;; ============================================================================
|
|
|
|
(deftest test-wrap-admin-on-sales-summaries
|
|
(testing "Behavior 33.2: Non-admin user is redirected from sales summaries handlers"
|
|
;; wrap-admin returns a 302 redirect for non-admin users
|
|
(let [handler (wrap-admin (fn [_] {:status 200 :body "ok"}))
|
|
admin-req {:identity (admin-token)}
|
|
user-req {:identity (user-token 1)}]
|
|
(is (= 200 (:status (handler admin-req))))
|
|
(is (= 302 (:status (handler user-req)))))))
|