Files
integreat/docs/solutions/test-failures/test-destructuring-accounts-module-20260206.md
Bryce a7daf839ec feat(tests): Add comprehensive tests for SSR admin vendors module
Add 8 BDD-style tests for the vendors module covering grid/list
operations and vendor merge functionality. Tests follow established
patterns from accounts_test.clj and include proper database
verification.

Tests Implemented:
- vendor-grid-loads-with-empty-database
- vendor-fetch-ids-returns-correct-structure
- vendor-fetch-page-returns-vendors
- vendor-hydrate-results-works
- vendor-merge-transfers-references
- vendor-merge-same-vendor-rejected
- vendor-merge-invalid-vendor-handled
- vendor-hydration-includes-all-fields

Key Implementation Details:
- Uses setup-test-data helper with unique temp IDs
- Tests focus on public interface (fetch-page, merge-submit)
- Follows BDD Given/When/Then pattern
- All 8 tests passing (26 assertions)

Documentation:
- Created implementation plan in docs/plans/
- Documented solution patterns in docs/solutions/
- Created code review todos for future improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-06 23:53:31 -08:00

229 lines
8.4 KiB
Markdown

---
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] ...)
```