Files
integreat/docs/plans/2026-02-06-feat-add-bdd-tests-for-admin-financial-account-creation-ssr-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

26 KiB

title: feat: Add BDD tests for admin financial account creation (ssr) type: feat date: 2026-02-06

Add BDD Tests for Admin Financial Account Creation (SSR)

Overview

This feature aims to add Behavior-Driven Development (BDD) tests for admin users creating financial accounts using Server-Side Rendering (SSR). The tests will cover the complete account creation flow, validation logic, duplicate detection, and Solr indexing integration.

Problem Statement

Currently, the project lacks BDD-style tests for admin financial account creation. Tests exist using Clojure.test but follow a unit/integration pattern rather than BDD Given-When-Then scenarios. This creates several challenges:

  1. Unclear test intent: Tests verify database state directly without clear behavioral descriptions
  2. Difficulty for new developers: BDD scenarios provide clearer user flow documentation
  3. Limited edge case coverage: Current tests may miss important business logic edge cases
  4. No validation testing: Duplicate detection and validation logic lacks comprehensive test coverage

Proposed Solution

Implement BDD-style tests for admin financial account creation following project conventions. Tests will:

  • Use Given-When-Then structure for clear behavioral descriptions
  • Test both success and failure scenarios
  • Verify database state changes after operations
  • Test Solr indexing after account creation
  • Test authorization (admin-only access)
  • Cover validation errors and duplicate detection

Technical Considerations

Architecture Impact

  • Tests will be added to test/clj/auto_ap/ssr/admin/accounts_test.clj
  • Tests will use existing test utilities: wrap-setup, admin-token, setup-test-data
  • Tests will verify database state using Datomic dc/pull and dc/q
  • Tests will follow project convention of testing user-observable behavior

Performance Implications

  • Tests will use in-memory Datomic for fast iteration
  • Each test will run independently with its own setup/teardown
  • Solr indexing will be tested in-memory (using mocked Solr client)

Security Considerations

  • Tests will use admin tokens (admin-token utility)
  • Non-admin access attempts will be tested and rejected
  • JWT validation will be tested for proper authorization

Acceptance Criteria

Functional Requirements

  • Test 1: Admin successfully creates account with valid data

    • Given: Admin is logged in with valid token
    • When: Admin submits valid account creation form
    • Then: Account is created successfully in database
    • Then: Account appears in account table
    • Then: Account is indexed in Solr search
  • Test 2: Account appears in database with correct attributes

    • Given: Account was created
    • When: Account is queried from database
    • Then: Account has correct numeric code, name, type, location
    • Then: Account has auto-generated ID
    • Then: Account timestamps are set correctly
  • Test 3: Validation errors for invalid data

    • Given: Admin submits invalid account form
    • When: Form validation fails
    • Then: Appropriate validation error is shown
    • Then: No account is created
  • Test 4: Duplicate numeric code detection

    • Given: Account with same numeric code already exists
    • When: Admin submits form with duplicate code
    • Then: Duplicate check fails
    • Then: Validation error is shown
    • Then: No account is created
  • Test 5: Duplicate account name detection

    • Given: Account with same name already exists
    • When: Admin submits form with duplicate name
    • Then: Duplicate check fails
    • Then: Validation error is shown
    • Then: No account is created
  • Test 6: Account searchability in Solr

    • Given: Account was created
    • When: Solr query is performed
    • Then: Account appears in search results
    • Then: Can search by numeric code
    • Then: Can search by account name
  • Test 7: Non-admin access is denied

    • Given: Non-admin user token
    • When: Non-admin attempts to create account
    • Then: Request is rejected with 403 Forbidden
    • Then: No account is created
  • Test 8: Client override validation

    • Given: Account creation form includes client overrides
    • When: Overrides contain duplicate client names
    • Then: Validation error is shown
    • Then: No account is created
  • Test 9: Account update functionality

    • Given: Account exists in database
    • When: Admin updates account attributes
    • Then: Account is updated successfully
    • Then: Solr index is updated
    • Then: Account in table reflects changes

Non-Functional Requirements

  • Tests use existing test utilities (wrap-setup, admin-token, etc.)
  • Tests follow project BDD style conventions
  • Tests verify user-observable behavior (database state)
  • Tests are isolated with proper setup/teardown
  • Test execution time < 5 seconds per test
  • Tests use lein test selector for running

