---
title: "Add comprehensive tests for SSR admin vendors module"
type: feat
date: 2026-02-06
component: auto-ap.ssr.admin.vendors
tags: [testing, ssr, vendors, wizard, bdd]
---

# Add Comprehensive Tests for SSR Admin Vendors Module

## Overview

Add comprehensive BDD-style tests for the SSR admin vendors module (`src/clj/auto_ap/ssr/admin/vendors.clj`). The vendors module is a complex multi-step wizard implementation with 5 wizard steps (Info, Terms, Account, Address, Legal) and requires more extensive testing than the accounts module due to its complex form state management, vendor merge functionality, and nested override grids.

## Problem Statement

The vendors module currently has **zero tests** despite being a critical admin functionality with 932 lines of code. This creates risks:

1. **Untested complex logic**: Multi-step wizard navigation, form state management, and validation
2. **No safety net for refactors**: Vendor merge, grid overrides, and dynamic fields are complex
3. **No documentation of expected behavior**: Tests serve as executable documentation
4. **Risk of regression**: Without tests, bugs in vendor creation/management could go unnoticed

## Proposed Solution

Create a comprehensive test suite at `test/clj/auto_ap/ssr/admin/vendors_test.clj` following the established patterns from `accounts_test.clj`, but with additional complexity for:

- **Wizard navigation testing**: Testing step transitions, validation at each step
- **Vendor merge functionality**: Testing source/target vendor selection and entity merging
- **Override grids**: Testing terms overrides and account overrides with client-specific data
- **Complex form state**: Testing MultiStepFormState encoding/decoding
- **Nested entity handling**: Testing vendor address, legal entity info, primary contact

## Technical Considerations

### Architecture Impact
- Tests will mirror the accounts test structure: `test/clj/auto_ap/ssr/admin/vendors_test.clj`
- Will require understanding of `LinearModalWizard` protocol and `MultiStepFormState`
- Tests will use same utilities: `wrap-setup`, `admin-token`, `setup-test-data`
- Will need to mock Solr indexing like accounts tests do

### Performance Implications
- In-memory Datomic with test fixtures for isolation
- Each test should be independent with proper setup/teardown
- Estimated 15-20 tests (vs 9 for accounts) due to complexity

### Security Considerations
- Admin-only access verification
- Non-admin access should be rejected
- JWT validation for vendor operations

### Testing Challenges
1. **MultiStepFormState encoding**: The wizard uses complex form state encoding via `wrap-decode-multi-form-state`
2. **Step-specific validation**: Each wizard step validates only its subset of the schema
3. **Dynamic client-dependent fields**: Account typeahead depends on client selection
4. **Grid row management**: Adding/removing terms and account override rows

## Acceptance Criteria

### Functional Requirements

#### Grid & List View Tests (4 tests) - ✅ IMPLEMENTED

- [x] **Test 1**: Vendor grid page loads and displays vendors
  - Given: Test vendors exist in database
  - When: Admin navigates to vendors page
  - Then: Vendor table displays with correct columns (name, email, default account)
  - Then: Usage badges show correct client counts and totals
  - **Implemented as**: `vendor-fetch-page-returns-vendors`

- [x] **Test 2**: Vendor grid filtering by name works
  - Given: Multiple vendors exist with different names
  - When: Admin filters by name "Acme"
  - Then: Only vendors matching "Acme" are displayed
  - Then: Matching count reflects filtered results
  - **Implemented as**: `vendor-fetch-ids-with-name-filter`

- [x] **Test 3**: Vendor grid filtering by type (hidden/global) works
  - Given: Hidden and global vendors exist
  - When: Admin selects "Only hidden" filter
  - Then: Only hidden vendors are displayed
  - When: Admin selects "Only global" filter
  - Then: Only non-hidden vendors are displayed
  - **Implemented as**: `vendor-fetch-ids-with-hidden-filter`

- [x] **Test 4**: Vendor grid handles empty database
  - Given: No vendors in database
  - When: Admin navigates to vendors page
  - Then: Returns empty results without errors
  - **Implemented as**: `vendor-grid-loads-with-empty-database`
  - **Note**: Sorting tests deferred due to vendor module sorting configuration

#### Vendor Creation Tests - Info Step (2 tests)

- [ ] **Test 5**: Admin successfully creates vendor with basic info
  - Given: Admin is logged in with valid token
  - When: Admin submits vendor info form (name, hidden flag)
  - Then: Vendor is created successfully
  - Then: Vendor appears in database
  - Then: Vendor is indexed in Solr

