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>
229 lines
8.4 KiB
Markdown
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] ...)
|
|
```
|