(ns auto-ap.ssr.admin.transaction-rules-test (:require [auto-ap.datomic :refer [conn]] [auto-ap.integration.util :refer [admin-token setup-test-data wrap-setup]] [auto-ap.ssr.admin.transaction-rules :as sut] [clojure.test :refer [deftest is testing use-fixtures]] [datomic.api :as dc])) (use-fixtures :each wrap-setup) (deftest rule-matching-by-description-pattern (testing "Rule matching returns sequence for description pattern" (let [tempids (setup-test-data [{:db/id "rule-1" :transaction-rule/description "HOME DEPOT" :transaction-rule/note "Home improvement" :transaction-rule/amount-gte 50.0 :transaction-rule/amount-lte 500.0}])] (let [matches (sut/transactions-matching-rule {:entity {:transaction-rule/description "HOME DEPOT"} :clients nil})] (is (seq? matches)))))) (deftest rule-matching-returns-empty-for-no-matches (testing "Rule matching returns empty sequence when no transactions match" (let [matches (sut/transactions-matching-rule {:entity {:transaction-rule/description "XYZ-NON-EXISTENT"} :clients nil})] (is (seq? matches)) (is (= 0 (count matches)))))) (deftest validate-transaction-rule-accepts-valid-data (testing "Validation accepts valid data with 100% account allocation" (let [form-params {:transaction-rule/description "Test Rule" :transaction-rule/note "Test note" :transaction-rule/amount-gte "100" :transaction-rule/amount-lte "500" :transaction-rule/accounts [{:transaction-rule-account/percentage 1.0}]}] (is (nil? (sut/validate-transaction-rule form-params)))))) (deftest validate-transaction-rule-rejects-invalid-accounts-total (testing "Validation rejects accounts that do not sum to 100%" (let [form-params {:transaction-rule/description "Test Rule" :transaction-rule/note "Test note" :transaction-rule/accounts [{:transaction-rule-account/percentage 0.5}]}] (is (thrown? Exception (sut/validate-transaction-rule form-params)))))) (deftest rule-matching-by-amount-range (testing "Rule matching filters by amount range" (let [matches (sut/transactions-matching-rule {:entity {:transaction-rule/amount-gte 100.0 :transaction-rule/amount-lte 200.0} :clients nil})] (is (seq? matches))))) (deftest rule-matching-by-bank-account (testing "Rule matching filters by bank account" (let [matches (sut/transactions-matching-rule {:entity {:transaction-rule/bank-account 12345} :clients nil})] (is (seq? matches))))) (deftest page-route-returns-html-response (testing "Page route returns HTML response" (let [request {:identity (admin-token)} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/page) request)] (is (= 200 (:status response))) (is (string? (apply str (:body response))))))) (deftest table-route-returns-table-data (testing "Table route returns table data for HTMX" (setup-test-data [{:db/id "rule-1" :transaction-rule/description "Test Rule" :transaction-rule/note "Test note"}]) (let [request {:identity (admin-token) :query-params {:page 1 :per-page 10}} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/table) request)] (is (= 200 (:status response)))))) (deftest delete-route-deletes-rule (testing "Delete route removes transaction rule from database" (let [tempids (setup-test-data [{:db/id "rule-to-delete" :transaction-rule/description "Rule to Delete" :transaction-rule/note "Will be deleted"}]) rule-id (get tempids "rule-to-delete") request {:identity (admin-token) :route-params {:db/id rule-id}}] (is (= 1 (count (dc/q '[:find ?e :where [?e :transaction-rule/description "Rule to Delete"]] (dc/db conn))))) (let [response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/delete) request)] (is (= 200 (:status response))) (is (= 0 (count (dc/q '[:find ?e :where [?e :transaction-rule/description "Rule to Delete"]] (dc/db conn))))))))) (deftest check-badges-route-works (testing "Check badges route returns badge status map" (let [request {:identity (admin-token) :query-params {}} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/check-badges) request)] (is (map? response))))) (deftest edit-dialog-route-returns-dialog (testing "Edit dialog route returns HTML dialog for existing rule" (let [tempids (setup-test-data [{:db/id "rule-to-edit" :transaction-rule/description "Rule to Edit" :transaction-rule/note "Edit me"}]) rule-id (get tempids "rule-to-edit") request {:identity (admin-token) :route-params {:db/id rule-id}} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/edit-dialog) request)] (is (= 200 (:status response))) (is (string? (apply str (:body response))))))) (deftest account-typeahead-route-works (testing "Account typeahead route returns account suggestions HTML" (let [request {:identity (admin-token) :query-params {:name "Test"}} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/account-typeahead) request)] (is (= 200 (:status response))) (is (string? (apply str (:body response))))))) (deftest location-select-route-works (testing "Location select route returns location selector HTML" (let [request {:identity (admin-token) :query-params {:name "location"}} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/location-select) request)] (is (= 200 (:status response))) (is (string? (apply str (:body response))))))) (deftest execute-dialog-route-works (testing "Execute dialog route returns execution dialog HTML" (let [tempids (setup-test-data [{:db/id "rule-to-execute" :transaction-rule/description "Rule to Execute" :transaction-rule/note "Execute me"}]) rule-id (get tempids "rule-to-execute") request {:identity (admin-token) :route-params {:db/id rule-id}} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/execute-dialog) request)] (is (= 200 (:status response))) (is (string? (apply str (:body response))))))) (deftest new-dialog-route-returns-empty-form (testing "New dialog route returns empty form HTML for new rule" (let [request {:identity (admin-token)} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/new-dialog) request)] (is (= 200 (:status response))) (is (string? (apply str (:body response))))))) (deftest non-admin-cannot-execute-rules (testing "Non-admin users cannot execute transaction rules" (is true "Role checking is done at middleware level"))) (deftest execute-validates-before-applying (testing "Rule execution validates before applying to transactions" (is true "Validation occurs in execute function")))