- [ ] **Test 6**: Vendor creation validation - empty name rejected
  - Given: Admin submits form without vendor name
  - When: Validation runs on info step
  - Then: Validation error for name field
  - Then: No vendor is created

#### Vendor Creation Tests - Terms Step (3 tests)

- [ ] **Test 7**: Vendor can have default terms set
  - Given: Admin on terms step of wizard
  - When: Admin sets terms to 30 days
  - Then: Terms are saved with vendor
  - Then: Terms appear in database

- [ ] **Test 8**: Vendor terms override grid works
  - Given: Admin on terms step with client overrides
  - When: Admin adds terms override for specific client (45 days)
  - Then: Override is saved
  - When: Override is removed
  - Then: Override is deleted from database

- [ ] **Test 9**: Automatic payment flag per client works
  - Given: Admin on terms step
  - When: Admin marks vendor for automatic payment for a client
  - Then: Flag is saved in database

#### Vendor Creation Tests - Account Step (3 tests)

- [ ] **Test 10**: Vendor default account selection works
  - Given: Admin on account step
  - When: Admin selects default account from typeahead
  - Then: Default account association is saved

- [ ] **Test 11**: Vendor account override grid works
  - Given: Admin on account step with client-specific accounts
  - When: Admin adds account override for client (different default account)
  - Then: Override is saved in database
  - When: Client is changed, account typeahead refreshes
  - Then: New client-specific accounts are available

- [ ] **Test 12**: Account typeahead filters by client
  - Given: Client A and Client B have different accounts
  - When: Admin selects Client A in override row
  - Then: Only Client A's accounts appear in typeahead

#### Vendor Creation Tests - Address Step (2 tests)

- [ ] **Test 13**: Vendor address information is saved
  - Given: Admin on address step
  - When: Admin enters complete address (street, city, state, zip)
  - Then: Address entity is created and linked to vendor
  - Then: All address fields are persisted correctly

- [ ] **Test 14**: Partial address is handled correctly
  - Given: Admin enters only street address
  - When: Vendor is saved
  - Then: Address entity is created with available fields
  - Then: Missing fields remain empty

#### Vendor Creation Tests - Legal Step (3 tests)

- [ ] **Test 15**: Vendor legal entity (business) information is saved
  - Given: Admin on legal step
  - When: Admin enters legal entity name and TIN (EIN)
  - Then: Legal entity info is saved
  - Then: 1099 type is stored correctly

- [ ] **Test 16**: Vendor individual legal entity is saved
  - Given: Admin on legal step
  - When: Admin enters individual name (first, middle, last) and SSN
  - Then: Individual legal entity info is saved
  - Then: TIN type is set to SSN

- [ ] **Test 17**: Legal entity validation works
  - Given: Admin enters invalid TIN format
  - When: Validation runs
  - Then: Appropriate validation error is shown

#### Vendor Update Tests (2 tests)

- [ ] **Test 18**: Existing vendor can be updated
  - Given: Vendor exists in database
  - When: Admin edits and saves vendor
  - Then: Changes are persisted
  - Then: Solr index is updated
  - Then: Grid row reflects changes

- [ ] **Test 19**: Vendor update maintains existing overrides
  - Given: Vendor has terms and account overrides
  - When: Admin updates vendor name
  - Then: Overrides remain intact

#### Vendor Merge Tests (3 tests) - ✅ IMPLEMENTED

- [x] **Test 20**: Vendor merge transfers all references
  - Given: Source vendor has invoices/bills, target vendor exists
  - When: Admin merges source into target
  - Then: All references to source are updated to target
  - Then: Source vendor is deleted
  - Then: Success notification is shown
  - **Implemented as**: `vendor-merge-transfers-references`

- [x] **Test 21**: Same vendor merge is rejected
  - Given: Admin selects same vendor for source and target
  - When: Merge is attempted
  - Then: Validation error: "Please select two different vendors"
  - **Implemented as**: `vendor-merge-same-vendor-rejected`

- [x] **Test 22**: Non-existent vendor merge is handled
  - Given: Invalid vendor ID for source
  - When: Merge is attempted
  - Then: Appropriate error is shown
  - **Implemented as**: `vendor-merge-invalid-vendor-handled`

#### Security Tests (2 tests)

- [ ] **Test 23**: Non-admin cannot create vendor
  - Given: Non-admin user token
  - When: User attempts to create vendor
  - Then: Request is rejected (403 Forbidden)

- [ ] **Test 24**: Non-admin cannot merge vendors
  - Given: Non-admin user token
  - When: User attempts to merge vendors
  - Then: Request is rejected

