--- module: SSR Admin component: testing_framework date: '2026-02-07' problem_type: best_practice resolution_type: test_fix severity: medium root_cause: inadequate_documentation symptoms: - Route tests only verified HTTP status codes (200), not actual HTML content - No verification that route responses contain expected page elements - Could have false positives where routes return empty or wrong content rails_version: 7.1.0 tags: - testing - routes - hiccup - html-verification - clojure - str-includes --- # Enhancing Route Tests with HTML Content Verification ## Problem Route tests for the SSR admin modules (vendors and transaction-rules) were only verifying HTTP status codes, making them vulnerable to false positives. A route could return a 200 status but with empty or incorrect HTML content, and the tests would still pass. ## Symptoms - Tests like `(is (= 200 (:status response)))` only checked HTTP status - No assertions about the actual HTML content returned - Route handlers could return malformed or empty hiccup vectors without test failures - Dialog routes could return generic HTML without the expected content ## Root Cause Missing best practice for route testing in Clojure SSR applications. Unlike Rails controller tests that can use `assert_select` or Capybara matchers, there was no established pattern for verifying hiccup-rendered HTML content. ## Solution Enhanced route tests to verify HTML content using `clojure.string/includes?` checks on the rendered HTML string. ### Implementation Pattern ```clojure ;; BEFORE: Only status check (deftest page-route-returns-html-response (testing "Page route returns HTML response" (let [request {:identity (admin-token)} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/page) request)] (is (= 200 (:status response)))))) ;; AFTER: Status + content verification (deftest page-route-returns-html-response (testing "Page route returns HTML response" (let [request {:identity (admin-token)} response ((get sut/key->handler :auto-ap.routes.admin.transaction-rules/page) request) html-str (apply str (:body response))] (is (= 200 (:status response))) (is (str/includes? html-str "Transaction Rules"))))) ``` ### Key Changes 1. **Convert body to string**: Use `(apply str (:body response))` to convert hiccup vectors to HTML string 2. **Add content assertions**: Use `clojure.string/includes?` to verify expected content exists 3. **Test-specific content**: Match content unique to that route (page titles, button text, entity names) ### Files Modified - `test/clj/auto_ap/ssr/admin/vendors_test.clj` - Added `vendor-page-route-contains-vendor-content` test - `test/clj/auto_ap/ssr/admin/transaction_rules_test.clj` - Enhanced 7 route tests with content verification: - `page-route-returns-html-response` → checks for "Transaction Rules" - `table-route-returns-table-data` → checks for "New Transaction Rule" - `edit-dialog-route-returns-dialog` → checks for entity-specific content - `account-typeahead-route-works` → checks for "account" - `location-select-route-works` → checks for "location" - `execute-dialog-route-works` → checks for "Code transactions" - `new-dialog-route-returns-empty-form` → checks for "Transaction rule" ### Testing Strategy For each route, identify the minimal but specific content that indicates the route is working: - **Page routes**: Check for page title or heading - **Dialog routes**: Check for dialog-specific button text or the entity name being edited - **Typeahead routes**: Check for the resource type (e.g., "account") - **Table routes**: Check for action buttons or empty state messages ## Prevention When writing route tests, always: 1. ✅ Verify HTTP status code (200, 302, etc.) 2. ✅ Verify response contains expected HTML content 3. ✅ Use specific content unique to that route 4. ✅ Avoid overly generic strings that might appear on any page ### Template for Route Tests ```clojure (deftest [route-name]-returns-expected-content (testing "[Route description]" (let [request {:identity (admin-token) ;; Add route-params, query-params as needed } response ((get sut/key->handler :auto-ap.routes.[module]/[route]) request) html-str (apply str (:body response))] (is (= 200 (:status response))) (is (str/includes? html-str "[Expected content]"))))) ``` ## Tools Used - `clojure.string/includes?` - Simple string containment check - `apply str` - Converts hiccup vector to HTML string - No additional dependencies needed ## Benefits - **Catches regressions**: Tests fail if route returns wrong content - **Self-documenting**: Test assertions describe expected behavior - **Lightweight**: No complex HTML parsing libraries required - **Fast**: String operations are performant ## Related - Similar pattern could apply to any Clojure SSR application using hiccup - For more complex DOM assertions, consider adding hickory or enlive for structured HTML parsing