Skip to content

Commit 1f5b60a

Browse files
committed
Error recovery tests
1 parent 9daa858 commit 1f5b60a

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

‎test/re_frame/query_test.cljc‎

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,3 +1011,120 @@
10111011
(process-event [:re-frame.query/ensure-query :books/list {}])
10121012
(is (zero? @call-count)
10131013
"no effect — query without stale-time-ms never auto-stales")))))
1014+
1015+
;; ---------------------------------------------------------------------------
1016+
;; Error recovery cycle tests
1017+
;; ---------------------------------------------------------------------------
1018+
1019+
(deftest query-error-then-success-clears-error
1020+
(testing "After a failed query, a successful retry clears the error and restores :success"
1021+
(rfq/reg-query :books/list {:query-fn (fn [_] {})})
1022+
(let [qid (util/query-id :books/list {})]
1023+
;; Initial failure
1024+
(process-event [:re-frame.query/query-failure :books/list {} {:status 500 :body "Internal Server Error"}])
1025+
(is (= :error (get-in (app-db) [:re-frame.query/queries qid :status])))
1026+
(is (= {:status 500 :body "Internal Server Error"}
1027+
(get-in (app-db) [:re-frame.query/queries qid :error])))
1028+
;; Retry succeeds
1029+
(process-event [:re-frame.query/query-success :books/list {} [{:id 1}]])
1030+
(let [query (get-in (app-db) [:re-frame.query/queries qid])]
1031+
(is (= :success (:status query))
1032+
"status transitions to :success")
1033+
(is (= [{:id 1}] (:data query))
1034+
"data is stored")
1035+
(is (nil? (:error query))
1036+
"error is cleared on success")
1037+
(is (false? (:fetching? query)))))))
1038+
1039+
(deftest query-repeated-failures-update-error
1040+
(testing "Each failure updates the error value, not accumulates"
1041+
(rfq/reg-query :books/list {:query-fn (fn [_] {})})
1042+
(let [qid (util/query-id :books/list {})]
1043+
;; First failure
1044+
(process-event [:re-frame.query/query-failure :books/list {} {:status 500}])
1045+
(is (= {:status 500} (get-in (app-db) [:re-frame.query/queries qid :error])))
1046+
;; Second failure with different error
1047+
(process-event [:re-frame.query/query-failure :books/list {} {:status 503}])
1048+
(is (= {:status 503} (get-in (app-db) [:re-frame.query/queries qid :error]))
1049+
"error is replaced, not accumulated")
1050+
(is (= :error (get-in (app-db) [:re-frame.query/queries qid :status]))))))
1051+
1052+
(deftest query-success-then-failure-preserves-data
1053+
(testing "After success then failure, data persists but status is :error"
1054+
(rfq/reg-query :books/list {:query-fn (fn [_] {})})
1055+
(let [qid (util/query-id :books/list {})]
1056+
;; Success first
1057+
(process-event [:re-frame.query/query-success :books/list {} [{:id 1}]])
1058+
(is (= :success (get-in (app-db) [:re-frame.query/queries qid :status])))
1059+
;; Then a refetch fails
1060+
(process-event [:re-frame.query/query-failure :books/list {} {:status 502}])
1061+
(let [query (get-in (app-db) [:re-frame.query/queries qid])]
1062+
(is (= :error (:status query))
1063+
"status is :error")
1064+
(is (= {:status 502} (:error query))
1065+
"error is stored")
1066+
(is (= [{:id 1}] (:data query))
1067+
"previous data is preserved across failure")))))
1068+
1069+
(deftest query-full-error-recovery-cycle
1070+
(testing "Full cycle: success → stale → refetch fails → retry → success with new data"
1071+
(let [call-count (atom 0)]
1072+
(rf/reg-fx :test-http (fn [_] (swap! call-count inc)))
1073+
(rfq/set-default-effect-fn!
1074+
(fn [request on-success on-failure]
1075+
{:test-http (assoc request
1076+
:on-success on-success
1077+
:on-failure on-failure)}))
1078+
(rfq/reg-query :books/list
1079+
{:query-fn (fn [_] {:method :get :url "/api/books"})
1080+
:stale-time-ms 1000})
1081+
(let [qid (util/query-id :books/list {})]
1082+
;; 1. Initial success
1083+
(process-event [:re-frame.query/query-success :books/list {} [{:id 1}]])
1084+
(is (= :success (get-in (app-db) [:re-frame.query/queries qid :status])))
1085+
;; 2. Make stale
1086+
(swap! rf-db/app-db assoc-in [:re-frame.query/queries qid :fetched-at] 0)
1087+
(reset! call-count 0)
1088+
;; 3. ensure-query detects staleness → refetch
1089+
(process-event [:re-frame.query/ensure-query :books/list {}])
1090+
(is (= 1 @call-count))
1091+
;; 4. Refetch fails
1092+
(process-event [:re-frame.query/query-failure :books/list {} {:status 500}])
1093+
(is (= :error (get-in (app-db) [:re-frame.query/queries qid :status])))
1094+
(is (= [{:id 1}] (get-in (app-db) [:re-frame.query/queries qid :data]))
1095+
"stale data preserved after failure")
1096+
;; 5. Retry — error status is stale, so ensure-query triggers
1097+
(reset! call-count 0)
1098+
(process-event [:re-frame.query/ensure-query :books/list {}])
1099+
(is (= 1 @call-count) "retry fires because error status is stale")
1100+
(is (= :loading (get-in (app-db) [:re-frame.query/queries qid :status]))
1101+
"status resets to :loading on retry after error")
1102+
;; 6. Success with new data
1103+
(process-event [:re-frame.query/query-success :books/list {} [{:id 1} {:id 2}]])
1104+
(let [query (get-in (app-db) [:re-frame.query/queries qid])]
1105+
(is (= :success (:status query)))
1106+
(is (= [{:id 1} {:id 2}] (:data query)))
1107+
(is (nil? (:error query))
1108+
"error is cleared after successful recovery"))))))
1109+
1110+
(deftest mutation-error-then-retry-success
1111+
(testing "A failed mutation followed by re-execution transitions to :success"
1112+
(rfq/reg-mutation :books/create
1113+
{:mutation-fn (fn [{:keys [title]}]
1114+
{:method :post :url "/api/books" :body {:title title}})})
1115+
(let [mid (util/query-id :books/create {:title "Dune"})]
1116+
;; First attempt fails
1117+
(process-event [:re-frame.query/execute-mutation :books/create {:title "Dune"}])
1118+
(process-event [:re-frame.query/mutation-failure :books/create {:title "Dune"} {:status 500}])
1119+
(is (= :error (get-in (app-db) [:re-frame.query/mutations mid :status])))
1120+
(is (= {:status 500} (get-in (app-db) [:re-frame.query/mutations mid :error])))
1121+
;; Retry succeeds
1122+
(process-event [:re-frame.query/execute-mutation :books/create {:title "Dune"}])
1123+
(is (= :loading (get-in (app-db) [:re-frame.query/mutations mid :status]))
1124+
"status resets to :loading")
1125+
(is (nil? (get-in (app-db) [:re-frame.query/mutations mid :error]))
1126+
"error cleared on retry")
1127+
(process-event [:re-frame.query/mutation-success :books/create {:title "Dune"} {:id 1}])
1128+
(is (= :success (get-in (app-db) [:re-frame.query/mutations mid :status])))
1129+
(is (= {:id 1} (get-in (app-db) [:re-frame.query/mutations mid :data])))
1130+
(is (nil? (get-in (app-db) [:re-frame.query/mutations mid :error]))))))

0 commit comments

Comments
 (0)