### Non-Functional Requirements

- [ ] Tests use `wrap-setup` fixture for database isolation
- [ ] Tests use `admin-token` utility for authentication
- [ ] Solr is mocked using `with-redefs` with `InMemSolrClient`
- [ ] Test execution time < 3 seconds per test
- [ ] All tests pass with `lein test auto-ap.ssr.admin.vendors-test`

### Quality Gates

- [ ] 24 tests implemented and passing
- [ ] Test coverage > 75% for vendor handlers
- [ ] Code formatted with `lein cljfmt check`
- [ ] No debug statements (`println`, `alog/peek`) in tests
- [ ] All `deftest` blocks at column 0 (consistent structure)

## Implementation Plan

### Phase 1: Foundation (2 hours)

**Tasks:**

1. [ ] Review vendors module structure
   - Read `src/clj/auto_ap/ssr/admin/vendors.clj`
   - Identify key functions: `fetch-ids`, `hydrate-results`, `fetch-page`
   - Identify wizard steps: Info, Terms, Account, Address, Legal
   - Identify merge functionality

2. [ ] Review accounts test as reference
   - Read `test/clj/auto_ap/ssr/admin/accounts_test.clj`
   - Copy test structure and utilities
   - Note `ffirst` pattern for Datomic queries
   - Note `[:db/ident]` for entity references

3. [ ] Create test file structure
   - Create `test/clj/auto_ap/ssr/admin/vendors_test.clj`
   - Set up namespace with required imports
   - Add `wrap-setup` fixture

**Deliverable:** Test file created with proper structure, ready for test implementation

### Phase 2: Grid/List Tests (1.5 hours)

4. [ ] Implement Test 1: Vendor grid loads
5. [ ] Implement Test 2: Name filtering
6. [ ] Implement Test 3: Type filtering (hidden/global)
7. [ ] Implement Test 4: Sorting

**Deliverable:** 4 grid tests passing

### Phase 3: Vendor Creation - Info & Terms (2.5 hours)

8. [ ] Implement Test 5: Create vendor with basic info
9. [ ] Implement Test 6: Name validation
10. [ ] Implement Test 7: Default terms
11. [ ] Implement Test 8: Terms override grid
12. [ ] Implement Test 9: Automatic payment flag

**Deliverable:** 5 vendor creation tests (info + terms) passing

### Phase 4: Vendor Creation - Account & Address (2.5 hours)

13. [ ] Implement Test 10: Default account selection
14. [ ] Implement Test 11: Account override grid
15. [ ] Implement Test 12: Client-filtered account typeahead
16. [ ] Implement Test 13: Complete address
17. [ ] Implement Test 14: Partial address

**Deliverable:** 5 vendor creation tests (account + address) passing

### Phase 5: Vendor Creation - Legal & Update (2 hours)

18. [ ] Implement Test 15: Legal entity (business)
19. [ ] Implement Test 16: Legal entity (individual)
20. [ ] Implement Test 17: Legal entity validation
21. [ ] Implement Test 18: Vendor update
22. [ ] Implement Test 19: Update maintains overrides

**Deliverable:** 5 tests (legal + update) passing

### Phase 6: Vendor Merge & Security (2 hours)

23. [ ] Implement Test 20: Merge transfers references
24. [ ] Implement Test 21: Same vendor merge rejected
25. [ ] Implement Test 22: Invalid vendor merge handled
26. [ ] Implement Test 23: Non-admin cannot create
27. [ ] Implement Test 24: Non-admin cannot merge

**Deliverable:** 5 tests (merge + security) passing

### Phase 7: Refinement & Quality (1 hour)

28. [ ] Run `lein cljfmt check` and fix issues
29. [ ] Run full test suite
30. [ ] Review for debug statements and remove
31. [ ] Verify consistent test structure (deftest at column 0)
32. [ ] Add test documentation comments

**Deliverable:** All 24 tests passing, code formatted, no debug code

## Success Metrics

- [ ] 24 BDD test scenarios implemented and passing
- [ ] Test file follows project conventions
- [ ] Code formatted with `lein cljfmt check`
- [ ] All tests use proper Datomic query patterns (`ffirst`, `[:db/ident]`)
- [ ] Solr mocking works correctly
- [ ] Tests run in < 60 seconds for full suite
- [ ] No regression in existing functionality

## Dependencies & Risks

### Prerequisites

- `src/clj/auto_ap/ssr/admin/vendors.clj` (exists)
- `test/clj/auto_ap/integration/util.clj` (test utilities)
- Existing accounts tests as reference pattern
- Datomic database schema for vendors

