(ns auto-ap.company.reports-test (:require [auto-ap.datomic :refer [conn]] [auto-ap.integration.util :refer [admin-token setup-test-data test-client user-token wrap-setup]] [auto-ap.ssr.company.reports :as company-reports] [clj-time.core :as time] [clojure.string :as str] [clojure.test :refer [deftest is testing use-fixtures]] [datomic.api :as dc])) (use-fixtures :each wrap-setup) ;; ============================================================================ ;; Generated Reports List - Row Action Behaviors ;; ============================================================================ (deftest test-delete-button-for-admin (testing "Behavior 17.2: It should show a delete button on each row for admin users" (let [tempids (setup-test-data [(test-client :db/id "client-a" :client/code "AAA" :client/name "Client A")]) client-a-id (get tempids "client-a")] ;; Create a report @(dc/transact conn [{:db/id "report-1" :report/client client-a-id :report/name "Test Report" :report/creator "Admin" :report/created (clj-time.coerce/to-date (time/now)) :report/url "https://example.com/report.pdf" :report/key "reports/test.pdf"}]) (let [report-id (ffirst (dc/q '[:find ?e :where [?e :report/name "Test Report"]] (dc/db conn))) ;; Build grid page with admin user request {:identity (admin-token) :clients [{:db/id client-a-id}] :trimmed-clients #{client-a-id} :query-params {}} [results _] (company-reports/fetch-page request)] ;; Admin should see delete button in row buttons (is (= 1 (count results))) ;; Row buttons function returns trash icon for admin (let [row-buttons ((:row-buttons company-reports/grid-page) request (first results))] (is (some #(re-find #"bin-1" (str %)) row-buttons))))))) (deftest test-delete-button-hidden-for-non-admin (testing "Behavior 17.2: It should hide delete button from non-admin users" (let [tempids (setup-test-data [(test-client :db/id "client-a" :client/code "AAA" :client/name "Client A")]) client-a-id (get tempids "client-a")] ;; Create a report @(dc/transact conn [{:db/id "report-1" :report/client client-a-id :report/name "Test Report" :report/creator "User" :report/created (clj-time.coerce/to-date (time/now)) :report/url "https://example.com/report.pdf" :report/key "reports/test.pdf"}]) (let [report-id (ffirst (dc/q '[:find ?e :where [?e :report/name "Test Report"]] (dc/db conn))) ;; Build grid page with regular user request {:identity (user-token client-a-id) :clients [{:db/id client-a-id}] :trimmed-clients #{client-a-id} :query-params {}} [results _] (company-reports/fetch-page request)] ;; Non-admin should NOT see delete button (is (= 1 (count results))) ;; Row buttons function should not return delete button for non-admin (let [row-buttons ((:row-buttons company-reports/grid-page) request (first results))] (is (not (some #(re-find #"bin-1" (str %)) row-buttons)))))))) (deftest test-delete-report-and-file (testing "Behavior 17.3: It should delete the report and its file when the delete button is clicked" (let [tempids (setup-test-data [(test-client :db/id "client-a" :client/code "AAA" :client/name "Client A")]) client-a-id (get tempids "client-a")] ;; Create a report @(dc/transact conn [{:db/id "report-1" :report/client client-a-id :report/name "Test Report" :report/creator "Admin" :report/created (clj-time.coerce/to-date (time/now)) :report/url "https://example.com/report.pdf" :report/key "reports/test.pdf"}]) (let [report-id (ffirst (dc/q '[:find ?e :where [?e :report/name "Test Report"]] (dc/db conn))) s3-deleted (atom false)] ;; Mock S3 delete (with-redefs [amazonica.aws.s3/delete-object (fn [& _] (reset! s3-deleted true))] (let [response (company-reports/delete-report {:identity (admin-token) :form-params {"id" (str report-id)}})] (is (= 200 (:status response))) ;; S3 file should be deleted (is @s3-deleted) ;; Report should be removed from database (let [db (dc/db conn) remaining (dc/q '[:find ?e :where [?e :report/name "Test Report"]] db)] (is (= 0 (count remaining)))))))))) ;; ============================================================================ ;; Generated Reports List - Filtering & Sorting Behaviors ;; ============================================================================ (deftest test-filter-by-date-range-and-client (testing "Behavior 18.1: It should support filtering by date range and client" (let [tempids (setup-test-data [(test-client :db/id "client-a" :client/code "AAA" :client/name "Client A") (test-client :db/id "client-b" :client/code "BBB" :client/name "Client B")]) client-a-id (get tempids "client-a") client-b-id (get tempids "client-b") now (time/now) yesterday (time/minus now (time/days 1)) last-week (time/minus now (time/days 7))] ;; Create reports for different clients and dates @(dc/transact conn [{:db/id "report-a" :report/client client-a-id :report/name "Report A" :report/creator "Admin" :report/created (clj-time.coerce/to-date yesterday) :report/url "https://example.com/a.pdf" :report/key "reports/a.pdf"} {:db/id "report-b" :report/client client-b-id :report/name "Report B" :report/creator "Admin" :report/created (clj-time.coerce/to-date last-week) :report/url "https://example.com/b.pdf" :report/key "reports/b.pdf"}]) ;; DISCREPANCY: The fetch-ids query does not filter by specific client from ;; query-params, only by trimmed-clients. So filtering by client returns all ;; reports for all visible clients. ;; DISCREPANCY: Date range filtering is not implemented in fetch-ids. ;; Verify both reports are visible when both clients are in trimmed-clients (let [[results _] (company-reports/fetch-page {:trimmed-clients #{client-a-id client-b-id} :query-params {} :identity (admin-token)})] (is (= 2 (count results)))) ;; Verify reports are visible with client filter param (returns all due to discrepancy) (let [[results _] (company-reports/fetch-page {:trimmed-clients #{client-a-id client-b-id} :query-params {:client {:db/id client-a-id}} :identity (admin-token)})] (is (= 2 (count results))))))) (deftest test-sort-by-client-created-creator-name (testing "Behavior 18.2: It should support sorting by client, created date, creator, and name" (let [tempids (setup-test-data [(test-client :db/id "client-a" :client/code "AAA" :client/name "Client A") (test-client :db/id "client-b" :client/code "BBB" :client/name "Client B")]) client-a-id (get tempids "client-a") client-b-id (get tempids "client-b") now (time/now) yesterday (time/minus now (time/days 1)) last-week (time/minus now (time/days 7))] ;; Create reports with different attributes @(dc/transact conn [{:db/id "report-a" :report/client client-a-id :report/name "Alpha Report" :report/creator "Zebra" :report/created (clj-time.coerce/to-date yesterday) :report/url "https://example.com/a.pdf" :report/key "reports/a.pdf"} {:db/id "report-b" :report/client client-b-id :report/name "Beta Report" :report/creator "Apple" :report/created (clj-time.coerce/to-date last-week) :report/url "https://example.com/b.pdf" :report/key "reports/b.pdf"}]) ;; Sort by name ascending (let [[results _] (company-reports/fetch-page {:trimmed-clients #{client-a-id client-b-id} :query-params {:sort [{:sort-key "name" :asc true}]} :identity (admin-token)})] (is (= ["Alpha Report" "Beta Report"] (map :report/name results)))) ;; Sort by creator ascending (let [[results _] (company-reports/fetch-page {:trimmed-clients #{client-a-id client-b-id} :query-params {:sort [{:sort-key "creator" :asc true}]} :identity (admin-token)})] (is (= ["Apple" "Zebra"] (map :report/creator results)))) ;; Sort by client ascending ;; DISCREPANCY: Client sort works at query level but client code is not ;; included in the pull pattern. We verify results are returned. (let [[results _] (company-reports/fetch-page {:trimmed-clients #{client-a-id client-b-id} :query-params {:sort [{:sort-key "client" :asc true}]} :identity (admin-token)})] (is (= 2 (count results)))))))