--- module: SSR Admin Vendors date: 2026-02-07 problem_type: test_failure component: testing_framework symptoms: - "SSR admin vendors module has 932 lines of code with zero test coverage" - "Wizard protocol methods (LinearModalWizard) are complex and difficult to test directly" - "Multiple test failures due to entity ID conflicts in test database" - "Syntax errors from unmatched parentheses after code generation" root_cause: inadequate_documentation resolution_type: test_fix severity: medium tags: [testing, vendors, ssr, datomic, wizard, bdd, clojure] --- # Adding Tests for SSR Admin Vendors Module ## Problem The SSR admin vendors module (`src/clj/auto_ap/ssr/admin/vendors.clj`) had **zero test coverage** despite being a critical 932-line component. This created risks for untested complex logic including multi-step wizard navigation, vendor merge functionality, and form state management. Initial attempts to test the wizard protocol directly failed due to its complexity. ## Environment - Module: SSR Admin Vendors - Component: Testing Framework (Clojure) - Date: 2026-02-07 - Location: `test/clj/auto_ap/ssr/admin/vendors_test.clj` ## Symptoms - No existing test file for vendors module - Attempts to call `sut/submit` (wizard protocol method) resulted in "No such var" errors - Direct wizard testing through `LinearModalWizard` protocol methods was too complex - Test data creation using default temp IDs caused entity conflicts - `lein cljfmt check` revealed formatting issues and delimiter errors - Tests failing with "Unable to resolve entity" errors for account references ## What Didn't Work **Attempted Solution 1: Direct wizard protocol testing** - Tried to test vendor creation through `sut/submit` with `VendorWizard` record - **Why it failed:** The `submit` method is part of the `LinearModalWizard` protocol, not a public var. It requires complex `MultiStepFormState` encoding that wraps handler functions with multiple middleware layers. **Attempted Solution 2: Using default test-vendor helper** - Used `(test-vendor :vendor/name "Test")` with default `:db/id "vendor-id"` - **Why it failed:** Multiple vendors with the same temp ID caused entity conflicts in Datomic transactions. **Attempted Solution 3: Testing vendor creation via wizard handlers** - Attempted to test the full wizard flow through route handlers - **Why it failed:** Route handlers are wrapped with middleware (`wrap-admin`, `wrap-schema-enforce`, etc.) that require full HTTP request context, making unit testing impractical. ## Solution **Key insight:** Test the underlying functions rather than the wizard protocol. Focus on: 1. Grid/list functions: `fetch-page`, `fetch-ids`, `hydrate-results` 2. Merge functionality: `merge-submit` 3. Data structure validation through direct database queries **Implementation approach:** ```clojure ;; HELPER: Create vendors with unique temp IDs to avoid conflicts (defn create-vendor [name & {:as attrs}] (merge {:db/id (str "vendor-" (java.util.UUID/randomUUID)) :vendor/name name :vendor/default-account "test-account-id"} attrs)) ;; EXAMPLE: Testing grid functionality (deftest vendor-fetch-ids-returns-correct-structure (setup-test-data [(create-vendor "Test Vendor 1") (create-vendor "Test Vendor 2")]) (let [db (dc/db conn) result (sut/fetch-ids db {:query-params {:page 1 :per-page 10}})] (is (contains? result :ids)) (is (contains? result :count)) (is (seq? (:ids result))))) ; Note: returns seq, not vector ``` **Test coverage implemented:** 1. **Grid/List Tests (5 tests)** - Empty database handling - Fetch-ids structure validation - Name filtering functionality - Hidden/global filtering - Data hydration 2. **Vendor Merge Tests (3 tests)** - Successful merge transfers references - Same vendor merge rejection - Invalid vendor handling **Final result:** 8 tests with 26 assertions, all passing. ## Why This Works 1. **Separation of concerns:** The vendors module separates wizard UI logic (complex, HTMX-driven) from data operations (testable functions). Testing `fetch-page`, `hydrate-results`, and `merge-submit` validates the core business logic without the UI complexity. 2. **Unique temp IDs:** Datomic requires unique temporary IDs for each entity in a transaction. Using `(str "vendor-" (java.util.UUID/randomUUID))` ensures no conflicts. 3. **Using setup-test-data:** This helper properly initializes the test database with accounts, clients, and vendors, providing the necessary relationships for vendor testing. 4. **Protocol vs. functions:** The wizard protocol (`LinearModalWizard`) is an abstraction over HTTP request handling. The actual data operations are in standalone functions that can be tested independently. ## Prevention **When adding tests for SSR modules:** 1. **Use unique temp IDs:** Always generate unique temporary IDs for entities: ```clojure {:db/id (str "entity-" (java.util.UUID/randomUUID))} ``` 2. **Test underlying functions:** Don't test wizard/protocol methods directly. Test the functions they call: - ✅ Test: `fetch-page`, `hydrate-results`, `merge-submit` - ❌ Don't test: Wizard step navigation, form state encoding 3. **Use existing helpers:** Leverage `setup-test-data` from `test/clj/auto_ap/integration/util.clj` for proper test data initialization. 4. **Run clj-paren-repair:** After generating code, run `clj-paren-repair` to fix delimiter issues before running tests. 5. **Check return types:** Datomic functions may return sequences instead of vectors. Use `seq?` instead of `vector?` for assertions. ## Related Issues - Similar testing patterns documented in: [test-destructuring-accounts-module-20260206.md](./test-destructuring-accounts-module-20260206.md) - Datomic query patterns: [atomic-query-patterns-in-bdd-tests-auto-ap-ssr-20260206.md](./atomic-query-patterns-in-bdd-tests-auto-ap-ssr-20260206.md) ## Key Files - **Tests:** `test/clj/auto_ap/ssr/admin/vendors_test.clj` - **Source:** `src/clj/auto_ap/ssr/admin/vendors.clj` - **Utilities:** `test/clj/auto_ap/integration/util.clj` - **Similar tests:** `test/clj/auto_ap/ssr/admin/accounts_test.clj`