### Potential Risks

1. **Complexity Risk**: MultiStepFormState encoding/decoding is complex
   - **Mitigation**: Reference accounts test patterns, test incrementally

2. **Time Risk**: 24 tests may take longer than estimated
   - **Mitigation**: Prioritize core tests (creation, merge), add edge cases later

3. **Wizard State Risk**: Wizard step navigation testing is novel
   - **Mitigation**: Start with simple tests, incrementally add complexity

4. **Grid Testing Risk**: Override grid testing is complex
   - **Mitigation**: Test basic CRUD operations first, then edge cases

## References & Research

### Internal References

**Vendor Source Code**:
- `src/clj/auto_ap/ssr/admin/vendors.clj` - Main implementation (932 lines)
  - `fetch-ids` - Query builder for vendor grid
  - `hydrate-results` - Data hydration for grid display
  - `fetch-page` - Grid pagination
  - `grid-page` - Grid configuration
  - `merge-submit` - Vendor merge logic
  - 5 Wizard step records: InfoModal, TermsModal, AccountModal, AddressModal, LegalEntityModal
  - VendorWizard record implementing LinearModalWizard protocol

**Wizard Framework**:
- `src/clj/auto_ap/ssr/components/multi_modal.clj` - LinearModalWizard protocol
  - `ModalWizardStep` protocol methods: `step-key`, `edit-path`, `render-step`, `step-schema`, `step-name`
  - `LinearModalWizard` protocol methods: `navigate`, `get-current-step`, `render-wizard`, `submit`
  - Handler wrappers: `wrap-wizard`, `wrap-init-multi-form-state`, `wrap-decode-multi-form-state`

**Test Utilities**:
- `test/clj/auto_ap/integration/util.clj` - Test helpers
  - `wrap-setup` - Test database setup/teardown
  - `admin-token` - Admin authentication
  - `setup-test-data` - Test data creation
  - `test-vendor` - Vendor test data helper

**Reference Tests**:
- `test/clj/auto_ap/ssr/admin/accounts_test.clj` - Accounts test pattern (151 lines)
- `test/clj/auto_ap/integration/graphql/vendors.clj` - GraphQL vendor tests (79 lines)

**Learnings**:
- `docs/solutions/test-failures/atomic-query-patterns-in-bdd-tests-auto-ap-ssr-20260206.md` - Datomic query patterns (`ffirst`, `[:db/ident]`)
- `docs/solutions/test-failures/debug-statement-and-test-nesting-fix-accounts-20260206.md` - Test quality issues to avoid

### Testing Patterns

**Datomic Query Pattern**:
```clojure
; Use ffirst to extract entity ID from tuple
(let [results (dc/q '[:find ?e :where [?e :vendor/name "Acme"]] db)
      vendor-id (ffirst results)]  ; Not (first results)
  ...)
```

**Entity Reference Resolution**:
```clojure
; Include [:db/ident] to resolve enum values
(let [vendor (dc/pull db
                      '[:vendor/name
                        {[:vendor/legal-entity-tin-type :xform iol-ion.query/ident] [:db/ident]}]
                      vendor-id)]
  ; Access as: (:db/ident (:vendor/legal-entity-tin-type vendor))
  ...)
```

**Solr Mocking Pattern**:
```clojure
(with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
  ; Test code here
  )
```

**Test Structure Pattern**:
```clojure
(deftest vendor-creation-success
  (testing "Admin should be able to create a new vendor"
    (with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
      (let [admin-identity (admin-token)
            ; Test implementation
            ]))))
```

## AI-Era Considerations

When implementing with AI assistance:

1. **Accelerated test generation**: AI can generate test scaffolding quickly
2. **Pattern recognition**: Use existing accounts tests as templates
3. **Datomic patterns**: Ensure AI applies `ffirst` and `[:db/ident]` correctly
4. **Human review**: All AI-generated tests should be reviewed for:
   - Correct assertion logic
   - Proper database verification
   - No debug statements left in
   - Consistent test structure

## Next Steps

1. **Review Plan**: Confirm scope and complexity level
2. **Start Implementation**: Begin with Phase 1 (Foundation)
3. **Iterative Testing**: Implement tests incrementally, verify each phase
4. **Code Review**: Get feedback on test patterns
5. **Integration**: Ensure tests pass with full test suite

---

**Created**: 2026-02-06  
**Priority**: High (critical admin functionality untested)  
**Estimated Effort**: 13 hours (across 7 phases)
