Files
integreat/docs/plans/2026-02-06-feat-add-tests-for-ssr-admin-vendors-plan.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

460 lines
17 KiB
Markdown

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