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