---
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
