Files
integreat/docs/solutions/test-failures/route-tests-html-verification-SSRAdmin-20260207.md
Bryce f4366fe98e Add location extraction for Bonanza Produce invoices
- Extract city/state/zip in location field
- Customer address now split across 3 fields:
  - customer-identifier: customer name
  - account-number: street address
  - location: city, state zip
- All components verified in test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-08 07:55:12 -08:00

5.0 KiB

module, component, date, problem_type, resolution_type, severity, root_cause, symptoms, rails_version, tags
module component date problem_type resolution_type severity root_cause symptoms rails_version tags
SSR Admin testing_framework 2026-02-07 best_practice test_fix medium inadequate_documentation
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
7.1.0
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

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

(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
  • 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