feat(tests): implement integration and unit tests for auth, company, and ledger behaviors

- Auth: 30 tests (97 assertions) covering OAuth, sessions, JWT, impersonation, roles
- Company: 35 tests (92 assertions) covering profile, 1099, expense reports, permissions
- Ledger: 113 tests (148 assertions) covering grid, journal entries, import, reports
- Fix existing test failures in running_balance, insights, tx, plaid, graphql
- Fix InMemSolrClient to handle Solr query syntax properly
- Update behavior docs: auth (42 done), company (32 done), ledger (120 done)
- All 478 tests pass with 0 failures, 0 errors
This commit is contained in:
2026-05-08 16:12:08 -07:00
parent d9d9263824
commit 6b5d33a32f
64 changed files with 9005 additions and 2086 deletions

View File

@@ -0,0 +1,93 @@
(ns auto-ap.auth.jwt-test
(:require
[auto-ap.integration.util :refer [wrap-setup]]
[auto-ap.routes.auth :as auth]
[buddy.sign.jwt :as jwt]
[clj-time.coerce :as coerce]
[clj-time.core :as time]
[clojure.test :refer [deftest is testing use-fixtures]]
[config.core :refer [env]]))
(use-fixtures :each wrap-setup)
(deftest test-user->jwt-generates-token
(testing "Behavior 7.1: It should generate a JWT containing the user's role and client access on login"
(let [user {:db/id 123
:user/name "Test User"
:user/role :user-role/user
:user/clients [{:db/id 1 :client/code "A" :client/locations ["DT"]}
{:db/id 2 :client/code "B" :client/locations ["MH"]}]}
token (auth/user->jwt user "fake-oauth-token")]
(is (= "Test User" (:user token)))
(is (= "user" (:user/role token)))
(is (= 123 (:db/id token)))
(is (= "Test User" (:user/name token)))
(is (some? (:exp token))))))
(deftest test-admin-jwt-compresses-clients
(testing "Behavior 7.2: It should compress the client list for admin users to fit in the JWT"
(let [user {:db/id 1
:user/name "Admin"
:user/role :user-role/admin
:user/clients [{:db/id 10 :client/code "A" :client/locations ["DT"]}
{:db/id 20 :client/code "B" :client/locations ["MH"]}]}
token (auth/user->jwt user "fake-oauth-token")]
(is (= "admin" (:user/role token)))
(is (some? (:gz-clients token)))
(is (string? (:gz-clients token)))
(is (nil? (:user/clients token)))
;; Verify the compressed data can be decompressed
(let [decompressed (auth/gunzip (:gz-clients token))]
(is (= [{:db/id 10 :client/code "A" :client/locations ["DT"]}
{:db/id 20 :client/code "B" :client/locations ["MH"]}]
decompressed))))))
(deftest test-readonly-jwt-compresses-clients
(testing "Behavior 7.3: It should compress the client list for read-only users to fit in the JWT"
(let [user {:db/id 2
:user/name "Read Only"
:user/role :user-role/read-only
:user/clients [{:db/id 30 :client/code "C" :client/locations ["DT"]}]}
token (auth/user->jwt user "fake-oauth-token")]
(is (= "read-only" (:user/role token)))
(is (some? (:gz-clients token)))
(is (string? (:gz-clients token)))
(is (nil? (:user/clients token)))
(let [decompressed (auth/gunzip (:gz-clients token))]
(is (= [{:db/id 30 :client/code "C" :client/locations ["DT"]}]
decompressed))))))
(deftest test-regular-user-jwt-plain-clients
(testing "Behavior 7.4: It should include a plain client list for regular users in the JWT"
(let [user {:db/id 3
:user/name "Regular"
:user/role :user-role/user
:user/clients [{:db/id 40 :client/code "D" :client/locations ["DT"]}]}
token (auth/user->jwt user "fake-oauth-token")]
(is (= "user" (:user/role token)))
(is (some? (:user/clients token)))
(is (sequential? (:user/clients token)))
(is (nil? (:gz-clients token)))
(is (= [{:db/id 40 :client/code "D" :client/locations ["DT"]}]
(:user/clients token))))))
(deftest test-api-token
(testing "Behavior 7.5: It should create API tokens with admin role and 1000-day expiration"
(let [token-str (auth/make-api-token)
claims (jwt/unsign token-str (:jwt-secret env) {:alg :hs512})
exp-dt (coerce/from-long (* 1000 (long (:exp claims))))
now (time/now)]
(is (= "API" (:user claims)))
(is (= "admin" (:user/role claims)))
(is (= "API" (:user/name claims)))
(is (some? (:exp claims)))
;; Verify expiration is approximately 1000 days from now
(is (time/after? exp-dt now))
(is (time/before? exp-dt (time/plus now (time/days 1001)))))))
(deftest test-gzip-roundtrip
(testing "gzip and gunzip are inverse operations"
(let [data [{:db/id 1 :client/code "A"} {:db/id 2 :client/code "B"}]
compressed (auth/gzip data)
decompressed (auth/gunzip compressed)]
(is (= data decompressed)))))