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>
This commit is contained in:
2026-02-06 23:53:31 -08:00
parent 791e41cf34
commit a7daf839ec
14 changed files with 3301 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
---
status: pending
priority: p1
issue_id: "006"
tags: [testing, imports, code-quality, vendors, clojure]
dependencies: []
---
# Fix Import Organization and Remove Unused Imports in vendors_test.clj
## Problem Statement
The vendors test file has import organization issues that violate project conventions:
1. Imports are not sorted alphabetically within groups
2. Multiple unused imports (test-account, test-client, test-vendor, user-token, clojure.string)
3. Inconsistent with accounts_test.clj pattern
This creates technical debt and confusion for developers trying to follow established patterns.
## Findings
**Current imports (vendors_test.clj lines 1-14):**
```clojure
(:require
[auto-ap.datomic :refer [conn]] ; internal
[auto-ap.integration.util :refer [admin-token ; internal
setup-test-data
test-account ; UNUSED
test-client ; UNUSED
test-vendor ; UNUSED
user-token ; UNUSED
wrap-setup]]
[auto-ap.ssr.admin.vendors :as sut] ; internal
[clojure.string :as str] ; stdlib
[clojure.test :refer [deftest is testing use-fixtures]] ; stdlib
[datomic.api :as dc]) ; third-party
```
**Issues identified by kieran-rails-reviewer:**
- Unused: `test-account`, `test-client`, `test-vendor`, `user-token`, `clojure.string`
- `auto-ap.integration.util` imports not alphabetized (admin-token before setup-test-data)
- Missing `:as t` alias for clojure.test (accounts_test.clj uses this)
**Expected order (per AGENTS.md):**
- Standard library imports first (clojure.test, clojure.string)
- Third-party libraries second (datomic.api)
- Internal library imports last (auto-ap.*)
## Proposed Solutions
### Option A: Minimal Fix (Recommended)
**Effort:** Small (5 minutes)
**Risk:** Low
Remove unused imports and reorganize:
```clojure
(:require
[auto-ap.datomic :refer [conn]]
[auto-ap.integration.util :refer [admin-token setup-test-data wrap-setup]]
[auto-ap.ssr.admin.vendors :as sut]
[clojure.test :refer [deftest is testing use-fixtures]]
[datomic.api :as dc])
```
**Pros:**
- Quick fix
- Addresses immediate issues
- Follows existing accounts_test.clj pattern
**Cons:**
- Still doesn't match AGENTS.md import ordering standard
### Option B: Full Standards Compliance
**Effort:** Small (10 minutes)
**Risk:** Low
Reorder to match AGENTS.md standard:
```clojure
(:require
[clojure.test :refer [deftest is testing use-fixtures]] ; stdlib first
[datomic.api :as dc] ; third-party second
[auto-ap.datomic :refer [conn]] ; internal last
[auto-ap.integration.util :refer [admin-token setup-test-data wrap-setup]]
[auto-ap.ssr.admin.vendors :as sut])
```
**Pros:**
- Follows project standards exactly
- Consistent with documented conventions
**Cons:**
- Different from accounts_test.clj pattern
- May require updating accounts_test.clj too for consistency
## Recommended Action
**Go with Option A** - minimal fix that removes unused imports and matches accounts_test.clj pattern. This provides immediate value without introducing inconsistency with the reference test file.
## Technical Details
**Affected Files:**
- `test/clj/auto_ap/ssr/admin/vendors_test.clj` (lines 1-14)
**Dependencies:** None
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test # Ensure tests still pass
lein cljfmt check # Verify formatting
```
## Acceptance Criteria
- [ ] All unused imports removed (test-account, test-client, test-vendor, user-token, clojure.string)
- [ ] Remaining imports organized consistently with accounts_test.clj
- [ ] Tests continue to pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Code Review Agent
**Actions:**
- Identified import issues during comprehensive review
- Documented current state and expected patterns
- Created todo for tracking
**Learnings:**
- accounts_test.clj serves as reference pattern
- AGENTS.md documents import ordering standards
- Multiple agents flagged this as inconsistency

View File

@@ -0,0 +1,152 @@
---
status: pending
priority: p1
issue_id: "007"
tags: [testing, solr, mocking, vendors, side-effects]
dependencies: []
---
# Add Missing Solr Mocking to vendors_test.clj
## Problem Statement
All tests in vendors_test.clj are missing the `(with-redefs [auto-ap.solr/impl ...])` wrapper that accounts_test.clj uses consistently. This may cause:
1. Test failures if vendor operations trigger Solr indexing
2. Side effects between tests if Solr state leaks
3. Inconsistency with established testing patterns
## Findings
**From kieran-rails-reviewer:**
Lines 31-38, 40-53, 55-69, etc. are missing:
```clojure
(with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
...)
```
**accounts_test.clj pattern (every test):**
```clojure
(deftest account-creation-success
(testing "Admin should be able to create..."
(with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
(let [admin-identity (admin-token)
result (sut/account-save ...)]
...))))
```
**Impact:**
- Tests may fail if Solr operations are triggered during vendor save/update
- Potential side effects between tests (shared Solr state)
- Violates test isolation principles
## Proposed Solutions
### Option A: Add Solr Wrapper to All Tests (Recommended)
**Effort:** Small (10 minutes)
**Risk:** Low
Wrap all test bodies with Solr mocking:
```clojure
(deftest vendor-fetch-ids-returns-correct-structure
(testing "fetch-ids should return properly structured results"
(with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
;; Given: Setup test data
(setup-test-data [(create-vendor "Test Vendor 1") ...])
...)))
```
**Pros:**
- Ensures test isolation
- Matches accounts_test.clj pattern exactly
- Prevents side effects between tests
**Cons:**
- Slightly more verbose test code
- Adds ~8 lines of boilerplate across all tests
### Option B: Verify Solr Not Needed
**Effort:** Small (10 minutes)
**Risk:** Medium
Research whether vendor operations actually use Solr:
1. Check if `sut/fetch-page`, `sut/fetch-ids`, `sut/hydrate-results`, or `sut/merge-submit` trigger Solr
2. Check vendors.clj for `solr/index-documents-raw` calls
3. Only add mocking if Solr is actually used
**Pros:**
- Avoids unnecessary code if Solr not used
- More targeted fix
**Cons:**
- Requires investigation
- Risk of missing edge cases
- Future changes could break tests
### Option C: Extract Solr Fixture
**Effort:** Medium (20 minutes)
**Risk:** Low
Create a test fixture for Solr mocking:
```clojure
(defn with-solr-mock [f]
(with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
(f)))
(use-fixtures :each wrap-setup with-solr-mock)
```
**Pros:**
- Cleaner test code (no inline with-redefs)
- Reusable across test files
- Automatically applied to all tests
**Cons:**
- Adds global fixture (may affect tests that don't need it)
- New pattern not used in accounts_test.clj
## Recommended Action
**Go with Option A** - add explicit Solr mocking to each test. This:
1. Matches the established accounts_test.clj pattern
2. Makes dependencies explicit (clear which tests need Solr)
3. Provides immediate protection without global changes
## Technical Details
**Affected Tests:**
1. `vendor-grid-loads-with-empty-database` (lines 31-38)
2. `vendor-fetch-ids-returns-correct-structure` (lines 40-53)
3. `vendor-fetch-page-returns-vendors` (lines 55-69)
4. `vendor-hydrate-results-works` (lines 71-86)
5. `vendor-merge-transfers-references` (lines 92-117)
6. `vendor-merge-same-vendor-rejected` (lines 119-134)
7. `vendor-merge-invalid-vendor-handled` (lines 136-152)
8. `vendor-hydration-includes-all-fields` (lines 158-177)
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test # Ensure all tests pass
```
## Acceptance Criteria
- [ ] All 8 tests wrapped with Solr mocking
- [ ] Pattern matches accounts_test.clj exactly
- [ ] Tests continue to pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Code Review Agent
**Actions:**
- Identified missing Solr mocking during test pattern review
- Compared with accounts_test.clj implementation
- Created todo for tracking
**Learnings:**
- accounts_test.clj wraps every test with Solr mocking
- Pattern recognition specialist flagged this as inconsistency
- Important for test isolation and preventing side effects

