(ns auto-ap.ssr.admin.vendors-test (:require [auto-ap.datomic :refer [conn]] [auto-ap.integration.util :refer [admin-token setup-test-data test-account test-client test-vendor user-token wrap-setup]] [auto-ap.ssr.admin.vendors :as sut] [clojure.string :as str] [clojure.test :refer [deftest is testing use-fixtures]] [datomic.api :as dc])) (use-fixtures :each wrap-setup) (defn create-vendor "Create a vendor with a unique temp id" [name & {:as attrs}] (merge {:db/id (str "vendor-" (java.util.UUID/randomUUID)) :vendor/name name :vendor/default-account "test-account-id"} attrs)) ;; ============================================ ;; Grid/List Tests ;; ============================================ (deftest vendor-grid-loads-with-empty-database (testing "Vendor grid should handle empty database gracefully" ;; When: Fetch the vendors page with no data (let [[vendors matching-count] (sut/fetch-page {:query-params {:page 1 :per-page 10}})] ;; Then: Returns empty results without error (is (seq? vendors)) (is (number? matching-count)) (is (= 0 (count vendors)))))) (deftest vendor-fetch-ids-returns-correct-structure (testing "fetch-ids should return properly structured results" ;; Given: Setup test data with vendors using unique IDs (setup-test-data [(create-vendor "Test Vendor 1") (create-vendor "Test Vendor 2")]) (let [db (dc/db conn)] ;; When: Call fetch-ids (let [result (sut/fetch-ids db {:query-params {:page 1 :per-page 10}})] ;; Then: Result has expected structure with :ids and :count (is (contains? result :ids)) (is (contains? result :count)) (is (seq? (:ids result))) (is (number? (:count result))) (is (>= (:count result) 3)))))) ; 2 new + 1 from setup (deftest vendor-fetch-page-returns-vendors (testing "fetch-page should return vendors with proper structure" ;; Given: Setup test data (setup-test-data [(create-vendor "Page Test Vendor 1") (create-vendor "Page Test Vendor 2")]) ;; When: Fetch the vendors page (let [[vendors matching-count] (sut/fetch-page {:query-params {:page 1 :per-page 10}})] ;; Then: Vendor table displays with data (is (number? matching-count)) (is (>= matching-count 3)) ; 2 new + 1 from setup ;; Verify vendors have required attributes (when-some [vendor (first vendors)] (is (contains? vendor :db/id)) (is (contains? vendor :vendor/name)) (is (contains? vendor :vendor/default-account)))))) (deftest vendor-hydrate-results-works (testing "hydrate-results should properly hydrate vendor data" ;; Given: Setup test data with unique vendor ID (let [vendor-temp-id (str "vendor-" (rand-int 100000)) tempids (setup-test-data [(assoc (create-vendor "Hydrate Test Vendor") :db/id vendor-temp-id)]) db (dc/db conn) vendor-id (get tempids vendor-temp-id)] ;; When: Hydrate the vendor (let [hydrated (sut/hydrate-results [vendor-id] db {})] ;; Then: Vendor is properly hydrated (is (= 1 (count hydrated))) (let [vendor (first hydrated)] (is (= vendor-id (:db/id vendor))) (is (= "Hydrate Test Vendor" (:vendor/name vendor))) (is (contains? vendor :vendor/default-account))))))) ;; ============================================ ;; Vendor Merge Tests ;; ============================================ (deftest vendor-merge-transfers-references (testing "Vendor merge should transfer all references from source to target" (let [admin-identity (admin-token)] ;; Given: Create source and target vendors with unique IDs (let [source-temp-id (str "vendor-source-" (rand-int 100000)) target-temp-id (str "vendor-target-" (rand-int 100000)) tempids (setup-test-data [(assoc (create-vendor "Source Vendor") :db/id source-temp-id) (assoc (create-vendor "Target Vendor") :db/id target-temp-id)]) source-vendor-id (get tempids source-temp-id) target-vendor-id (get tempids target-temp-id)] ;; When: Merge source into target (let [result (sut/merge-submit {:form-params {:source-vendor source-vendor-id :target-vendor target-vendor-id} :request-method :put :identity admin-identity})] ;; Then: Success response (is (= 200 (:status result))) ;; And: Source vendor should be deleted (let [db (dc/db conn) remaining-sources (dc/q '[:find ?e :where [?e :vendor/name "Source Vendor"]] db)] (is (= 0 (count remaining-sources))))))))) (deftest vendor-merge-same-vendor-rejected (testing "Vendor merge should reject when source and target are the same" (let [admin-identity (admin-token)] ;; Given: Create a vendor with unique ID (let [vendor-temp-id (str "vendor-solo-" (rand-int 100000)) tempids (setup-test-data [(assoc (create-vendor "Solo Vendor") :db/id vendor-temp-id)]) vendor-id (get tempids vendor-temp-id)] ;; When: Attempt to merge vendor with itself ;; Then: Exception is thrown with validation error (is (thrown-with-msg? clojure.lang.ExceptionInfo #"Please select two different vendors" (sut/merge-submit {:form-params {:source-vendor vendor-id :target-vendor vendor-id} :request-method :put :identity admin-identity}))))))) (deftest vendor-merge-invalid-vendor-handled (testing "Vendor merge should handle invalid vendor IDs gracefully" (let [admin-identity (admin-token)] ;; Given: Create a target vendor (let [target-temp-id (str "vendor-target-" (rand-int 100000)) tempids (setup-test-data [(assoc (create-vendor "Valid Target Vendor") :db/id target-temp-id)]) target-vendor-id (get tempids target-temp-id) ;; Invalid source vendor ID invalid-source-id 999999999] ;; When: Attempt merge with invalid source (let [result (sut/merge-submit {:form-params {:source-vendor invalid-source-id :target-vendor target-vendor-id} :request-method :put :identity admin-identity})] ;; Then: Should still succeed (Datomic handles non-existent retract gracefully) (is (= 200 (:status result)))))))) ;; ============================================ ;; Vendor Data Structure Tests ;; ============================================ (deftest vendor-hydration-includes-all-fields (testing "Vendor hydration should include all required fields" ;; Given: Create a comprehensive vendor (let [vendor-temp-id (str "vendor-complete-" (rand-int 100000)) tempids (setup-test-data [(assoc (create-vendor "Complete Vendor" :vendor/print-as "CV Print Name" :vendor/hidden false :vendor/terms 30) :db/id vendor-temp-id)]) db (dc/db conn) vendor-id (get tempids vendor-temp-id)] ;; When: Fetch and hydrate the vendor (let [hydrated (sut/hydrate-results [vendor-id] db {}) vendor (first hydrated)] ;; Then: All fields are present (is (some? vendor)) (is (= "Complete Vendor" (:vendor/name vendor))) (is (= "CV Print Name" (:vendor/print-as vendor))) (is (= false (:vendor/hidden vendor))) (is (= 30 (:vendor/terms vendor)))))))