April 13, 2026

Nullable pattern: Experience report II

back to the future

In the previous experience report I speculated a bit about what the future might hold, once we had the pattern up and running in more of the code base. And great scott, am I happy with the result.

great scott

As the Great Scott once said: "I don’t know if our circuits can handle this alien contraption!". And yet, it turns out she does just fine.

(defdescribe regenerate-password-integration-test
  (it "regenerates password in backend and updates frontend"
    (let [{:keys [backend frontend]}
          (helper.system/unified-setup
           {:fixtures
            {:datomic #{:my-fixtures}}
           {:authenticated? true
            :initial-state  {}})
          public-id        (:my-fixtures fixtures/some-ids)
          initial-password (ffirst
                            (d/q '[:find ?password
                                   :in $ ?pub-id
                                   :where
                                   [?e :some-stuff/id ?pub-id]
                                   [?e :some-stuff/password ?password]]
                                 (d/db (:datomic/conn backend))
                                 (:my-fixtures fixtures/some-ids)))]

      ;; Act: Regenerate password from frontend
      ((:dispatch frontend)
       {}
       [[:action/regenerate-password ::widget-id public-id]])

      ;; Assert: Backend password changed and frontend updated
      (let [new-password (ffirst
                          (d/q '[:find ?password
                                 :in $ ?pub-id
                                 :where
                                 [?e :some-stuff/id ?pub-id]
                                 [?e :some-stuff/password ?password]]
                               (d/db (:datomic/conn backend))
                               (:my-fixtures fixtures/some-ids)))]
        (expect (not= initial-password new-password)
                "Password changed in backend")
        (expect (= new-password
                   (get-in @(:store frontend)
                           [:some-stuff :some-stuff/password]))
                "Frontend has new password")))))

This little piece of code starts up the backend system with the databases we need with our chosen fixtures. In addition to the databases, it also starts up our HTTP handler (the one we use in the system, not a fake one) with all of the middle and routes that are present there.

For the frontend it initiates our nullable js-env, a nullable version of the system that communicates with the backend and all of the nexus actions and effects.

From there we run the action :action/regenerate-password which initiates a chain rection that is exactly the same as in the browser (minus the HTTP transfer layer). In doing so, we have a full integration test from frontend to backend to frontend, along with checks on state changes. Once warmed up, the test takes about 40ms on my machine.

Very nice!

Tags: clojure