View File

@@ -0,0 +1,178 @@
---
status: pending
priority: p1
issue_id: "008"
tags: [testing, architecture, refactoring, vendors, best-practices]
dependencies: []
---
# Refactor Tests to Focus on Behavior vs Implementation Details
## Problem Statement
The vendors test file tests internal implementation functions (`fetch-ids`, `hydrate-results`) rather than the public interface (`fetch-page`). This creates:
1. Brittle tests that break during refactoring
2. Tight coupling to internal structure
3. Violation of "Test user-observable behavior" principle
## Findings
**From architecture-strategist and kieran-rails-reviewer:**
**Tests exercising internal functions (lines 47, 80, 170):**
```clojure
;; Testing internal implementation
(sut/fetch-ids db {:query-params ...}) ; Internal query helper
(sut/hydrate-results [vendor-id] db {}) ; Internal hydration helper
```
**Problem:** These are intermediate functions used by `fetch-page`. Testing them directly:
- Couples tests to implementation details
- Makes refactoring harder (changing internal structure breaks tests)
- Violates testing conventions from AGENTS.md
**accounts_test.clj pattern - tests public interface:**
```clojure
;; Tests public behavior through account-save and fetch-page
(let [result (sut/account-save {:form-params ...})]
(is (= 200 (:status result))))
(let [[accounts matching-count] (sut/fetch-page {:query-params ...})]
(is (number? matching-count)))
```
## Proposed Solutions
### Option A: Remove Implementation Detail Tests (Recommended)
**Effort:** Small (15 minutes)
**Risk:** Low
Remove or refactor tests that directly test `fetch-ids` and `hydrate-results`:
1. **Remove:** `vendor-fetch-ids-returns-correct-structure` (lines 40-53)
- Already covered by `vendor-fetch-page-returns-vendors`
- Tests same functionality through public interface
2. **Remove:** `vendor-hydrate-results-works` (lines 71-86)
- Merge into `vendor-fetch-page-returns-vendors`
- Test hydration through `fetch-page` output
3. **Keep:** `vendor-hydration-includes-all-fields` (lines 158-177)
- Rename to `vendor-fetch-page-returns-complete-vendor-data`
- Test through `fetch-page` instead of `hydrate-results`
**Pros:**
- Follows accounts_test.clj pattern
- Tests are more resilient to refactoring
- Focuses on user-observable behavior
- Reduces test file size (~40 lines)
**Cons:**
- Slightly less granular test coverage
- May miss edge cases in internal functions
### Option B: Make Functions Private
**Effort:** Small (10 minutes)
**Risk:** Medium
Change `fetch-ids` and `hydrate-results` to private (`defn-`):
```clojure
(defn- fetch-ids [db request] ...)
(defn- hydrate-results [ids db _] ...)
```
Then test through `fetch-page`:
```clojure
(deftest vendor-fetch-page-works
(let [[vendors count] (sut/fetch-page request)]
;; This implicitly tests fetch-ids and hydrate-results
...))
```
**Pros:**
- Clearly signals these are implementation details
- Forces tests to use public interface
**Cons:**
- Requires modifying source file (vendors.clj)
- May break other code using these functions
- Risk of breaking changes
### Option C: Extract to Query Namespace
**Effort:** Medium (1 hour)
**Risk:** Medium
Create `auto-ap.queries.vendor` namespace:
```clojure
(ns auto-ap.queries.vendor
(:require [datomic.api :as dc]))
(defn fetch-ids [db query-params] ...)
(defn hydrate-results [ids db] ...)
```
Test in separate file with explicit contract tests.
**Pros:**
- Clear separation of concerns
- Query functions become public API of new namespace
- Follows single responsibility principle
**Cons:**
- Significant refactoring
- Requires updating all callers
- Overkill for current scope
## Recommended Action
**Go with Option A** - remove implementation detail tests and focus on behavior:
1. Delete `vendor-fetch-ids-returns-correct-structure` (covered by fetch-page test)
2. Delete `vendor-hydrate-results-works` (merge into fetch-page test)
3. Refactor `vendor-hydration-includes-all-fields` to use `fetch-page`
This aligns with:
- accounts_test.clj pattern
- testing-conventions skill guidelines
- "Test behavior, not implementation" principle
## Technical Details
**Affected Files:**
- `test/clj/auto_ap/ssr/admin/vendors_test.clj`
**Tests to Remove/Refactor:**
- Lines 40-53: `vendor-fetch-ids-returns-correct-structure` → REMOVE
- Lines 71-86: `vendor-hydrate-results-works` → REMOVE (merge assertions into fetch-page test)
- Lines 158-177: `vendor-hydration-includes-all-fields` → REFACTOR to use fetch-page
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test # All tests pass
lein cljfmt check # Formatting correct
```
## Acceptance Criteria
- [ ] `vendor-fetch-ids-returns-correct-structure` removed
- [ ] `vendor-hydrate-results-works` removed (assertions merged)
- [ ] `vendor-hydration-includes-all-fields` refactored to test through `fetch-page`
- [ ] Remaining tests focus on public interface (`fetch-page`, `merge-submit`)
- [ ] Tests still pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Architecture Strategist Agent
**Actions:**
- Identified implementation detail testing pattern
- Compared with accounts_test.clj public interface approach
- Created todo with multiple solution options
**Learnings:**
- testing-conventions skill emphasizes testing behavior not implementation
- accounts_test.clj only tests public functions (account-save, fetch-page)
- Internal function testing creates maintenance burden

View File

@@ -0,0 +1,160 @@
---
status: pending
priority: p2
issue_id: "009"
tags: [testing, patterns, consistency, vendors, datomic]
dependencies: []
---
# Standardize Temp ID Generation Pattern in vendors_test.clj
## Problem Statement
The vendors test file uses **inconsistent** temp ID generation patterns:
1. `(str "vendor-" (java.util.UUID/randomUUID))` in create-vendor helper
2. `(str "vendor-" (rand-int 100000))` in test bodies
3. `(str "vendor-source-" (rand-int 100000))` for merge tests
This inconsistency:
- Creates confusion about which pattern to use
- `rand-int` has collision risk (1 in 100,000 per test)
- Makes code harder to maintain
## Findings
**Inconsistent patterns identified by pattern-recognition-specialist:**
**Line 22:**
```clojure
(defn create-vendor ...
{:db/id (str "vendor-" (java.util.UUID/randomUUID)) ...})
```
**Lines 74, 96, 123, 140, 161:**
```clojure
(let [vendor-temp-id (str "vendor-" (rand-int 100000)) ...])
(let [source-temp-id (str "vendor-source-" (rand-int 100000)) ...])
```
**accounts_test.clj pattern:**
Uses `(rand-int 100000)` consistently throughout.
## Proposed Solutions
### Option A: Standardize on UUID (Recommended)
**Effort:** Small (10 minutes)
**Risk:** Low
Replace all `(rand-int 100000)` with `(java.util.UUID/randomUUID)`:
```clojure
;; Helper function
(defn- generate-temp-id [prefix]
(str prefix "-" (java.util.UUID/randomUUID)))
;; Usage
(let [vendor-temp-id (generate-temp-id "vendor") ...]
(let [source-temp-id (generate-temp-id "vendor-source") ...]
```
**Pros:**
- Virtually zero collision probability
- Consistent across all tests
- UUID is standard for unique IDs
**Cons:**
- Slightly longer IDs (but doesn't matter for tests)
- Different from accounts_test.clj pattern
### Option B: Standardize on rand-int (Matching accounts_test.clj)
**Effort:** Small (10 minutes)
**Risk:** Low
Change create-vendor to use rand-int:
```clojure
(defn create-vendor ...
{:db/id (str "vendor-" (rand-int 100000)) ...})
```
**Pros:**
- Matches accounts_test.clj exactly
- Shorter IDs
- Simpler
**Cons:**
- Collision risk (though statistically low)
- UUID is more standard for uniqueness
### Option C: Use Sequential IDs
**Effort:** Small (5 minutes)
**Risk:** Low
Use simple sequential pattern:
```clojure
;; No random generation needed
(let [vendor-temp-id "vendor-hydrate-test" ...])
```
**Pros:**
- Simplest possible
- No collision risk
- Self-documenting IDs
**Cons:**
- Different from accounts_test.clj
- Tests may fail if run concurrently (same IDs)
## Recommended Action
**Go with Option A** - standardize on UUID:
1. Create helper function for consistency
2. Update all test temp IDs to use UUID
3. Update create-vendor helper to use UUID
This provides the safest pattern with zero collision risk.
## Technical Details
**Affected Lines:**
- Line 22: create-vendor helper
- Lines 74, 96, 97, 123, 140, 161: Test temp IDs
**Implementation:**
```clojure
(defn- temp-id [prefix]
(str prefix "-" (java.util.UUID/randomUUID)))
;; Replace all instances:
(temp-id "vendor") ; instead of (str "vendor-" (rand-int 100000))
(temp-id "vendor-source") ; instead of (str "vendor-source-" (rand-int 100000))
(temp-id "vendor-target") ; etc.
```
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test
lein cljfmt check
```
## Acceptance Criteria
- [ ] Helper function created for temp ID generation
- [ ] All tests use consistent UUID-based temp IDs
- [ ] create-vendor helper updated
- [ ] Tests pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Pattern Recognition Specialist Agent
**Actions:**
- Identified inconsistent ID generation patterns
- Documented all occurrences
- Created todo for standardization
**Learnings:**
- accounts_test.clj uses rand-int consistently
- UUID provides better collision resistance
- Consistency across codebase is important for maintainability

View File

@@ -0,0 +1,172 @@
---
status: pending
priority: p2
issue_id: "010"
tags: [testing, helpers, refactoring, vendors, dry]
dependencies: []
---
# Replace Custom create-vendor Helper with test-vendor from util.clj
## Problem Statement
The vendors_test.clj defines a custom `create-vendor` helper (lines 18-25) that duplicates functionality already provided by `test-vendor` in `integration/util.clj`. This:
- Violates DRY principle
- Creates maintenance burden (two sources of truth)
- May diverge over time
## Findings
**From architecture-strategist and kieran-rails-reviewer:**
**Current custom helper (lines 18-25):**
```clojure
(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))
```
**Existing utility (util.clj lines 41-44):**
```clojure
(defn test-vendor [& kwargs]
(apply assoc {:db/id "vendor-id"
:vendor/name "Vendorson"
:vendor/default-account "test-account-id"}
kwargs))
```
**Usage comparison:**
```clojure
;; Current (vendors_test.clj):
(create-vendor "Test Vendor 1")
;; Could be (using test-vendor):
(test-vendor :vendor/name "Test Vendor 1")
```
**Note:** The only difference is `create-vendor` generates unique IDs while `test-vendor` uses static ID. For unique IDs, can use:
```clojure
(assoc (test-vendor :vendor/name "Test") :db/id (str "vendor-" (UUID/randomUUID)))
```
## Proposed Solutions
### Option A: Use test-vendor Directly (Recommended)
**Effort:** Small (15 minutes)
**Risk:** Low
Remove `create-vendor` and use `test-vendor` with assoc for unique IDs:
```clojure
;; Instead of:
(setup-test-data [(create-vendor "Test Vendor 1")])
;; Use:
(setup-test-data [(test-vendor :vendor/name "Test Vendor 1")])
;; For unique IDs:
(setup-test-data [(assoc (test-vendor :vendor/name "Test Vendor 1")
:db/id (str "vendor-" (UUID/randomUUID)))])
```
**Pros:**
- Single source of truth
- Follows existing util.clj pattern
- Removes duplication
**Cons:**
- More verbose for unique ID cases
- Need to import UUID
### Option B: Enhance test-vendor in util.clj
**Effort:** Small (10 minutes)
**Risk:** Low
Modify `test-vendor` to auto-generate unique IDs:
```clojure
(defn test-vendor [& kwargs]
(apply assoc {:db/id (str "vendor-" (java.util.UUID/randomUUID))
:vendor/name "Vendorson"
:vendor/default-account "test-account-id"}
kwargs))
```
Then vendors_test.clj simply calls `(test-vendor :vendor/name "Test")`.
**Pros:**
- Improves utility for all test files
- No local helper needed
**Cons:**
- May break existing tests expecting static ID
- Requires updating util.clj (affects all tests)
### Option C: Create Named Vendor Helper
**Effort:** Small (5 minutes)
**Risk:** Low
Keep local helper but use test-vendor internally:
```clojure
(defn vendor-with-name [name]
(test-vendor :vendor/name name))
```
**Pros:**
- Shorter than test-vendor call
- Uses existing utility
**Cons:**
- Still have local helper
- Less explicit than using test-vendor directly
## Recommended Action
**Go with Option A** - use `test-vendor` directly:
1. Remove `create-vendor` helper
2. Update all usages to use `test-vendor`
3. Use `assoc` for unique IDs where needed
This follows DRY principle and uses established patterns.
## Technical Details
**Affected Code:**
- Lines 18-25: Remove `create-vendor` function
- Lines 43-44, 58-59, 75-76, 98-101, etc.: Replace usages
**Files:**
- `test/clj/auto_ap/ssr/admin/vendors_test.clj`
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test
lein cljfmt check
```
## Acceptance Criteria
- [ ] `create-vendor` helper removed
- [ ] All usages replaced with `test-vendor`
- [ ] Unique IDs handled with `assoc` where needed
- [ ] Tests pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Architecture Strategist Agent
**Actions:**
- Identified duplicate helper function
- Compared with existing test-vendor utility
- Documented usage patterns
**Learnings:**
- DRY principle violation in test helpers
- test-vendor already provides same functionality
- Small duplication can create maintenance burden

View File

@@ -0,0 +1,137 @@
---
status: pending
priority: p3
issue_id: "011"
tags: [testing, readability, agents, vendors, assertions]
dependencies: []
---
# Add Assertion Messages to Improve Agent-Readable Test Output
## Problem Statement
Most assertions in vendors_test.clj lack custom messages, making failures hard for automated agents to interpret and debug. Adding messages would:
- Improve automated failure analysis
- Make test output self-documenting
- Help future developers understand failures
## Findings
**From agent-native-reviewer:**
**Current assertions without messages:**
```clojure
(is (seq? vendors))
(is (number? matching-count))
(is (= 0 (count vendors)))
(is (contains? result :ids))
```
**Better with messages:**
```clojure
(is (seq? vendors) "Expected vendors to be a sequence")
(is (number? matching-count) "Expected matching-count to be a number, got: %s" (type matching-count))
(is (= 0 (count vendors)) "Expected empty vendor list when database is empty, found %d vendors" (count vendors))
```
**Benefits:**
- Agents can understand what went wrong without reading code
- Self-documenting test output
- Easier debugging when tests fail
## Proposed Solutions
### Option A: Add Messages to All Assertions (Recommended)
**Effort:** Small (20 minutes)
**Risk:** Low
Add descriptive messages to all `is` assertions:
```clojure
;; Before:
(is (= 200 (:status result)))
;; After:
(is (= 200 (:status result))
"Expected 200 status, got %d" (:status result))
```
**Pros:**
- Maximum clarity for agents and humans
- Self-documenting failures
**Cons:**
- Adds verbosity
- More code to maintain
### Option B: Add Messages to Complex Assertions Only
**Effort:** Small (10 minutes)
**Risk:** Low
Only add messages to non-obvious assertions:
```clojure
;; Keep simple assertions as-is:
(is (= 200 (:status result)))
;; Add messages to complex ones:
(is (>= (:count result) 3)
"Expected at least 3 vendors (2 new + 1 from setup), got %d"
(:count result))
```
**Pros:**
- Less verbose
- Focus on non-obvious assertions
**Cons:**
- Inconsistent coverage
- Agents still can't understand simple failures
## Recommended Action
**Go with Option B** - add messages to complex/value-checking assertions first. This provides the most value with less overhead.
Priority assertions to enhance:
1. Lines 53, 64: Magic number assertions with `>=`
2. Lines 110, 117: Status code and count assertions
3. Lines 176-177: Field value assertions
## Technical Details
**High-Priority Assertions:**
- Line 53: `(is (>= (:count result) 3))`
- Line 64: `(is (>= matching-count 3))`
- Line 110: `(is (= 200 (:status result)))`
- Line 117: `(is (= 0 (count remaining-sources)))`
**Message format:**
```clojure
(is assertion "Expected X, got Y: %s" value)
```
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test # Test failure messages
```
## Acceptance Criteria
- [ ] Complex assertions have descriptive messages
- [ ] Messages explain expected vs actual values
- [ ] Tests still pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Agent-Native Reviewer Agent
**Actions:**
- Identified lack of assertion messages
- Documented benefits for automated agents
- Prioritized which assertions need messages most
**Learnings:**
- Assertion messages critical for agent-based development
- Most assertions in file lack messages
- Focus on complex/value-checking assertions first

View File

@@ -0,0 +1,142 @@
---
status: pending
priority: p3
issue_id: "012"
tags: [testing, error-handling, patterns, vendors, assertions]
dependencies: []
---
# Improve Error Testing Pattern for Validation Errors
## Problem Statement
The vendor merge same-vendor test uses `thrown-with-msg?` which only checks the error message string. The accounts_test.clj pattern uses try/catch with `ex-data` assertions, which is more robust and tests the structured error data, not just the message.
## Findings
**From kieran-rails-reviewer:**
**Current vendors_test.clj pattern (lines 129-130):**
```clojure
(is (thrown-with-msg? clojure.lang.ExceptionInfo
#"Please select two different vendors"
(sut/merge-submit ...)))
```
**accounts_test.clj pattern (lines 45-58):**
```clojure
(try
(sut/account-save {...})
(is false "Should have thrown validation error")
(catch clojure.lang.ExceptionInfo e
(let [data (ex-data e)]
(is (= :field-validation (:type data)))
(is (contains? (:form-errors data) :account/numeric-code))
(is (str/includes? (get-in (:form-errors data) [:account/numeric-code])
"already in use")))))
```
**Benefits of accounts_test.clj pattern:**
- Tests structured error data, not just message
- More specific about what failed
- Can assert on error type and field-specific errors
- Less brittle (message strings can change)
## Proposed Solutions
### Option A: Use try/catch Pattern (Recommended)
**Effort:** Small (10 minutes)
**Risk:** Low
Refactor same-vendor merge test to use try/catch:
```clojure
(deftest vendor-merge-same-vendor-rejected
(testing "Vendor merge should reject when source and target are the same"
(let [admin-identity (admin-token)
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)]
(try
(sut/merge-submit {:form-params {:source-vendor vendor-id
:target-vendor vendor-id}
:request-method :put
:identity admin-identity})
(is false "Should have thrown validation error for same vendor merge")
(catch clojure.lang.ExceptionInfo e
(let [data (ex-data e)]
(is (= :form-validation (:type data)))
(is (str/includes? (:form-validation-errors data)
"Please select two different vendors"))))))))
```
**Pros:**
- More robust error testing
- Matches accounts_test.clj pattern
- Tests structured error data
**Cons:**
- More verbose
- Requires checking source code for error structure
### Option B: Keep Current Pattern
**Effort:** None
**Risk:** Low
Leave as-is with `thrown-with-msg?`.
**Pros:**
- Already working
- Simpler code
**Cons:**
- Less robust
- Only tests message string
- Different from accounts_test.clj
## Recommended Action
**Go with Option A** - use try/catch pattern with `ex-data` assertions. This provides more robust testing and matches the accounts_test.clj convention.
## Technical Details
**Affected Test:**
- Lines 119-134: `vendor-merge-same-vendor-rejected`
**Source Investigation:**
Need to check vendors.clj or utils.clj to see the actual error structure:
```clojure
;; Check what ex-data contains:
(catch clojure.lang.ExceptionInfo e
(println (ex-data e)) ; Inspect the structure
...)
```
**Verification:**
```bash
lein test auto-ap.ssr.admin.vendors-test/vendor-merge-same-vendor-rejected
```
## Acceptance Criteria
- [ ] Test uses try/catch pattern
- [ ] Assertions check `ex-data` structure
- [ ] Error type and fields verified
- [ ] Tests pass
- [ ] Code formatted with lein cljfmt
## Work Log
### 2026-02-07 - Initial Creation
**By:** Kieran Rails Reviewer Agent
**Actions:**
- Compared error testing patterns
- Identified inconsistency with accounts_test.clj
- Documented benefits of structured error testing
**Learnings:**
- accounts_test.clj uses try/catch with ex-data
- thrown-with-msg? is less robust
- Error structure testing provides better validation