Quality Gates

  • Test coverage for account creation flow > 80%
  • All tests pass on initial run
  • Tests run with lein test :integration and lein test :functional
  • Test file follows project naming conventions (auto-ap.ssr.admin.accounts-test)
  • Code formatting verified with lein cljfmt check

Success Metrics

  • 9 BDD test scenarios implemented and passing
  • Clear Given-When-Then documentation for each test
  • Tests cover happy path, validation errors, and edge cases
  • No regression in existing account creation functionality
  • Tests provide clear documentation for developers
  • Tests can be run in parallel without conflicts

Dependencies & Risks

Prerequisites

  • Existing Datomic database schema for accounts
  • Existing SSR admin module (src/clj/auto_ap/ssr/admin/accounts.clj)
  • Existing test utilities in test/clj/auto_ap/integration/util.clj
  • In-memory Solr client for testing

Potential Risks

  1. Time Risk: Comprehensive BDD test coverage may take longer than estimated

    • Mitigation: Focus on critical tests first, add edge cases in follow-up PRs
  2. Complexity Risk: Solr indexing may be difficult to test in isolation

    • Mitigation: Use mocked Solr client with in-memory index
  3. Regression Risk: New tests may fail due to changes in production code

    • Mitigation: Run full test suite after each test implementation
    • Mitigation: Use feature flags for test environment
  4. Duplicate Detection Complexity: Duplicate check logic may have edge cases

    • Mitigation: Review existing implementation, add targeted tests for each edge case

Implementation Plan

Phase 1: Foundation (1-2 hours)

Tasks:

  1. Review existing account creation code

    • Read src/clj/auto_ap/ssr/admin/accounts.clj
    • Identify account-save function and validation logic
    • Identify duplicate check logic
    • Identify Solr indexing logic
  2. Review existing test patterns

    • Read test/clj/auto_ap/ssr/invoice/new_invoice_wizard_test.clj
    • Read test/clj/auto_ap/integration/graphql/accounts.clj
    • Understand wrap-setup, admin-token, setup-test-data utilities
    • Review test structure and conventions
  3. Create test directory structure

    • Create test/clj/auto_ap/ssr/admin/ directory if not exists
    • Verify namespace conventions and naming

Deliverable:

  • Clear understanding of account creation flow
  • Test file template created
  • Setup environment ready

Phase 2: Core Tests (3-4 hours)

Task 1: Account Creation Success Test

  1. Create basic test structure

    • Create test/clj/auto_ap/ssr/admin/accounts_test.clj
    • Define namespace with required imports
    • Set up test fixtures (wrap-setup, admin-token)
  2. Implement Test 1: Admin creates account successfully

    (deftest account-creation-success
      (testing "Admin should be able to create a new financial account"
        ;; Given: Admin is logged in
        (let [admin-identity (admin-token)]
    
          ;; When: Admin submits valid account creation form
          (let [form-params {:account/numeric-code 12345
                             :account/name "New Cash Account"
                             :account/type :account-type/asset
                             :account/location "B"
                             :account/default-allowance :allowance/allowed}
                result (sut/account-save {:form-params form-params
                                          :request-method :post
                                          :identity admin-identity})]
    
            ;; Then: Account should be created successfully
            (is (= :success (:status result)))
    
            ;; And: Account should appear in database
            (let [db-after (dc/db conn)
                  created-account (dc/pull db-after
                                           '[:db/id
                                             :account/code
                                             :account/name
                                             :account/numeric-code
                                             :account/location
                                             :account/type
                                             {[:account/type :xform iol-ion.query/ident] :db/ident}]
                                           (get result [:tempids "new"]))]
              (is (= 12345 (:account/numeric-code created-account)))
              (is (= "New Cash Account" (:account/name created-account)))))))
    
  3. Verify Test 1 passes

    • Run lein test auto-ap.ssr.admin.accounts-test/account-creation-success
    • Fix any failures
    • Verify test output is clear

Deliverable:

  • Test 1 passes successfully
  • Basic test framework in place

