critique of wizard design.
This commit is contained in:
114
test/clj/auto_ap/ssr/components/wizard_trial/core_test.clj
Normal file
114
test/clj/auto_ap/ssr/components/wizard_trial/core_test.clj
Normal file
@@ -0,0 +1,114 @@
|
||||
(ns auto-ap.ssr.components.wizard-trial.core-test
|
||||
(:require
|
||||
[auto-ap.ssr.components.wizard-trial.core :as sut]
|
||||
[auto-ap.ssr.components.wizard-trial.state :as ws]
|
||||
[clojure.test :refer [deftest is testing]]
|
||||
[hiccup.core :as hiccup]))
|
||||
|
||||
(deftest render-step-test
|
||||
(testing "render-step produces a form with hidden wizard-id and step-key inputs"
|
||||
(let [wizard-id (ws/create! {})
|
||||
step-config {:key :test-step
|
||||
:render (fn [{:keys [step-data errors request]}]
|
||||
[:div (str "data: " step-data) (when errors [:span.error (str errors)])])
|
||||
:submit-route "/test-submit"}
|
||||
result (sut/render-step {:wizard-id wizard-id
|
||||
:step-config step-config
|
||||
:request {}})]
|
||||
(is (= :form (first result)))
|
||||
(let [attrs (second result)
|
||||
children (drop 2 result)]
|
||||
(is (= "/test-submit" (:hx-post attrs)))
|
||||
(is (= "this" (:hx-target attrs)))
|
||||
(let [html (hiccup/html result)]
|
||||
(is (re-find #"name=\"wizard-id\"" html))
|
||||
(is (re-find #"value=\"" html))
|
||||
(is (re-find #"name=\"step-key\"" html))
|
||||
(is (re-find #"value=\"test-step\"" html))))))
|
||||
|
||||
(testing "render-step passes step-data, errors, and request to the render function"
|
||||
(let [wizard-id (ws/create! {:test-step {:field "value"}})
|
||||
captured (atom nil)
|
||||
step-config {:key :test-step
|
||||
:render (fn [args] (reset! captured args) [:div "rendered"])
|
||||
:submit-route "/test-submit"}
|
||||
_ (sut/render-step {:wizard-id wizard-id
|
||||
:step-config step-config
|
||||
:request {:client-id 123}
|
||||
:errors {:field ["is invalid"]}})
|
||||
{:keys [step-data errors request]} @captured]
|
||||
(is (= {:field "value"} step-data))
|
||||
(is (= {:field ["is invalid"]} errors))
|
||||
(is (= {:client-id 123} request)))))
|
||||
|
||||
(deftest handle-submit-test
|
||||
(testing "handle-submit with valid data saves step and calls done-fn"
|
||||
(let [done-result (atom nil)
|
||||
wizard-id (ws/create! {})
|
||||
step-config {:key :test-step
|
||||
:schema [:map [:name :string]]
|
||||
:fields [:name]
|
||||
:render (fn [_] [:div "rendered"])
|
||||
:submit-route "/test-submit"
|
||||
:done-fn (fn [data request]
|
||||
(reset! done-result {:data data :request request})
|
||||
{:status 200 :body "done"})}
|
||||
request {:form-params {"wizard-id" wizard-id
|
||||
"step-key" "test-step"
|
||||
"name" "Alice"}}
|
||||
response (sut/handle-submit step-config request)]
|
||||
(is (= 200 (:status response)))
|
||||
(is (= "done" (:body response)))
|
||||
(is (= "Alice" (get-in @done-result [:data :name])))
|
||||
(is (nil? (ws/get-wizard wizard-id)) "Wizard session should be destroyed after successful submit")))
|
||||
|
||||
(testing "handle-submit with invalid data re-renders step with errors"
|
||||
(let [wizard-id (ws/create! {})
|
||||
step-config {:key :test-step
|
||||
:schema [:map [:name :string]]
|
||||
:fields [:name]
|
||||
:render (fn [{:keys [errors]}]
|
||||
[:div (when errors [:span.error (str errors)])])
|
||||
:submit-route "/test-submit"
|
||||
:done-fn (fn [_ _] {:status 200 :body "done"})}
|
||||
request {:form-params {"wizard-id" wizard-id
|
||||
"step-key" "test-step"
|
||||
"name" ""}}
|
||||
response (sut/handle-submit step-config request)]
|
||||
(is (= 200 (:status response)))
|
||||
(is (string? (:body response)))
|
||||
(is (re-find #"error" (:body response)) "Response body should contain error markup")
|
||||
(is (some? (ws/get-wizard wizard-id)) "Wizard session should still exist after failed validation")))
|
||||
|
||||
(testing "handle-submit with missing required field shows validation error"
|
||||
(let [wizard-id (ws/create! {})
|
||||
step-config {:key :test-step
|
||||
:schema [:map [:name :string]]
|
||||
:fields [:name]
|
||||
:render (fn [{:keys [errors]}]
|
||||
[:div (when errors [:span.error (str errors)])])
|
||||
:submit-route "/test-submit"
|
||||
:done-fn (fn [_ _] {:status 200 :body "done"})}
|
||||
request {:form-params {"wizard-id" wizard-id
|
||||
"step-key" "test-step"}}
|
||||
response (sut/handle-submit step-config request)]
|
||||
(is (= 200 (:status response)))
|
||||
(is (re-find #"error" (:body response)) "Response body should contain error markup for missing field")))
|
||||
|
||||
(testing "handle-submit decodes step data using main-transformer"
|
||||
(let [done-result (atom nil)
|
||||
wizard-id (ws/create! {})
|
||||
step-config {:key :test-step
|
||||
:schema [:map [:count int?]]
|
||||
:fields [:count]
|
||||
:render (fn [_] [:div "rendered"])
|
||||
:submit-route "/test-submit"
|
||||
:done-fn (fn [data _]
|
||||
(reset! done-result data)
|
||||
{:status 200 :body "done"})}
|
||||
request {:form-params {"wizard-id" wizard-id
|
||||
"step-key" "test-step"
|
||||
"count" "42"}}
|
||||
response (sut/handle-submit step-config request)]
|
||||
(is (= 200 (:status response)))
|
||||
(is (= 42 (:count @done-result)) "String count should be decoded to integer"))))
|
||||
76
test/clj/auto_ap/ssr/components/wizard_trial/state_test.clj
Normal file
76
test/clj/auto_ap/ssr/components/wizard_trial/state_test.clj
Normal file
@@ -0,0 +1,76 @@
|
||||
(ns auto-ap.ssr.components.wizard-trial.state-test
|
||||
(:require
|
||||
[auto-ap.ssr.components.wizard-trial.state :as sut]
|
||||
[clojure.test :refer [deftest is testing]]))
|
||||
|
||||
(deftest create-and-get-wizard-test
|
||||
(testing "Session creation returns a non-nil wizard-id"
|
||||
(let [wizard-id (sut/create! {:foo "bar"})]
|
||||
(is (string? wizard-id))
|
||||
(is (seq wizard-id))))
|
||||
|
||||
(testing "Session retrieval returns the stored data"
|
||||
(let [wizard-id (sut/create! {:foo "bar"})
|
||||
wizard (sut/get-wizard wizard-id)]
|
||||
(is (map? wizard))
|
||||
(is (= {:foo "bar"} (:data wizard)))
|
||||
(is (inst? (:created-at wizard)))))
|
||||
|
||||
(testing "Session retrieval returns nil for unknown id"
|
||||
(is (nil? (sut/get-wizard "non-existent-id")))))
|
||||
|
||||
(deftest update-step-test
|
||||
(testing "update-step! merges data into the specified step key"
|
||||
(let [wizard-id (sut/create! {})
|
||||
_ (sut/update-step! wizard-id :step1 {:field-a "a"})
|
||||
wizard (sut/get-wizard wizard-id)]
|
||||
(is (= {:field-a "a"} (get-in wizard [:data :step1])))))
|
||||
|
||||
(testing "update-step! merges without overwriting other step keys"
|
||||
(let [wizard-id (sut/create! {})
|
||||
_ (sut/update-step! wizard-id :step1 {:field-a "a"})
|
||||
_ (sut/update-step! wizard-id :step2 {:field-b "b"})
|
||||
wizard (sut/get-wizard wizard-id)]
|
||||
(is (= {:field-a "a"} (get-in wizard [:data :step1])))
|
||||
(is (= {:field-b "b"} (get-in wizard [:data :step2])))))
|
||||
|
||||
(testing "update-step! merges within the same step key"
|
||||
(let [wizard-id (sut/create! {})
|
||||
_ (sut/update-step! wizard-id :step1 {:field-a "a"})
|
||||
_ (sut/update-step! wizard-id :step1 {:field-b "b"})
|
||||
wizard (sut/get-wizard wizard-id)]
|
||||
(is (= {:field-a "a" :field-b "b"} (get-in wizard [:data :step1]))))))
|
||||
|
||||
(deftest destroy-test
|
||||
(testing "destroy! removes the wizard session"
|
||||
(let [wizard-id (sut/create! {:foo "bar"})
|
||||
_ (sut/destroy! wizard-id)]
|
||||
(is (nil? (sut/get-wizard wizard-id)))))
|
||||
|
||||
(testing "destroy! is a no-op for unknown id"
|
||||
(sut/destroy! "non-existent-id")
|
||||
(is (nil? (sut/get-wizard "non-existent-id")))))
|
||||
|
||||
(deftest get-all-data-test
|
||||
(testing "get-all-data merges non-map values and map values from all steps"
|
||||
(let [wizard-id (sut/create! {:client-id 123})
|
||||
_ (sut/update-step! wizard-id :step1 {:vendor 456})
|
||||
_ (sut/update-step! wizard-id :step2 {:accounts [{:account 1}]})
|
||||
all-data (sut/get-all-data wizard-id)]
|
||||
(is (= {:client-id 123 :vendor 456 :accounts [{:account 1}]} all-data))))
|
||||
|
||||
(testing "get-all-data returns nil for unknown id"
|
||||
(is (nil? (sut/get-all-data "non-existent-id")))))
|
||||
|
||||
(deftest session-exists-test
|
||||
(testing "Session exists after creation"
|
||||
(let [wizard-id (sut/create! {})]
|
||||
(is (some? (sut/get-wizard wizard-id)))))
|
||||
|
||||
(testing "Session does not exist after destruction"
|
||||
(let [wizard-id (sut/create! {})
|
||||
_ (sut/destroy! wizard-id)]
|
||||
(is (nil? (sut/get-wizard wizard-id)))))
|
||||
|
||||
(testing "Session does not exist for random id"
|
||||
(is (nil? (sut/get-wizard (str (java.util.UUID/randomUUID)))))))
|
||||
Reference in New Issue
Block a user