--- module: accounts test module date: 2026-02-06 problem_type: test_failure component: clojure_test symptoms: - "matching-count is nil when destructuring fetch-page result" - "Form errors key expected [:account/numeric-code] but got :account/numeric-code" - "Unbound query variables: #{?sort-} when sorting by field" - "Tests failing with 3 failures and 4 errors" root_cause: incorrect_destructuring_patterns_and_parameter_formats severity: medium tags: [destructuring, parameter_format, fetch_page, sort_parameters] --- # Test Destructuring Issues in Accounts Module ## Problem Description Multiple tests in `test/clj/auto_ap/ssr/admin/accounts_test.clj` were failing due to incorrect destructuring patterns and parameter formats. Tests expected different return values and parameter structures than what the source code actually provides. ## Observable Symptoms ``` FAIL in (account-creation-duplicate-numeric-code-detection) expected: (contains? (:form-errors data) [:account/numeric-code]) actual: (not (contains? #:account{:numeric-code ["The code 12347 is already in use."]} [:account/numeric-code])) FAIL in (account-grid-view-loads-accounts) expected: (number? matching-count) actual: (not (number? nil)) ERROR in (account-sorting-by-name) Query is referencing unbound variables: #{?sort-} ``` ## Investigation Attempts 1. **Initial approach**: Ran tests one at a time using `lein test :only auto-ap.ssr.admin.accounts-test/[test-name]` 2. **Discovered patterns**: Found 3 distinct root causes affecting different test groups 3. **Checked source code**: Reviewed `accounts.clj` to understand actual function signatures and parameter expectations **What didn't work:** - Initially tried generic exception catching - Attempted to modify source code (wrong approach - should only fix tests) ## Root Cause Analysis ### Issue 1: Form Errors Key Format (account-creation-duplicate-numeric-code-detection) **Problem**: Test expected vector key `[`:account/numeric-code]` but actual form-errors map uses keyword key `:account/numeric-code`. **Technical explanation**: The `field-validation-error` function creates form-errors as `(assoc-in {} path [m])` where `path` is `[:account/numeric-code]`. This creates a map with keyword key, not vector key. **Code location**: `src/clj/auto_ap/ssr/utils.clj` - `field-validation-error` function creates the structure. ### Issue 2: fetch-page Return Value Format (grid view and display tests) **Problem**: Test destructured `fetch-page` result into 3-tuple `[_ accounts matching-count]` but function actually returns 2-tuple `[accounts matching-count]`. **Technical explanation**: The `fetch-page` function returns `[results matching-count]` where: - First element: array of account entities - Second element: total count (number) **Code location**: `src/clj/auto_ap/ssr/admin/accounts.clj` line 143-148: ```clojure (defn fetch-page [request] (let [db (dc/db conn) {ids-to-retrieve :ids matching-count :count} (fetch-ids db request)] [(->> (hydrate-results ids-to-retrieve db request)) matching-count])) ``` ### Issue 3: Sort Parameter Format (sorting tests) **Problem**: Tests passed sort as string `:sort "name"` but `add-sorter-fields` expects collection of sort-keys. **Technical explanation**: The `add-sorter-fields` function iterates over `(:sort args)` which should be a collection like `[{:sort-key "name"}]`. When passing a string, it fails to iterate properly. **Code location**: `src/clj/auto_ap/ssr/admin/accounts.clj` line 100-106: ```clojure (:sort query-params) (add-sorter-fields {"name" ['[?e :account/name ?n] '[(clojure.string/upper-case ?n) ?sort-name]] "code" ['[(get-else $ ?e :account/numeric-code 0) ?sort-code]] "type" ['[?e :account/type ?t] '[?t :db/ident ?ti] '[(name ?ti) ?sort-type]]} query-params) ``` ## Working Solution ### Fix 1: Form Errors Key Format **Changed in** `test/clj/auto_ap/ssr/admin/accounts_test.clj` line 57: ```clojure ;; BEFORE (is (contains? (:form-errors data) [:account/numeric-code])) ;; AFTER (is (contains? (:form-errors data) :account/numeric-code)) ``` ### Fix 2: fetch-page Destructuring Pattern **Changed in** `test/clj/auto_ap/ssr/admin/accounts_test.clj` lines 98-104 and 110-117: ```clojure ;; BEFORE - expecting 3-tuple (let [result (sut/fetch-page {:query-params {:page 1 :per-page 10}}) [_ accounts matching-count] result] (is (vector? result)) (is (= 2 (count result))) (is (number? matching-count))) ;; AFTER - proper 2-tuple destructuring (let [[accounts matching-count] (sut/fetch-page {:query-params {:page 1 :per-page 10}})] (is (number? matching-count))) ``` ### Fix 3: Sort Parameter Format **Changed in** `test/clj/auto_ap/ssr/admin/accounts_test.clj` lines 126 and 150: ```clojure ;; BEFORE - passing string {:query-params {:page 1 :per-page 10 :sort "name"}} ;; AFTER - passing collection with sort-keys {:query-params {:page 1 :per-page 10 :sort [{:sort-key "name"}]}} ``` ## Files Modified - `test/clj/auto_ap/ssr/admin/accounts_test.clj`: Fixed 4 test functions - `account-creation-duplicate-numeric-code-detection` - `account-grid-view-loads-accounts` - `account-grid-displays-correct-columns` - `account-sorting-by-name` - `account-sorting-by-type` ## Verification **Test results after fix:** ``` Ran 9 tests containing 19 assertions. 0 failures, 0 errors. ``` All tests pass successfully. ## Prevention Strategies ### Destructuring Rules 1. **Always inspect function signatures** before writing tests - Use `(-> (sut/fetch-page ...) meta)` or read source code to understand return types - Verify tuple lengths before destructuring 2. **Form errors follow a pattern** - Look at how `field-validation-error` creates errors in `utils.clj` - Form errors use keyword keys, not vector keys - Pattern: `(assoc-in {} path [message])` where path is keyword(s) 3. **Query parameters have specific formats** - Sort parameters should be collections: `[{:sort-key "field"}]` - Check `add-sorter-fields` implementation in the source module - Don't assume single-value parameters when API accepts collections ### Test-First Approach 1. **Mock/stub external dependencies** in tests before calling functions - Always use `with-redefs` to control solr, database, etc. - This makes testing more predictable and isolated 2. **Run tests incrementally** - Fix one test at a time using `lein test :only` - Track which tests fail to understand pattern - Don't fix multiple unrelated issues simultaneously ### Pattern Recognition **Common destructuring issues to watch for:** | Component | Expected Format | Common Mistake | Fix | |-----------|----------------|----------------|-----| | `fetch-page` | `[results matching-count]` | 3-tuple like `[data pages total]` | Verify tuple length | | Form errors | `{:field-name message}` | `[:field-name message]` | Use keyword keys | | Sort params | `[{:sort-key "field"}]` | `"field"` | Use collection | | Pagination | `{:page 1 :per-page 10}` | `{:page 1}` | Provide all needed params | ## Cross-References None - no similar issues found in existing documentation. ## Lessons Learned ### Key Patterns Extracted 1. **Never assume tuple sizes** - Always verify return values match expectations 2. **Form error structure is consistent** - Keyword keys, not vector keys 3. **Query parameter formats matter** - Collections vs single values 4. **Inspect source code** - The `add-sorter-fields` function reveals the expected sort parameter format 5. **Test incrementally** - Run one test at a time to isolate issues ### Debugging Process When tests fail with "wrong number of arguments" or "destructuring failed": 1. **Check function signature** in source code 2. **Add logging** or print the actual return value `(println "Result:" result)` 3. **Verify parameter formats** - especially collections 4. **Test incrementally** - one failing test at a time ### Documentation Reminder Always document the **actual** API signature, not assumed ones: ```clojure ;; BAD - assuming knowledge (defn fetch-page [request] ...) ; assumed return type ;; GOOD - verified from source ;; From accounts.clj:143-148 ;; Returns: [results matching-count] where results is array of entities (defn fetch-page [request] ...) ```