Task 2: Account Database Verification Test

  1. Implement Test 2: Account appears in database

    (deftest account-appears-in-database
      (testing "Created account should have correct attributes in database"
        (let [admin-identity (admin-token)
              form-params {:account/numeric-code 12346
                           :account/name "Cash Account"
                           :account/type :account-type/asset
                           :account/location "C"}
              result @(sut/account-save {:form-params form-params
                                          :request-method :post
                                          :identity admin-identity})]
          ;; Then: Account has correct attributes
          (let [db-after (dc/db conn)
                account-id (get result [:tempids "new"])
                account (dc/pull db-after
                                 '[:db/id
                                   :account/code
                                   :account/name
                                   :account/numeric-code
                                   :account/location
                                   :account/type]
                                 account-id)]
            (is (= "Cash Account" (:account/name account)))
            (is (= 12346 (:account/numeric-code account)))
            (is (= "C" (:account/location account)))))))
    
  2. Implement helper function for cleanup

    • Create setup-account-with-code helper function
    • Create teardown logic to remove test accounts
    • Use test fixture for automatic cleanup
  3. Verify Test 2 passes

    • Run test
    • Fix failures
    • Test cleanup works correctly

Deliverable:

  • Test 2 passes successfully
  • Cleanup helper functions implemented

Task 3: Validation Error Tests

  1. Implement Test 3: Empty name validation error

    (deftest account-creation-validation-error-empty-name
      (testing "Should show validation error when name is empty"
        (let [admin-identity (admin-token)
              form-params {:account/numeric-code 12347
                           :account/name ""
                           :account/type :account-type/asset}
              result (sut/account-save {:form-params form-params
                                         :request-method :post
                                         :identity admin-identity})]
          (is (not= :success (:status result)))
          (is (some #(str/includes? (first %) "Name") (:form-errors result)))))))
    
  2. Implement Test 4: Invalid account type validation error

    (deftest account-creation-validation-error-invalid-type
      (testing "Should show validation error when account type is invalid"
        (let [admin-identity (admin-token)
              form-params {:account/numeric-code 12348
                           :account/name "Test Account"
                           :account/type :account-type/invalid-type}
              result (sut/account-save {:form-params form-params
                                         :request-method :post
                                         :identity admin-identity})]
          (is (not= :success (:status result)))
          (is (some #(str/includes? (first %) "Type") (:form-errors result)))))))
    
  3. Implement Test 5: Numeric code format validation

    • Test negative numbers
    • Test non-numeric characters
    • Test leading zeros
    • Test very long codes
  4. Verify validation tests pass

    • Run each validation test
    • Fix failures
    • Verify error messages are clear

Deliverable:

  • Tests 3, 4, 5 pass successfully
  • Validation error scenarios covered

Task 4: Duplicate Detection Tests

  1. Implement helper to create test account

    (defn setup-account-with-code [code name type]
      (setup-test-data [{:db/id "existing-account-1"
                         :account/numeric-code code
                         :account/account-set "default"
                         :account/name name
                         :account/type type
                         :account/location "A"}]))
    
  2. Implement Test 6: Duplicate numeric code detection

    (deftest account-creation-duplicate-code
      (testing "Should detect and reject duplicate numeric code"
        (let [admin-identity (admin-token)
              _ (setup-account-with-code 12345 "Existing Account" :account-type/asset)
              form-params {:account/numeric-code 12345
                           :account/name "New Account"
                           :account/type :account-type/asset}
              result (sut/account-save {:form-params form-params
                                         :request-method :post
                                         :identity admin-identity})]
          (is (not= :success (:status result)))
          (is (some #(str/includes? (first %) "code") (:form-errors result)))
          ;; Verify no new account was created
          (let [db-after (dc/db conn)
                accounts (dc/q '[:find ?e
                                :where [?e :account/numeric-code 12345]]
                              db-after)]
            (is (= 1 (count accounts)))))))
    
  3. Implement Test 7: Duplicate account name detection

    (deftest account-creation-duplicate-name
      (testing "Should detect and reject duplicate account name"
        (let [admin-identity (admin-token)
              _ (setup-account-with-code 12346 "Cash Account" :account-type/asset)
              form-params {:account/numeric-code 12347
                           :account/name "Cash Account"
                           :account/type :account-type/asset}
              result (sut/account-save {:form-params form-params
                                         :request-method :post
                                         :identity admin-identity})]
          (is (not= :success (:status result)))
          (is (some #(str/includes? (first %) "name") (:form-errors result)))
          ;; Verify no new account was created
          (let [db-after (dc/db conn)
                accounts (dc/q '[:find ?e
                                :where [?e :account/name "Cash Account"]]
                              db-after)]
            (is (= 1 (count accounts)))))))
    
  4. Implement Test 8: Case-insensitive duplicate detection

    • Test "Cash" vs "cash" duplicates
    • Test "CASH" vs "Cash" duplicates
    • Verify case-sensitivity handling
  5. Verify duplicate detection tests pass

    • Run each duplicate test
    • Fix failures
    • Verify no account created on duplicates

Deliverable:

  • Tests 6, 7, 8 pass successfully
  • Duplicate detection logic thoroughly tested

Task 5: Solr Indexing Tests

  1. Mock Solr client for testing

    (with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
      (let [result @(sut/account-save {...})]
        ;; Test Solr index)
    
  2. Implement Test 9: Account appears in Solr search

    (deftest account-creation-solr-indexing
      (testing "Created account should be searchable in Solr"
        (with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
          (let [admin-identity (admin-token)
                form-params {:account/numeric-code 12349
                             :account/name "Solr Test Account"
                             :account/type :account-type/asset}
                result @(sut/account-save {:form-params form-params
                                           :request-method :post
                                           :identity admin-identity})]
            ;; Then: Account should be indexed in Solr
            (let [solr (auto-ap.solr/->InMemSolrClient (atom {}))
                  search-results (solr/query {:query "Solr Test Account"})]
              (is (> (count search-results) 0)))))))
    
  3. Implement Test 10: Can search by numeric code

    • Test searching by numeric code
    • Verify exact match
    • Test search returns correct account
  4. Implement Test 11: Solr index update on account update

    • Create account
    • Update account
    • Verify Solr index contains updated data
    • Verify old data removed
  5. Verify Solr indexing tests pass

    • Run each Solr test
    • Fix failures
    • Verify index operations work correctly

Deliverable:

  • Tests 9, 10, 11 pass successfully
  • Solr indexing thoroughly tested

Phase 3: Authorization & Edge Cases (2-3 hours)

Task 6: Authorization Tests

  1. Implement Test 12: Non-admin access is denied

    (deftest account-creation-non-admin-access-denied
      (testing "Non-admin users should not be able to create accounts"
        (let [user-identity {:user "TEST USER"
                             :user/role "user"
                             :user/name "TEST USER"}
              form-params {:account/numeric-code 12350
                           :account/name "Unauthorized Account"
                           :account/type :account-type/asset}
              result (sut/account-save {:form-params form-params
                                         :request-method :post
                                         :identity user-identity})]
          (is (not= :success (:status result)))
          ;; Should return 403 or error
          (is (some #(str/includes? (first %) "not authorized") (:form-errors result)))))))
    
  2. Implement Test 13: Admin with invalid token

    • Test expired token
    • Test malformed token
    • Test missing token
    • Verify proper error handling
  3. Verify authorization tests pass

    • Run each authorization test
    • Fix failures
    • Verify security constraints

Deliverable:

  • Tests 12, 13 pass successfully
  • Authorization thoroughly tested

Task 7: Edge Cases

  1. Implement Test 14: Client override validation

    • Test duplicate client names in overrides
    • Test empty overrides
    • Test too many overrides
    • Test invalid client references
  2. Implement Test 15: Account name edge cases

    • Test special characters
    • Test unicode characters
    • Test extremely long names
    • Test names with leading/trailing spaces
  3. Implement Test 16: Numeric code edge cases

    • Test very long codes (near database limit)
    • Test zero
    • Test decimal numbers
    • Test codes with spaces
  4. Implement Test 17: Transaction rollback on Solr failure

    • Simulate Solr failure
    • Verify Datomic transaction is rolled back
    • Verify no partial data created
  5. Implement Test 18: Concurrent account creation

    • Test two admins creating accounts simultaneously
    • Verify no duplicate code/name conflicts
    • Test race condition handling
  6. Verify edge case tests pass

    • Run each edge case test
    • Fix failures
    • Document any limitations

Deliverable:

  • Tests 14, 15, 16, 17, 18 pass successfully
  • Edge cases thoroughly tested

Phase 4: Refinement & Documentation (1-2 hours)

Task 8: Code Quality

  1. Run linting

    lein cljfmt check
    
  2. Fix formatting issues

    lein cljfmt fix
    
  3. Verify no syntax errors

    • Run lein check or lein test to catch any issues
  4. Add test comments explaining BDD Given-When-Then flow

    • Document purpose of each test
    • Explain assumptions
    • Note any test limitations
  5. Organize tests by feature

    • Group related tests together
    • Use clear headings
    • Add docstrings
  6. Update test documentation

    • Document test utilities used
    • Explain test setup and teardown
    • Add reference to source code

Deliverable:

  • Code formatted and linted
  • Well-documented tests
  • Clear test structure

Task 9: Integration Testing

  1. Run full test suite

    lein test
    
  2. Run integration tests only

    lein test :integration
    
  3. Run functional tests only

    lein test :functional
    
  4. Fix any failing tests

    • Analyze test failures
    • Fix implementation or test
    • Re-run until all tests pass
  5. Verify test performance

    • Check execution time
    • Identify slow tests
    • Optimize if necessary

Deliverable:

  • All tests pass
  • Tests run in acceptable time (< 2 minutes for full suite)

Task 10: Code Review Preparation

  1. Review test code quality

    • Check naming conventions
    • Verify test isolation
    • Ensure proper cleanup
  2. Document test patterns

    • Note common test utilities used
    • Document testing conventions
    • Add examples for future tests
  3. Create summary documentation

    • List all tests implemented
    • Explain test coverage
    • Document any test limitations
    • Provide guidance for running tests

Deliverable:

  • Clean, maintainable test code
  • Comprehensive test documentation
  • Ready for code review

References & Research

Internal References

  • Account Creation Source: src/clj/auto_ap/ssr/admin/accounts.clj:196-49

    • Main account-save function
    • Form schema validation logic
    • Duplicate check implementation
    • Solr indexing logic
  • Test Utilities: test/clj/auto_ap/integration/util.clj:1-117

    • wrap-setup - Test database setup/teardown
    • admin-token - Admin authentication token creation
    • setup-test-data - Common test data creation
    • test-account - Helper for account test data
  • Existing SSR Tests:

    • test/clj/auto_ap/ssr/invoice/new_invoice_wizard_test.clj - SSR test patterns
    • test/clj/auto_ap/ssr/ledger_test.clj - Comprehensive test examples
    • test/clj/auto_ap/integration/graphql/accounts.clj - Integration test patterns
  • Testing Conventions: .claude/skills/testing-conventions/SKILL.md

    • Core principle: Test user-observable behavior
    • Database testing patterns
    • Test fixture usage
    • Helper function recommendations

External References

  • Clojure Testing: clojure.test documentation

    • Test structure and patterns
    • Fixtures and setup/teardown
    • Assertions and test organization
  • Datomic API: datomic.api documentation

    • Database queries (dc/q, dc/pull)
    • Transaction operations
    • Entity manipulation
  • BDD in Clojure: Cucumber Clojure (if needed)

    • If BDD framework is adopted
    • Alternative to Clojure.test patterns
  • Previous Account Tests: test/clj/auto_ap/integration/graphql/accounts.clj (215 lines)

    • Existing account-related tests for reference
    • GraphQL API patterns that may apply
  • Admin Tests: None found (admin functionality less tested)

    • This feature will be first comprehensive admin test suite
    • Opportunity to establish admin testing patterns

Testing Conventions Applied

Following project conventions:

  1. User-Observable Behavior: Tests verify database state changes, not implementation details
  2. Given-When-Then Structure: Tests document behavioral intent clearly
  3. Test Utilities: Leverage existing wrap-setup, admin-token, setup-test-data
  4. Database Verification: Use dc/pull and dc/q to verify state after operations
  5. Isolation: Each test has proper setup and teardown
  6. Clarity: Test names are descriptive and clear about intent
  7. Documentation: Test comments explain BDD flow and assumptions

Success Criteria Summary

  • 18 BDD test scenarios implemented and passing
  • Clear Given-When-Then documentation for each test
  • Tests cover happy path, validation errors, duplicates, Solr, authorization, edge cases
  • No regression in existing account creation functionality
  • Tests provide clear behavioral documentation for developers
  • Tests run in parallel without conflicts
  • Code formatted and linted
  • Full test suite passes

Next Steps

  1. Review Plan: Confirm scope and detail level
  2. Run Deepen Research: Optionally enhance with best practices and performance analysis
  3. Start Implementation: Begin with Phase 1 and iterate through phases
  4. Code Review: Get feedback on test implementation
  5. Iterate: Refine tests based on feedback