Repository: CSCfi/rems
Pull request #3171 (2023-07-05 11:24:56)

Refactor macro utilities
`with-language` and `with-fixed-time` utilities are now macros, instead of functions which require callback function as input. This is purely technical cleanup effort, no functionality should change.

# Checklist for author

Remove items that aren't applicable, check items that are done.

## Follow-up
- [ ] New tasks are created for pending or remaining tasks



Patch:
diff --git a/src/clj/rems/api/applications.clj b/src/clj/rems/api/applications.clj
index 0280566de..04f260a91 100644
--- a/src/clj/rems/api/applications.clj
+++ b/src/clj/rems/api/applications.clj
@@ -323,13 +323,13 @@
       :produces ["application/pdf"]
       (if-let [app (applications/get-application-for-user (getx-user-id) application-id)]
         (with-language context/*lang*
-          #(-> app
-               (pdf/application-to-pdf-bytes)
-               (ByteArrayInputStream.)
-               (ok)
+          (-> app
+              (pdf/application-to-pdf-bytes)
+              (ByteArrayInputStream.)
+              (ok)
                ;; could also set "attachment" here to force download:
-               (header "Content-Disposition" (str "filename=\"" application-id ".pdf\""))
-               (content-type "application/pdf")))
+              (header "Content-Disposition" (str "filename=\"" application-id ".pdf\""))
+              (content-type "application/pdf")))
         (api-util/not-found-json-response)))
 
     (GET "/:application-id/license-attachment/:license-id/:language" []
diff --git a/src/clj/rems/application/bona_fide_bot.clj b/src/clj/rems/application/bona_fide_bot.clj
index c6519825b..c2400bf21 100644
--- a/src/clj/rems/application/bona_fide_bot.clj
+++ b/src/clj/rems/application/bona_fide_bot.clj
@@ -103,70 +103,69 @@
 
 (deftest test-generate-commands
   (with-fixed-time (time/date-time 2010)
-    (fn []
-      (testing "submitted event,"
-        (let [event {:event/type :application.event/submitted
-                     :event/actor "applicant"
-                     :application/id 1234}
-              applicant-attributes {:userid "applicant"
-                                    :email "applicant@example.com"
-                                    :name "An Applicant"}
-              forms [{:form/fields [{:field/type :text
-                                     :field/value "this is text"}
-                                    {:field/type :email
-                                     :field/value "referer92@example.com"}
-                                    {:field/type :date
-                                     :field/value "2020-01-01"}]}]]
-          (testing "bot not handler"
-            (is (empty? (generate-commands event
-                                           applicant-attributes
-                                           {:application/workflow {:workflow.dynamic/handlers [{:userid "handler"}]}
-                                            :application/forms forms}))))
-          (testing "bot is handler"
-            (is (= [{:type :application.command/invite-decider
-                     :time (time/date-time 2010)
-                     :application-id 1234
-                     :actor "bona-fide-bot"
-                     :decider {:name "Referer" :email "referer92@example.com"}}]
-                   (generate-commands event
-                                      applicant-attributes
-                                      {:application/workflow {:workflow.dynamic/handlers [{:userid "handler"}
-                                                                                          {:userid bot-userid}]}
-                                       :application/forms forms}))))))
-      (testing "decided event,"
-        (let [event {:event/type :application.event/decided
-                     :event/actor "referer"
-                     :application/decision :approved
-                     :application/id 1234}
-              referer-attributes {:userid "referer"
-                                  :email "refer2000@example.com"
-                                  :name "Ref Errer"}]
-          (testing "bot not handler"
-            (is (empty? (generate-commands event
-                                           referer-attributes
-                                           {:application/workflow {:workflow.dynamic/handlers [{:userid "handler"}]}}))))
-          (testing "bot is handler,"
-            (let [application {:application/workflow {:workflow.dynamic/handlers [{:userid bot-userid}]}}]
-              (testing "referer does not have researcher status"
-                (is (= [{:type :application.command/reject
-                         :time (time/date-time 2010)
-                         :application-id 1234
-                         :actor "bona-fide-bot"}]
-                       (generate-commands event referer-attributes application))))
-              (testing "referer has researcher status,"
-                (let [referer-attributes (assoc referer-attributes :researcher-status-by "so")]
-                  (testing "referer approves"
-                    (is (= [{:type :application.command/approve
-                             :time (time/date-time 2010)
-                             :application-id 1234
-                             :actor "bona-fide-bot"}]
-                           (generate-commands event referer-attributes application))))
-                  (testing "referer rejects"
-                    (is (= [{:type :application.command/reject
-                             :time (time/date-time 2010)
-                             :application-id 1234
-                             :actor "bona-fide-bot"}]
-                           (generate-commands (assoc event :application/decision :rejected) referer-attributes application)))))))))))))
+    (testing "submitted event,"
+      (let [event {:event/type :application.event/submitted
+                   :event/actor "applicant"
+                   :application/id 1234}
+            applicant-attributes {:userid "applicant"
+                                  :email "applicant@example.com"
+                                  :name "An Applicant"}
+            forms [{:form/fields [{:field/type :text
+                                   :field/value "this is text"}
+                                  {:field/type :email
+                                   :field/value "referer92@example.com"}
+                                  {:field/type :date
+                                   :field/value "2020-01-01"}]}]]
+        (testing "bot not handler"
+          (is (empty? (generate-commands event
+                                         applicant-attributes
+                                         {:application/workflow {:workflow.dynamic/handlers [{:userid "handler"}]}
+                                          :application/forms forms}))))
+        (testing "bot is handler"
+          (is (= [{:type :application.command/invite-decider
+                   :time (time/date-time 2010)
+                   :application-id 1234
+                   :actor "bona-fide-bot"
+                   :decider {:name "Referer" :email "referer92@example.com"}}]
+                 (generate-commands event
+                                    applicant-attributes
+                                    {:application/workflow {:workflow.dynamic/handlers [{:userid "handler"}
+                                                                                        {:userid bot-userid}]}
+                                     :application/forms forms}))))))
+    (testing "decided event,"
+      (let [event {:event/type :application.event/decided
+                   :event/actor "referer"
+                   :application/decision :approved
+                   :application/id 1234}
+            referer-attributes {:userid "referer"
+                                :email "refer2000@example.com"
+                                :name "Ref Errer"}]
+        (testing "bot not handler"
+          (is (empty? (generate-commands event
+                                         referer-attributes
+                                         {:application/workflow {:workflow.dynamic/handlers [{:userid "handler"}]}}))))
+        (testing "bot is handler,"
+          (let [application {:application/workflow {:workflow.dynamic/handlers [{:userid bot-userid}]}}]
+            (testing "referer does not have researcher status"
+              (is (= [{:type :application.command/reject
+                       :time (time/date-time 2010)
+                       :application-id 1234
+                       :actor "bona-fide-bot"}]
+                     (generate-commands event referer-attributes application))))
+            (testing "referer has researcher status,"
+              (let [referer-attributes (assoc referer-attributes :researcher-status-by "so")]
+                (testing "referer approves"
+                  (is (= [{:type :application.command/approve
+                           :time (time/date-time 2010)
+                           :application-id 1234
+                           :actor "bona-fide-bot"}]
+                         (generate-commands event referer-attributes application))))
+                (testing "referer rejects"
+                  (is (= [{:type :application.command/reject
+                           :time (time/date-time 2010)
+                           :application-id 1234
+                           :actor "bona-fide-bot"}]
+                         (generate-commands (assoc event :application/decision :rejected) referer-attributes application))))))))))))
 
 
 
diff --git a/src/clj/rems/application/search.clj b/src/clj/rems/application/search.clj
index 436c241b6..725c068a2 100644
--- a/src/clj/rems/application/search.clj
+++ b/src/clj/rems/application/search.clj
@@ -68,12 +68,12 @@
    :state (->> (:languages env)
                (map (fn [lang]
                       (text/with-language lang
-                        #(text/localize-state (:application/state app)))))
+                        (text/localize-state (:application/state app)))))
                (str/join " "))
    :todo (->> (:languages env)
               (map (fn [lang]
                      (text/with-language lang
-                       #(text/localize-todo (:application/todo app)))))
+                       (text/localize-todo (:application/todo app)))))
               (cons (str (:application/todo app)))
               (str/join " "))
    :form (->> (select [:application/forms ALL :form/fields ALL :field/value] app) ;; TODO: filter out checkboxes, attachments etc?
diff --git a/src/clj/rems/db/csv.clj b/src/clj/rems/db/csv.clj
index 5d4068281..c0489402b 100644
--- a/src/clj/rems/db/csv.clj
+++ b/src/clj/rems/db/csv.clj
@@ -94,11 +94,11 @@
   (if (empty? applications)
     ""
     (text/with-language language
-      #(print-to-csv :column-names (concat (mapv (comp text/text :name) application-columns)
-                                           (form-field-names form-id (first applications)))
-                     :rows (mapv (partial application-to-row form-id) applications)
-                     :quote-strings? true
-                     :strip-line-returns? true))))
+      (print-to-csv :column-names (concat (mapv (comp text/text :name) application-columns)
+                                          (form-field-names form-id (first applications)))
+                    :rows (mapv (partial application-to-row form-id) applications)
+                    :quote-strings? true
+                    :strip-line-returns? true))))
 
 (defn applications-filename []
   (format "applications_%s.csv" (str/replace (text/localize-time (time/now)) " " "_")))
diff --git a/src/clj/rems/email/template.clj b/src/clj/rems/email/template.clj
index 3632e4e94..0fb8d4360 100644
--- a/src/clj/rems/email/template.clj
+++ b/src/clj/rems/email/template.clj
@@ -51,26 +51,25 @@
   (vec
    (for [recipient recipients
          :let [email (with-language (:language (user-settings/get-user-settings (:userid recipient)))
-                       (fn []
-                         (when (and body-text (not (str/blank? (text-no-fallback body-text))))
-                           {:to-user (:userid recipient)
-                            :subject (text-format subject-text
-                                                  (application-util/get-member-name recipient)
-                                                  (application-util/get-member-name (:event/actor-attributes event))
-                                                  (format-application-for-email application)
-                                                  (application-util/get-applicant-name application)
-                                                  (resources-for-email application)
-                                                  (link-to-application (:application/id event)))
-                            :body (str
-                                   (text-format body-text
+                       (when (and body-text (not (str/blank? (text-no-fallback body-text))))
+                         {:to-user (:userid recipient)
+                          :subject (text-format subject-text
                                                 (application-util/get-member-name recipient)
                                                 (application-util/get-member-name (:event/actor-attributes event))
                                                 (format-application-for-email application)
                                                 (application-util/get-applicant-name application)
                                                 (resources-for-email application)
                                                 (link-to-application (:application/id event)))
-                                   (text :t.email/regards)
-                                   (text :t.email/footer))})))]
+                          :body (str
+                                 (text-format body-text
+                                              (application-util/get-member-name recipient)
+                                              (application-util/get-member-name (:event/actor-attributes event))
+                                              (format-application-for-email application)
+                                              (application-util/get-applicant-name application)
+                                              (resources-for-email application)
+                                              (link-to-application (:application/id event)))
+                                 (text :t.email/regards)
+                                 (text :t.email/footer))}))]
          :when email]
      email)))
 
@@ -188,57 +187,54 @@
 
 (defmethod event-to-emails :application.event/member-invited [event application]
   (with-language (:default-language env)
-    (fn []
-      [{:to (:email (:application/member event))
-        :subject (text-format :t.email.member-invited/subject
-                              (:name (:application/member event))
-                              (application-util/get-applicant-name application)
-                              (format-application-for-email application)
-                              (invitation-link (:invitation/token event)))
-        :body (str
-               (text-format :t.email.member-invited/message
+    [{:to (:email (:application/member event))
+      :subject (text-format :t.email.member-invited/subject
                             (:name (:application/member event))
                             (application-util/get-applicant-name application)
                             (format-application-for-email application)
                             (invitation-link (:invitation/token event)))
-               (text :t.email/regards)
-               (text :t.email/footer))}])))
+      :body (str
+             (text-format :t.email.member-invited/message
+                          (:name (:application/member event))
+                          (application-util/get-applicant-name application)
+                          (format-application-for-email application)
+                          (invitation-link (:invitation/token event)))
+             (text :t.email/regards)
+             (text :t.email/footer))}]))
 
 (defmethod event-to-emails :application.event/reviewer-invited [event application]
   (with-language (:default-language env)
-    (fn []
-      [{:to (:email (:application/reviewer event))
-        :subject (text-format :t.email.reviewer-invited/subject
-                              (:name (:application/reviewer event))
-                              (application-util/get-applicant-name application)
-                              (format-application-for-email application)
-                              (invitation-link (:invitation/token event)))
-        :body (str
-               (text-format :t.email.reviewer-invited/message
+    [{:to (:email (:application/reviewer event))
+      :subject (text-format :t.email.reviewer-invited/subject
                             (:name (:application/reviewer event))
                             (application-util/get-applicant-name application)
                             (format-application-for-email application)
                             (invitation-link (:invitation/token event)))
-               (text :t.email/regards)
-               (text :t.email/footer))}])))
+      :body (str
+             (text-format :t.email.reviewer-invited/message
+                          (:name (:application/reviewer event))
+                          (application-util/get-applicant-name application)
+                          (format-application-for-email application)
+                          (invitation-link (:invitation/token event)))
+             (text :t.email/regards)
+             (text :t.email/footer))}]))
 
 (defmethod event-to-emails :application.event/decider-invited [event application]
   (with-language (:default-language env)
-    (fn []
-      [{:to (:email (:application/decider event))
-        :subject (text-format :t.email.decider-invited/subject
-                              (:name (:application/decider event))
-                              (application-util/get-applicant-name application)
-                              (format-application-for-email application)
-                              (invitation-link (:invitation/token event)))
-        :body (str
-               (text-format :t.email.decider-invited/message
+    [{:to (:email (:application/decider event))
+      :subject (text-format :t.email.decider-invited/subject
                             (:name (:application/decider event))
                             (application-util/get-applicant-name application)
                             (format-application-for-email application)
                             (invitation-link (:invitation/token event)))
-               (text :t.email/regards)
-               (text :t.email/footer))}])))
+      :body (str
+             (text-format :t.email.decider-invited/message
+                          (:name (:application/decider event))
+                          (application-util/get-applicant-name application)
+                          (format-application-for-email application)
+                          (invitation-link (:invitation/token event)))
+             (text :t.email/regards)
+             (text :t.email/footer))}]))
 
 (defmethod event-to-emails :application.event/applicant-changed [event application]
   (concat (emails-to-recipients (application-util/applicant-and-members application)
@@ -254,76 +250,72 @@
   (vec
    (for [recipient (application-util/applicant-and-members application)]
      (with-language (:language (user-settings/get-user-settings (:userid recipient)))
-       (fn []
-         {:to-user (:userid recipient)
-          :subject (text-format :t.email.application-expiration-notification/subject-to-member
-                                (application-util/get-member-name recipient)
-                                (format-application-for-email application)
-                                (localize-utc-date (:last-activity event))
-                                (localize-utc-date (:expires-on event))
-                                (link-to-application (:application/id application)))
-          :body (str
-                 (text-format :t.email.application-expiration-notification/message-to-member
+       {:to-user (:userid recipient)
+        :subject (text-format :t.email.application-expiration-notification/subject-to-member
                               (application-util/get-member-name recipient)
                               (format-application-for-email application)
                               (localize-utc-date (:last-activity event))
                               (localize-utc-date (:expires-on event))
                               (link-to-application (:application/id application)))
-                 (text :t.email/regards)
-                 (text :t.email/footer))})))))
+        :body (str
+               (text-format :t.email.application-expiration-notification/message-to-member
+                            (application-util/get-member-name recipient)
+                            (format-application-for-email application)
+                            (localize-utc-date (:last-activity event))
+                            (localize-utc-date (:expires-on event))
+                            (link-to-application (:application/id application)))
+               (text :t.email/regards)
+               (text :t.email/footer))}))))
 
 ;; TODO member-joined?
 
 (defn handler-reminder-email [lang handler applications]
   (with-language lang
-    (fn []
-      (when (not (empty? applications))
-        (let [list (->> applications
-                        (map (fn [application]
-                               (text-format :t.email.handler-reminder/application
-                                            (format-application-for-email application)
-                                            (application-util/get-member-name (:application/applicant application)))))
-                        (str/join "\n"))]
-          {:to-user (:userid handler)
-           :subject (text :t.email.handler-reminder/subject)
-           :body (text-format :t.email.handler-reminder/message
-                              (application-util/get-member-name handler)
-                              list
-                              (str (:public-url env) "actions"))})))))
+    (when (not (empty? applications))
+      (let [list (->> applications
+                      (map (fn [application]
+                             (text-format :t.email.handler-reminder/application
+                                          (format-application-for-email application)
+                                          (application-util/get-member-name (:application/applicant application)))))
+                      (str/join "\n"))]
+        {:to-user (:userid handler)
+         :subject (text :t.email.handler-reminder/subject)
+         :body (text-format :t.email.handler-reminder/message
+                            (application-util/get-member-name handler)
+                            list
+                            (str (:public-url env) "actions"))}))))
 
 (defn reviewer-reminder-email [lang reviewer applications]
   (with-language lang
-    (fn []
-      (when (not (empty? applications))
-        (let [list (->> applications
-                        (map (fn [application]
-                               (text-format :t.email.reviewer-reminder/application
-                                            (format-application-for-email application)
-                                            (application-util/get-member-name (:application/applicant application)))))
-                        (str/join "\n"))]
-          {:to-user (:userid reviewer)
-           :subject (text :t.email.reviewer-reminder/subject)
-           :body (text-format :t.email.reviewer-reminder/message
-                              (application-util/get-member-name reviewer)
-                              list
-                              (str (:public-url env) "actions"))})))))
+    (when (not (empty? applications))
+      (let [list (->> applications
+                      (map (fn [application]
+                             (text-format :t.email.reviewer-reminder/application
+                                          (format-application-for-email application)
+                                          (application-util/get-member-name (:application/applicant application)))))
+                      (str/join "\n"))]
+        {:to-user (:userid reviewer)
+         :subject (text :t.email.reviewer-reminder/subject)
+         :body (text-format :t.email.reviewer-reminder/message
+                            (application-util/get-member-name reviewer)
+                            list
+                            (str (:public-url env) "actions"))}))))
 
 (defn workflow-handler-invitation-email [lang invitation workflow]
   (with-language lang
-    (fn []
-      (when workflow
-        {:to (:invitation/email invitation)
-         :subject (text-format :t.email.workflow-handler-invitation/subject
-                               (:invitation/name invitation)
-                               (get-in invitation [:invitation/invited-by :name])
-                               (:title workflow)
-                               (invitation-link (:invitation/token invitation)))
-         :body (str
-                (text-format :t.email.workflow-handler-invitation/message
+    (when workflow
+      {:to (:invitation/email invitation)
+       :subject (text-format :t.email.workflow-handler-invitation/subject
                              (:invitation/name invitation)
                              (get-in invitation [:invitation/invited-by :name])
                              (:title workflow)
                              (invitation-link (:invitation/token invitation)))
-                (text :t.email/regards)
-                (text :t.email/footer))}))))
+       :body (str
+              (text-format :t.email.workflow-handler-invitation/message
+                           (:invitation/name invitation)
+                           (get-in invitation [:invitation/invited-by :name])
+                           (:title workflow)
+                           (invitation-link (:invitation/token invitation)))
+              (text :t.email/regards)
+              (text :t.email/footer))})))
 
diff --git a/src/clj/rems/layout.clj b/src/clj/rems/layout.clj
index 5569d58e4..3e6473d7f 100644
--- a/src/clj/rems/layout.clj
+++ b/src/clj/rems/layout.clj
@@ -65,34 +65,34 @@
                context/*lang*
                (env :default-language))]
     (with-language lang
-      #(html5 [:html {:lang "en"}
-               (into [:head
-                      [:meta {:http-equiv "Content-Type" :content "text/html; charset=UTF-8"}]
-                      [:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
-                      [:meta {:name "description" :content (text :t.meta/description)}]
-                      [:meta {:name "keywords" :content (text :t.meta/keywords)}]
-                      [:link {:rel "icon" :href "/img/favicon.ico" :type "image/x-icon"}]
-                      [:link {:rel "shortcut icon" :href "/img/favicon.ico" :type "image/x-icon"}]
+      (html5 [:html {:lang "en"}
+              (into [:head
+                     [:meta {:http-equiv "Content-Type" :content "text/html; charset=UTF-8"}]
+                     [:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
+                     [:meta {:name "description" :content (text :t.meta/description)}]
+                     [:meta {:name "keywords" :content (text :t.meta/keywords)}]
+                     [:link {:rel "icon" :href "/img/favicon.ico" :type "image/x-icon"}]
+                     [:link {:rel "shortcut icon" :href "/img/favicon.ico" :type "image/x-icon"}]
 
-                      [:title (text :t.header/title)]
-                      (include-css "/assets/bootstrap/css/bootstrap.min.css")
-                      (include-css "/assets/font-awesome/css/all.css")
-                      (include-css (cache-bust (css-filename context/*lang*)))
-                      (for [extra-stylesheet (get-in env [:extra-stylesheets :files])]
-                        (include-css (cache-bust extra-stylesheet)))]
-                     (logo-preloads))
-               [:body
-                [:div#app app-content]
-                (include-js "/assets/font-awesome/js/fontawesome.js")
-                (include-js "/assets/better-dateinput-polyfill/dist/better-dateinput-polyfill.js")
-                (include-js "/assets/jquery/jquery.min.js")
-                (include-js "/assets/popper.js/dist/umd/popper.min.js")
-                (include-js "/assets/tether/dist/js/tether.min.js")
-                (include-js "/assets/bootstrap/js/bootstrap.min.js")
-                (when (:accessibility-report env) (include-js "/assets/axe-core/axe.min.js"))
-                (for [extra-script (get-in env [:extra-scripts :files])]
-                  (include-js extra-script))
-                content]]))))
+                     [:title (text :t.header/title)]
+                     (include-css "/assets/bootstrap/css/bootstrap.min.css")
+                     (include-css "/assets/font-awesome/css/all.css")
+                     (include-css (cache-bust (css-filename context/*lang*)))
+                     (for [extra-stylesheet (get-in env [:extra-stylesheets :files])]
+                       (include-css (cache-bust extra-stylesheet)))]
+                    (logo-preloads))
+              [:body
+               [:div#app app-content]
+               (include-js "/assets/font-awesome/js/fontawesome.js")
+               (include-js "/assets/better-dateinput-polyfill/dist/better-dateinput-polyfill.js")
+               (include-js "/assets/jquery/jquery.min.js")
+               (include-js "/assets/popper.js/dist/umd/popper.min.js")
+               (include-js "/assets/tether/dist/js/tether.min.js")
+               (include-js "/assets/bootstrap/js/bootstrap.min.js")
+               (when (:accessibility-report env) (include-js "/assets/axe-core/axe.min.js"))
+               (for [extra-script (get-in env [:extra-scripts :files])]
+                 (include-js extra-script))
+               content]]))))
 
 (defn render
   "renders HTML generated by Hiccup
diff --git a/src/clj/rems/pdf.clj b/src/clj/rems/pdf.clj
index 6343350f5..7a2ad32d3 100644
--- a/src/clj/rems/pdf.clj
+++ b/src/clj/rems/pdf.clj
@@ -234,6 +234,6 @@
 
 (comment
   (with-language :en
-    #(clojure.pprint/pprint (render-application application)))
+    (clojure.pprint/pprint (render-application application)))
   (with-language :en
-    #(application-to-pdf application "/tmp/application.pdf")))
+    (application-to-pdf application "/tmp/application.pdf")))
diff --git a/src/cljc/rems/text.cljc b/src/cljc/rems/text.cljc
index 98c94a892..c6175f0ea 100644
--- a/src/cljc/rems/text.cljc
+++ b/src/cljc/rems/text.cljc
@@ -12,11 +12,12 @@
             #?(:clj [rems.locales :as locales])
             [taoensso.tempura :refer [tr]]))
 
-(defn with-language [lang f]
-  (assert (keyword? lang) {:lang lang})
-  #?(:clj (binding [context/*lang* lang
-                    context/*tempura* (partial tr (locales/tempura-config) [lang])]
-            (f))))
+#?(:clj
+   (defmacro with-language [lang & body]
+     `(binding [rems.context/*lang* ~lang
+                rems.context/*tempura* (partial tr (rems.locales/tempura-config) [~lang])]
+        (assert (keyword? ~lang) {:lang ~lang})
+        ~@body)))
 
 (defn- failsafe-fallback
   "Fallback for when loading the translations has failed."


Test patch:
diff --git a/test/clj/rems/api/test_applications.clj b/test/clj/rems/api/test_applications.clj
index d943c23a7..2379bce6a 100644
--- a/test/clj/rems/api/test_applications.clj
+++ b/test/clj/rems/api/test_applications.clj
@@ -583,15 +583,13 @@
                                          :enable-save-compaction true)]
       (testing "save draft"
         (with-fixed-time (time/date-time 2022 1 1)
-          (fn []
-
-            (is (= {:success true}
-                   (send-command user-id
-                                 {:type :application.command/save-draft
-                                  :application-id application-id
-                                  :field-values [{:form form-id
-                                                  :field "field"
-                                                  :value "1"}]}))))))
+          (is (= {:success true}
+                 (send-command user-id
+                               {:type :application.command/save-draft
+                                :application-id application-id
+                                :field-values [{:form form-id
+                                                :field "field"
+                                                :value "1"}]})))))
 
       (testing "application has one save event"
         (let [application (get-application-for-user application-id user-id)]
@@ -616,14 +614,13 @@
 
       (testing "save draft again"
         (with-fixed-time (time/date-time 2022 1 2)
-          (fn []
-            (is (= {:success true}
-                   (send-command user-id
-                                 {:type :application.command/save-draft
-                                  :application-id application-id
-                                  :field-values [{:form form-id
-                                                  :field "field"
-                                                  :value "2"}]}))))))
+          (is (= {:success true}
+                 (send-command user-id
+                               {:type :application.command/save-draft
+                                :application-id application-id
+                                :field-values [{:form form-id
+                                                :field "field"
+                                                :value "2"}]})))))
 
       (testing "application still has one save event"
         (let [application (get-application-for-user application-id user-id)]
diff --git a/test/clj/rems/api/test_entitlements.clj b/test/clj/rems/api/test_entitlements.clj
index 3547e68f4..342a2f3ff 100644
--- a/test/clj/rems/api/test_entitlements.clj
+++ b/test/clj/rems/api/test_entitlements.clj
@@ -55,130 +55,129 @@
 
 (deftest entitlements-test
   (with-fixed-time (time/date-time 2010)
-    (fn []
-      (api-key/add-api-key! api-key {})
-      (test-helpers/create-user! {:userid "alice" :name "Alice Applicant" :email "alice@example.com" :nickname "In Wonderland"})
-      ;; don't set malice's email to test the api with nil emails
-      (test-helpers/create-user! {:userid "malice" :name "Malice Applicant"})
-      (test-helpers/create-user! {:userid "handler"})
-      ;; owner is automatically created by (test-helpers/create-resource!) but here for consistency
-      (test-helpers/create-user! {:userid "owner"} :owner)
-      (test-helpers/create-user! {:userid "reporter"} :reporter)
-      (let [res-id (test-helpers/create-resource! {:resource-ext-id "urn:nbn:fi:lb-201403262"})
-            wf-id (test-helpers/create-workflow! {:type :workflow/default :handlers ["handler"]})
-            form-id (test-helpers/create-form! {})
-            cat-id (test-helpers/create-catalogue-item! {:resource-id res-id :form-id form-id :workflow-id wf-id})
-            app-id (test-helpers/create-application! {:actor "alice" :catalogue-item-ids [cat-id]})
-            expired-app-id (test-helpers/create-application! {:actor "alice" :catalogue-item-ids [cat-id]})
-            malice-app-id (test-helpers/create-application! {:actor "malice" :catalogue-item-ids [cat-id]})]
-        (testing "set up data"
-          (test-helpers/command! {:type :application.command/submit
-                                  :application-id app-id
-                                  :actor "alice"})
-          (test-helpers/command! {:type :application.command/approve
-                                  :application-id app-id
-                                  :actor "handler"})
-          (test-helpers/command! {:type :application.command/submit
-                                  :application-id expired-app-id
-                                  :actor "alice"})
-          (test-helpers/command! {:type :application.command/approve
-                                  :application-id expired-app-id
-                                  :actor "handler"})
-          (test-helpers/command! {:type :application.command/close
-                                  :application-id expired-app-id
-                                  :actor "handler"})
-          (test-helpers/command! {:type :application.command/submit
-                                  :application-id malice-app-id
-                                  :actor "malice"})
-          (test-helpers/command! {:type :application.command/approve
-                                  :application-id malice-app-id
-                                  :actor "handler"
-                                  :entitlement-end (time/date-time 2100 01 01)}))
-        (testing "listing without authentication"
-          (doseq [endpoint ["/api/entitlements" "/api/entitlements/export-csv"]]
-            (testing endpoint
-              (is (response-is-unauthorized? (api-response :get endpoint))))))
-
-        (testing "all"
-          (let [data (api-call :get "/api/entitlements" nil api-key "handler")]
+    (api-key/add-api-key! api-key {})
+    (test-helpers/create-user! {:userid "alice" :name "Alice Applicant" :email "alice@example.com" :nickname "In Wonderland"})
+    ;; don't set malice's email to test the api with nil emails
+    (test-helpers/create-user! {:userid "malice" :name "Malice Applicant"})
+    (test-helpers/create-user! {:userid "handler"})
+    ;; owner is automatically created by (test-helpers/create-resource!) but here for consistency
+    (test-helpers/create-user! {:userid "owner"} :owner)
+    (test-helpers/create-user! {:userid "reporter"} :reporter)
+    (let [res-id (test-helpers/create-resource! {:resource-ext-id "urn:nbn:fi:lb-201403262"})
+          wf-id (test-helpers/create-workflow! {:type :workflow/default :handlers ["handler"]})
+          form-id (test-helpers/create-form! {})
+          cat-id (test-helpers/create-catalogue-item! {:resource-id res-id :form-id form-id :workflow-id wf-id})
+          app-id (test-helpers/create-application! {:actor "alice" :catalogue-item-ids [cat-id]})
+          expired-app-id (test-helpers/create-application! {:actor "alice" :catalogue-item-ids [cat-id]})
+          malice-app-id (test-helpers/create-application! {:actor "malice" :catalogue-item-ids [cat-id]})]
+      (testing "set up data"
+        (test-helpers/command! {:type :application.command/submit
+                                :application-id app-id
+                                :actor "alice"})
+        (test-helpers/command! {:type :application.command/approve
+                                :application-id app-id
+                                :actor "handler"})
+        (test-helpers/command! {:type :application.command/submit
+                                :application-id expired-app-id
+                                :actor "alice"})
+        (test-helpers/command! {:type :application.command/approve
+                                :application-id expired-app-id
+                                :actor "handler"})
+        (test-helpers/command! {:type :application.command/close
+                                :application-id expired-app-id
+                                :actor "handler"})
+        (test-helpers/command! {:type :application.command/submit
+                                :application-id malice-app-id
+                                :actor "malice"})
+        (test-helpers/command! {:type :application.command/approve
+                                :application-id malice-app-id
+                                :actor "handler"
+                                :entitlement-end (time/date-time 2100 01 01)}))
+      (testing "listing without authentication"
+        (doseq [endpoint ["/api/entitlements" "/api/entitlements/export-csv"]]
+          (testing endpoint
+            (is (response-is-unauthorized? (api-response :get endpoint))))))
+
+      (testing "all"
+        (let [data (api-call :get "/api/entitlements" nil api-key "handler")]
+          (is (= 2 (count data)))
+          (check-alice-entitlement (first data))
+          (check-malice-entitlement (second data))))
+
+      (doseq [userid ["handler" "owner" "reporter"]]
+        (testing (str "all as " userid)
+          (let [data (api-call :get "/api/entitlements" nil api-key userid)]
             (is (= 2 (count data)))
             (check-alice-entitlement (first data))
-            (check-malice-entitlement (second data))))
-
-        (doseq [userid ["handler" "owner" "reporter"]]
-          (testing (str "all as " userid)
-            (let [data (api-call :get "/api/entitlements" nil api-key userid)]
-              (is (= 2 (count data)))
-              (check-alice-entitlement (first data))
-              (check-malice-entitlement (second data)))))
-
-        (testing "for one resource"
-          (let [data (api-call :get "/api/entitlements?resource=urn:nbn:fi:lb-201403262" nil api-key "handler")]
-            (is (= 2 (count data)))
-            (check-alice-entitlement (first data))
-            (check-malice-entitlement (second data))))
-
-        (testing "just for alice as a handler"
-          (let [data (api-call :get "/api/entitlements?user=alice" nil api-key "handler")]
-            (is (= 1 (count data)))
-            (check-alice-entitlement (first data))))
-
-        (testing "just for alice as an owner"
-          (let [data (api-call :get "/api/entitlements?user=alice" nil api-key "owner")]
-            (is (= 1 (count data)))
-            (check-alice-entitlement (first data))))
-
-        (testing "also expired / ended as an owner"
-          (let [data (api-call :get "/api/entitlements?expired=true" nil api-key "owner")]
-            (is (= 3 (count data)))
-            (check-alice-entitlement (first data))
-            (check-alice-expired-entitlement (second data))
-            (check-malice-entitlement (nth data 2))))
-
-        (testing "just for alice as a reporter"
-          (let [data (api-call :get "/api/entitlements?user=alice" nil api-key "reporter")]
-            (is (= 1 (count data)))
-            (check-alice-entitlement (first data))))
-
-        (testing "listing as applicant"
-          (testing "with entitlements"
-            (let [data (api-call :get "/api/entitlements" nil api-key "alice")]
-              (is (coll-is-not-empty? data))
-              (doseq [x data]
-                (check-alice-entitlement x))))
-
-          (testing "without entitlements"
-            (test-helpers/create-user! {:userid "allison"})
-            (is (coll-is-empty?
-                 (api-call :get "/api/entitlements" nil api-key "allison")))))
-
-        (testing "export entitlements csv"
-          (let [api "/api/entitlements/export-csv"]
-            (doseq [user #{"handler" "reporter"}
-                    :let [get-entitlements-csv (fn [& {:keys [separator] :as query-params}]
-                                                 (-> (api-response :get api nil api-key user query-params)
-                                                     (read-ok-csv {:separator (or separator ",")})))]]
+            (check-malice-entitlement (second data)))))
+
+      (testing "for one resource"
+        (let [data (api-call :get "/api/entitlements?resource=urn:nbn:fi:lb-201403262" nil api-key "handler")]
+          (is (= 2 (count data)))
+          (check-alice-entitlement (first data))
+          (check-malice-entitlement (second data))))
+
+      (testing "just for alice as a handler"
+        (let [data (api-call :get "/api/entitlements?user=alice" nil api-key "handler")]
+          (is (= 1 (count data)))
+          (check-alice-entitlement (first data))))
+
+      (testing "just for alice as an owner"
+        (let [data (api-call :get "/api/entitlements?user=alice" nil api-key "owner")]
+          (is (= 1 (count data)))
+          (check-alice-entitlement (first data))))
+
+      (testing "also expired / ended as an owner"
+        (let [data (api-call :get "/api/entitlements?expired=true" nil api-key "owner")]
+          (is (= 3 (count data)))
+          (check-alice-entitlement (first data))
+          (check-alice-expired-entitlement (second data))
+          (check-malice-entitlement (nth data 2))))
+
+      (testing "just for alice as a reporter"
+        (let [data (api-call :get "/api/entitlements?user=alice" nil api-key "reporter")]
+          (is (= 1 (count data)))
+          (check-alice-entitlement (first data))))
+
+      (testing "listing as applicant"
+        (testing "with entitlements"
+          (let [data (api-call :get "/api/entitlements" nil api-key "alice")]
+            (is (coll-is-not-empty? data))
+            (doseq [x data]
+              (check-alice-entitlement x))))
+
+        (testing "without entitlements"
+          (test-helpers/create-user! {:userid "allison"})
+          (is (coll-is-empty?
+               (api-call :get "/api/entitlements" nil api-key "allison")))))
+
+      (testing "export entitlements csv"
+        (let [api "/api/entitlements/export-csv"]
+          (doseq [user #{"handler" "reporter"}
+                  :let [get-entitlements-csv (fn [& {:keys [separator] :as query-params}]
+                                               (-> (api-response :get api nil api-key user query-params)
+                                                   (read-ok-csv {:separator (or separator ",")})))]]
+            (testing (str "as " user)
+              (is (= [["resource" "application" "user" "start"]
+                      ["urn:nbn:fi:lb-201403262" (str app-id) "alice" "2010-01-01T00:00:00.000Z"]
+                      ["urn:nbn:fi:lb-201403262" (str expired-app-id) "alice" "2010-01-01T00:00:00.000Z"]
+                      ["urn:nbn:fi:lb-201403262" (str malice-app-id) "malice" "2010-01-01T00:00:00.000Z"]]
+                     (get-entitlements-csv {:separator ";" :resource "urn:nbn:fi:lb-201403262"})
+                     (get-entitlements-csv))) ; backwards compatibility
+              (is (= [["resource" "application" "user" "start"]
+                      ["urn:nbn:fi:lb-201403262" (str app-id) "alice" "2010-01-01T00:00:00.000Z"]]
+                     (get-entitlements-csv {:separator "\t" :user "alice" :expired false})))
+              (is (= [["resource" "application" "user" "start"]
+                      ["urn:nbn:fi:lb-201403262" (str malice-app-id) "malice" "2010-01-01T00:00:00.000Z"]]
+                     (get-entitlements-csv {:user "malice"})))))
+          (testing "without proper role"
+            (doseq [user ["alice" "malice" "owner"]]
               (testing (str "as " user)
-                (is (= [["resource" "application" "user" "start"]
-                        ["urn:nbn:fi:lb-201403262" (str app-id) "alice" "2010-01-01T00:00:00.000Z"]
-                        ["urn:nbn:fi:lb-201403262" (str expired-app-id) "alice" "2010-01-01T00:00:00.000Z"]
-                        ["urn:nbn:fi:lb-201403262" (str malice-app-id) "malice" "2010-01-01T00:00:00.000Z"]]
-                       (get-entitlements-csv {:separator ";" :resource "urn:nbn:fi:lb-201403262"})
-                       (get-entitlements-csv))) ; backwards compatibility
-                (is (= [["resource" "application" "user" "start"]
-                        ["urn:nbn:fi:lb-201403262" (str app-id) "alice" "2010-01-01T00:00:00.000Z"]]
-                       (get-entitlements-csv {:separator "\t" :user "alice" :expired false})))
-                (is (= [["resource" "application" "user" "start"]
-                        ["urn:nbn:fi:lb-201403262" (str malice-app-id) "malice" "2010-01-01T00:00:00.000Z"]]
-                       (get-entitlements-csv {:user "malice"})))))
-            (testing "without proper role"
-              (doseq [user ["alice" "malice" "owner"]]
-                (testing (str "as " user)
-                  (is (response-is-forbidden?
-                       (api-response :get api nil api-key user))))))
-            (testing "redirect /entitlements.csv"
-              (let [response (-> (api-response :get "/entitlements.csv" nil api-key "handler")
-                                 (assert-response-is-redirect))]
-                (is (-> (get-redirect-location response)
-                        (str/ends-with? api)))))))))))
+                (is (response-is-forbidden?
+                     (api-response :get api nil api-key user))))))
+          (testing "redirect /entitlements.csv"
+            (let [response (-> (api-response :get "/entitlements.csv" nil api-key "handler")
+                               (assert-response-is-redirect))]
+              (is (-> (get-redirect-location response)
+                      (str/ends-with? api))))))))))
 
diff --git a/test/clj/rems/api/test_user_settings.clj b/test/clj/rems/api/test_user_settings.clj
index 2cd5690c0..d867a2c6f 100644
--- a/test/clj/rems/api/test_user_settings.clj
+++ b/test/clj/rems/api/test_user_settings.clj
@@ -108,27 +108,26 @@
     (testing "success"
       (with-fake-login-users {user-id {:sub user-id :name "Test User" :email "test.user@example.com"}}
         (with-fixed-time (time-core/date-time 2021)
-          (fn []
-            (run-with-ega-server
-             {"/p/api_key/generate" {:status 200 :content-type "application/json" :body (json/generate-string {:token "access-token-xyz"})}}
-             (fn [_server]
-               (let [cookie (login-with-cookies user-id)
-                     csrf (get-csrf-token cookie)]
-                 (testing "generate-ega-api-key with session"
-                   (is (= {:status 200
-                           :body {:success true
-                                  :api-key-expiration-date "2022-01-01T00:00:00.000Z"}} ; one year expiry
-                          (-> (request :post "/api/user-settings/generate-ega-api-key")
-                              (header "Cookie" cookie)
-                              (header "x-csrf-token" csrf)
-                              handler
-                              assert-response-is-ok
-                              read-body-and-status)))
-                   (is (= (time-core/date-time 2022)
-                          (get-in (user-settings/get-user-settings user-id) [:ega :api-key-expiration-date]))
-                       "one year expiry")
-                   (is (= {:ega {:api-key "access-token-xyz"}}
-                          (user-secrets/get-user-secrets user-id)))))))))))))
+          (run-with-ega-server
+           {"/p/api_key/generate" {:status 200 :content-type "application/json" :body (json/generate-string {:token "access-token-xyz"})}}
+           (fn [_server]
+             (let [cookie (login-with-cookies user-id)
+                   csrf (get-csrf-token cookie)]
+               (testing "generate-ega-api-key with session"
+                 (is (= {:status 200
+                         :body {:success true
+                                :api-key-expiration-date "2022-01-01T00:00:00.000Z"}} ; one year expiry
+                        (-> (request :post "/api/user-settings/generate-ega-api-key")
+                            (header "Cookie" cookie)
+                            (header "x-csrf-token" csrf)
+                            handler
+                            assert-response-is-ok
+                            read-body-and-status)))
+                 (is (= (time-core/date-time 2022)
+                        (get-in (user-settings/get-user-settings user-id) [:ega :api-key-expiration-date]))
+                     "one year expiry")
+                 (is (= {:ega {:api-key "access-token-xyz"}}
+                        (user-secrets/get-user-secrets user-id))))))))))))
 
 (deftest test-delete-api-key
   (test-data/create-test-api-key!)
@@ -141,22 +140,21 @@
     (testing "setup api-key to delete"
       (with-fake-login-users {handler-id {:sub handler-id :name "Handler" :email "handler@example.com"}}
         (with-fixed-time (time-core/date-time 2021)
-          (fn []
-            (run-with-ega-server
-             {"/p/api_key/generate" {:status 200 :content-type "application/json" :body (json/generate-string {:token "access-token-xyz"})}}
-             (fn [_server]
-               (let [cookie (login-with-cookies handler-id)
-                     csrf (get-csrf-token cookie)]
-                 (testing "generate-ega-api-key with session"
-                   (is (= {:status 200
-                           :body {:success true
-                                  :api-key-expiration-date "2022-01-01T00:00:00.000Z"}}
-                          (-> (request :post "/api/user-settings/generate-ega-api-key")
-                              (header "Cookie" cookie)
-                              (header "x-csrf-token" csrf)
-                              handler
-                              assert-response-is-ok
-                              read-body-and-status)))))))))))
+          (run-with-ega-server
+           {"/p/api_key/generate" {:status 200 :content-type "application/json" :body (json/generate-string {:token "access-token-xyz"})}}
+           (fn [_server]
+             (let [cookie (login-with-cookies handler-id)
+                   csrf (get-csrf-token cookie)]
+               (testing "generate-ega-api-key with session"
+                 (is (= {:status 200
+                         :body {:success true
+                                :api-key-expiration-date "2022-01-01T00:00:00.000Z"}}
+                        (-> (request :post "/api/user-settings/generate-ega-api-key")
+                            (header "Cookie" cookie)
+                            (header "x-csrf-token" csrf)
+                            handler
+                            assert-response-is-ok
+                            read-body-and-status))))))))))
 
     (testing "without authentication"
       (let [{:keys [body] :as response} (-> (request :post "/api/user-settings/delete-ega-api-key")
@@ -186,19 +184,18 @@
     (testing "success"
       (with-fake-login-users {handler-id {:sub handler-id :name "Handler" :email "handler@example.com"}}
         (with-fixed-time (time-core/date-time 2021)
-          (fn []
-            (run-with-ega-server
-             {{:path (str "/p/api_key/" handler-id) :method "DELETE"} {:status 200 :content-type "application/json" :body ""}}
-             (fn [server]
-               (let [cookie (login-with-cookies handler-id)
-                     csrf (get-csrf-token cookie)]
-                 (testing "delete-ega-api-key with session"
-                   (is (= {:status 200
-                           :body {:success true}}
-                          (-> (request :post "/api/user-settings/delete-ega-api-key")
-                              (header "Cookie" cookie)
-                              (header "x-csrf-token" csrf)
-                              handler
-                              assert-response-is-ok
-                              read-body-and-status)))))))))))))
+          (run-with-ega-server
+           {{:path (str "/p/api_key/" handler-id) :method "DELETE"} {:status 200 :content-type "application/json" :body ""}}
+           (fn [server]
+             (let [cookie (login-with-cookies handler-id)
+                   csrf (get-csrf-token cookie)]
+               (testing "delete-ega-api-key with session"
+                 (is (= {:status 200
+                         :body {:success true}}
+                        (-> (request :post "/api/user-settings/delete-ega-api-key")
+                            (header "Cookie" cookie)
+                            (header "x-csrf-token" csrf)
+                            handler
+                            assert-response-is-ok
+                            read-body-and-status))))))))))))
 
diff --git a/test/clj/rems/application/test_commands.clj b/test/clj/rems/application/test_commands.clj
index 8b313db1f..6d0ab1e4a 100644
--- a/test/clj/rems/application/test_commands.clj
+++ b/test/clj/rems/application/test_commands.clj
@@ -927,13 +927,12 @@
             :application/id app-id
             :application/comment "fine"}
            (with-fixed-time (DateTime. 1234)
-             (fn []
-               (ok-command {:type :application.command/approve
-                            :actor handler-user-id
-                            :entitlement-end (time/plus (DateTime. 1234) (time/days 1))
-                            :comment "fine"}
-                           (build-application-view [dummy-created-event
-                                                    dummy-submitted-event])))))))
+             (ok-command {:type :application.command/approve
+                          :actor handler-user-id
+                          :entitlement-end (time/plus (DateTime. 1234) (time/days 1))
+                          :comment "fine"}
+                         (build-application-view [dummy-created-event
+                                                  dummy-submitted-event]))))))
   (testing "rejected successfully"
     (is (= {:event/type :application.event/rejected
             :application/comment "bad"
diff --git a/test/clj/rems/application/test_eraser.clj b/test/clj/rems/application/test_eraser.clj
index f7e863403..3b2fc8691 100644
--- a/test/clj/rems/application/test_eraser.clj
+++ b/test/clj/rems/application/test_eraser.clj
@@ -137,88 +137,87 @@
 (deftest test-send-reminder-email
   (binding [command/*fail-on-process-manager-errors* true]
     (with-fixed-time (time/date-time 2022)
-      (fn []
-        (test-helpers/create-user! {:userid "alice"})
-        (test-helpers/create-user! {:userid "member"})
-        (test-helpers/create-user! {:userid expirer-bot/bot-userid})
-        (roles/add-role! expirer-bot/bot-userid :expirer)
-        (let [now (time/now)
-              draft-expires-in-6d (create-application! {:draft? true
-                                                        :date-time (time/minus now (time/days 84))
-                                                        :actor "alice"
-                                                        :members [{:userid "member"
-                                                                   :name "Member"
-                                                                   :email "member@example.com"}]})
-              draft-expires-in-8d (create-application! {:draft? true
-                                                        :date-time (time/minus now (time/days 82))
-                                                        :actor "alice"})
-              submitted (create-application! {:date-time (time/minus now (time/days 84))
-                                              :actor "alice"})
-              outbox-emails (atom [])]
-          (with-redefs [outbox/put! (fn [email] (swap! outbox-emails conj email))]
-
-            (testing "should not send reminder because config is missing or partially correct"
-              (doseq [mock-env [{:application-expiration {:application.state/draft {:delete-after "P90D"}}}
-                                {:application-expiration {:application.state/draft {:reminder-before "P7D"}}}
-                                {:application-expiration nil}]]
-                (with-redefs [env mock-env]
-                  (eraser/process-applications!))
-                (is (= #{draft-expires-in-6d draft-expires-in-8d submitted}
-                       (set (get-all-application-ids "alice"))))
-                (is (empty? @outbox-emails))
-                (is (empty? (expiration-notification-events draft-expires-in-6d)))
-                (is (empty? (expiration-notification-events draft-expires-in-8d)))
-                (is (empty? (expiration-notification-events submitted)))))
-
-            (testing "send expiration notifications"
-              (with-redefs [env {:application-expiration {:application.state/draft {:delete-after "P90D"
-                                                                                    :reminder-before "P7D"}}
-                                 :application-id-column :id
-                                 :public-url "localhost/"}
-                            user-settings/get-user-settings (constantly {:language :en})]
+      (test-helpers/create-user! {:userid "alice"})
+      (test-helpers/create-user! {:userid "member"})
+      (test-helpers/create-user! {:userid expirer-bot/bot-userid})
+      (roles/add-role! expirer-bot/bot-userid :expirer)
+      (let [now (time/now)
+            draft-expires-in-6d (create-application! {:draft? true
+                                                      :date-time (time/minus now (time/days 84))
+                                                      :actor "alice"
+                                                      :members [{:userid "member"
+                                                                 :name "Member"
+                                                                 :email "member@example.com"}]})
+            draft-expires-in-8d (create-application! {:draft? true
+                                                      :date-time (time/minus now (time/days 82))
+                                                      :actor "alice"})
+            submitted (create-application! {:date-time (time/minus now (time/days 84))
+                                            :actor "alice"})
+            outbox-emails (atom [])]
+        (with-redefs [outbox/put! (fn [email] (swap! outbox-emails conj email))]
+
+          (testing "should not send reminder because config is missing or partially correct"
+            (doseq [mock-env [{:application-expiration {:application.state/draft {:delete-after "P90D"}}}
+                              {:application-expiration {:application.state/draft {:reminder-before "P7D"}}}
+                              {:application-expiration nil}]]
+              (with-redefs [env mock-env]
+                (eraser/process-applications!))
+              (is (= #{draft-expires-in-6d draft-expires-in-8d submitted}
+                     (set (get-all-application-ids "alice"))))
+              (is (empty? @outbox-emails))
+              (is (empty? (expiration-notification-events draft-expires-in-6d)))
+              (is (empty? (expiration-notification-events draft-expires-in-8d)))
+              (is (empty? (expiration-notification-events submitted)))))
+
+          (testing "send expiration notifications"
+            (with-redefs [env {:application-expiration {:application.state/draft {:delete-after "P90D"
+                                                                                  :reminder-before "P7D"}}
+                               :application-id-column :id
+                               :public-url "localhost/"}
+                          user-settings/get-user-settings (constantly {:language :en})]
+              (eraser/process-applications!)
+              (is (= #{draft-expires-in-6d draft-expires-in-8d submitted}
+                     (set (get-all-application-ids "alice")))
+                  "no applications have been deleted")
+              (is (empty? (expiration-notification-events draft-expires-in-8d)))
+              (is (empty? (expiration-notification-events submitted)))
+
+              (testing "expiration notifications sent event was created for draft expiring in 6 days"
+                (let [events (expiration-notification-events draft-expires-in-6d)]
+                  (is (= 1 (count events)))
+                  (is (time/equal? (time/plus now (time/days 6)) (:expires-on (first events))))
+                  (is (time/equal? (time/minus now (time/days 84)) (:last-activity (first events))))
+                  (is (time/equal? now (:event-time (first events))))))
+              (is (= [{:outbox/deadline (time/date-time 2022)
+                       :outbox/email {:subject (str "Your unsubmitted application " draft-expires-in-6d " will be deleted soon")
+                                      :body (str "Dear alice,\n\n"
+                                                 "Your unsubmitted application has been inactive since 2021-10-09 and it will be deleted after 2022-01-07, if it is not edited.\n\n"
+                                                 "You can view and edit the application at localhost/application/" draft-expires-in-6d)
+                                      :to-user "alice"}
+                       :outbox/type :email}
+                      {:outbox/deadline (time/date-time 2022)
+                       :outbox/email {:subject (str "Your unsubmitted application " draft-expires-in-6d " will be deleted soon")
+                                      :body (str "Dear member,\n\n"
+                                                 "Your unsubmitted application has been inactive since 2021-10-09 and it will be deleted after 2022-01-07, if it is not edited.\n\n"
+                                                 "You can view and edit the application at localhost/application/" draft-expires-in-6d)
+                                      :to-user "member"}
+                       :outbox/type :email}]
+                     @outbox-emails))
+
+              (testing "processing applications again should not send new notifications"
+                (reset! outbox-emails [])
                 (eraser/process-applications!)
                 (is (= #{draft-expires-in-6d draft-expires-in-8d submitted}
                        (set (get-all-application-ids "alice")))
                     "no applications have been deleted")
                 (is (empty? (expiration-notification-events draft-expires-in-8d)))
                 (is (empty? (expiration-notification-events submitted)))
+                (is (empty? @outbox-emails))
 
-                (testing "expiration notifications sent event was created for draft expiring in 6 days"
+                (testing "expiration notifications events have not changed for draft expiring in 6 days"
                   (let [events (expiration-notification-events draft-expires-in-6d)]
                     (is (= 1 (count events)))
                     (is (time/equal? (time/plus now (time/days 6)) (:expires-on (first events))))
                     (is (time/equal? (time/minus now (time/days 84)) (:last-activity (first events))))
-                    (is (time/equal? now (:event-time (first events))))))
-                (is (= [{:outbox/deadline (time/date-time 2022)
-                         :outbox/email {:subject (str "Your unsubmitted application " draft-expires-in-6d " will be deleted soon")
-                                        :body (str "Dear alice,\n\n"
-                                                   "Your unsubmitted application has been inactive since 2021-10-09 and it will be deleted after 2022-01-07, if it is not edited.\n\n"
-                                                   "You can view and edit the application at localhost/application/" draft-expires-in-6d)
-                                        :to-user "alice"}
-                         :outbox/type :email}
-                        {:outbox/deadline (time/date-time 2022)
-                         :outbox/email {:subject (str "Your unsubmitted application " draft-expires-in-6d " will be deleted soon")
-                                        :body (str "Dear member,\n\n"
-                                                   "Your unsubmitted application has been inactive since 2021-10-09 and it will be deleted after 2022-01-07, if it is not edited.\n\n"
-                                                   "You can view and edit the application at localhost/application/" draft-expires-in-6d)
-                                        :to-user "member"}
-                         :outbox/type :email}]
-                       @outbox-emails))
-
-                (testing "processing applications again should not send new notifications"
-                  (reset! outbox-emails [])
-                  (eraser/process-applications!)
-                  (is (= #{draft-expires-in-6d draft-expires-in-8d submitted}
-                         (set (get-all-application-ids "alice")))
-                      "no applications have been deleted")
-                  (is (empty? (expiration-notification-events draft-expires-in-8d)))
-                  (is (empty? (expiration-notification-events submitted)))
-                  (is (empty? @outbox-emails))
-
-                  (testing "expiration notifications events have not changed for draft expiring in 6 days"
-                    (let [events (expiration-notification-events draft-expires-in-6d)]
-                      (is (= 1 (count events)))
-                      (is (time/equal? (time/plus now (time/days 6)) (:expires-on (first events))))
-                      (is (time/equal? (time/minus now (time/days 84)) (:last-activity (first events))))
-                      (is (time/equal? now (:event-time (first events)))))))))))))))
+                    (is (time/equal? now (:event-time (first events))))))))))))))
 
diff --git a/test/clj/rems/db/test_entitlements.clj b/test/clj/rems/db/test_entitlements.clj
index 671ac04c9..1eebcd915 100644
--- a/test/clj/rems/db/test_entitlements.clj
+++ b/test/clj/rems/db/test_entitlements.clj
@@ -8,7 +8,7 @@
             [rems.db.test-data-helpers :as test-helpers]
             [rems.db.testing :refer [reset-caches-fixture test-db-fixture rollback-db-fixture]]
             [rems.json :as json]
-            [rems.testing-util :refer [fixed-time-fixture suppress-logging]]
+            [rems.testing-util :refer [fixed-time-fixture suppress-logging-fixture]]
             [stub-http.core :as stub]))
 
 (def +test-time+ (time/date-time 2050 01 01)) ;; needs to be in the future so that catalogue items are active
@@ -17,7 +17,7 @@
 (use-fixtures
   :once
   (fixed-time-fixture +test-time+)
-  (suppress-logging "rems.db.entitlements")
+  (suppress-logging-fixture "rems.db.entitlements")
   test-db-fixture
   rollback-db-fixture
   reset-caches-fixture)
diff --git a/test/clj/rems/email/test_template.clj b/test/clj/rems/email/test_template.clj
index 9a8543061..432e2b4e1 100644
--- a/test/clj/rems/email/test_template.clj
+++ b/test/clj/rems/email/test_template.clj
@@ -536,10 +536,10 @@
                       :application/member {:userid "member"}}
           member-events (conj created-events add-member)
           notifications-sent (with-fixed-time (time/date-time 2023 6 19)
-                               #(do {:application/id 7
-                                     :event/type :application.event/expiration-notifications-sent
-                                     :expires-on (time/plus (time/now) (time/days 7))
-                                     :last-activity (time/minus (time/now) (time/days 83))}))]
+                               {:application/id 7
+                                :event/type :application.event/expiration-notifications-sent
+                                :expires-on (time/plus (time/now) (time/days 7))
+                                :last-activity (time/minus (time/now) (time/days 83))})]
       (is (= [{:to-user "applicant"
                :subject "Your unsubmitted application 2001/3, \"Application title\" will be deleted soon"
                :body "Dear Alice Applicant,\n\nYour unsubmitted application has been inactive since 2023-03-28 and it will be deleted after 2023-06-26, if it is not edited.\n\nYou can view and edit the application at http://example.com/application/7"}
diff --git a/test/clj/rems/test_browser.clj b/test/clj/rems/test_browser.clj
index ff031333b..542e28323 100644
--- a/test/clj/rems/test_browser.clj
+++ b/test/clj/rems/test_browser.clj
@@ -30,7 +30,7 @@
             [rems.db.user-settings :as user-settings]
             [rems.main]
             [rems.testing-util :refer [with-user with-fake-login-users]]
-            [rems.text :as text]))
+            [rems.text :refer [localize-time text with-language]]))
 
 (comment ; convenience for development testing
   (btu/init-driver! :chrome "http://localhost:3000/" :development))
@@ -117,10 +117,10 @@
   (btu/scroll-and-click [{:css ".language-switcher"} {:fn/text (.toUpperCase (name language))}])
   ;; wait for the new language to take effect
   (btu/wait-predicate #(= (btu/value-of [{:css ".footer-text"}])
-                          (text/with-language language
-                            (fn [] (text/text :t/footer))))))
+                          (with-language language
+                            (text :t/footer)))))
 
-(defmacro with-language
+(defmacro with-change-language
   "Executes body between calls to `(change-language language)`
    and `(change-language :en)`."
   [language & body]
@@ -2503,7 +2503,7 @@
                           [(:application/id application)
                            (q (:application/external-id application))
                            (q (get-in application [:application/applicant :name]))
-                           (q (text/localize-time (get-in application [:application/first-submitted])))
+                           (q (localize-time (get-in application [:application/first-submitted])))
                            (q "Applied")
                            (q "")
                            (q "Tämä on monimutkainen arvo skandein varusteltuna!")])]
@@ -2930,7 +2930,7 @@
     (login-as "owner")
     (testing "create licenses with different license types"
       (testing "external link"
-        (with-language :en
+        (with-change-language :en
           (go-to-admin "Licenses")
           (is (btu/eventually-visible? {:tag :h1 :fn/has-text "Licenses"}))
           (btu/scroll-and-click :create-license)
@@ -2960,7 +2960,7 @@
                  (slurp-fields :license)))))
       (testing "inline text"
         (go-to-admin "Licenses")
-        (with-language :fi
+        (with-change-language :fi
           (is (btu/eventually-visible? {:tag :h1 :fn/has-text "Lisenssit"}))
           (btu/scroll-and-click :create-license)
           (btu/screenshot "before-filling-inline-text-fi")
@@ -2986,7 +2986,7 @@
                  (slurp-fields :license)))))
       (testing "attachment"
         (go-to-admin "Licenses")
-        (with-language :sv
+        (with-change-language :sv
           (is (btu/eventually-visible? {:tag :h1 :fn/has-text "Licenser"}))
           (btu/scroll-and-click :create-license)
           (btu/screenshot "before-filling-attachments-sv")
diff --git a/test/clj/rems/test_ga4gh.clj b/test/clj/rems/test_ga4gh.clj
index dd72a31c7..2efdc437a 100644
--- a/test/clj/rems/test_ga4gh.clj
+++ b/test/clj/rems/test_ga4gh.clj
@@ -9,24 +9,23 @@
 (deftest test-entitlement->visa-claims
   (with-redefs [env {:public-url "https://rems.example/"}]
     (with-fixed-time (time/date-time 2010 01 01)
-      (fn []
-        (is (= {:iss "https://rems.example/"
-                :sub "user@example.com"
-                :iat (clj-time.coerce/to-epoch "2010")
-                :exp (clj-time.coerce/to-epoch "2011")
-                :ga4gh_visa_v1 {:type "ControlledAccessGrants"
-                                :value "urn:1234"
-                                :source "https://rems.example/"
-                                :by "dac"
-                                :asserted (clj-time.coerce/to-epoch "2009")}}
-               (#'ga4gh/entitlement->visa-claims {:resid "urn:1234" :start (time/date-time 2009) :userid "user@example.com"})))
-        (is (= {:iss "https://rems.example/"
-                :sub "user@example.com"
-                :iat (clj-time.coerce/to-epoch "2010")
-                :exp (clj-time.coerce/to-epoch "2010-06-02")
-                :ga4gh_visa_v1 {:type "ControlledAccessGrants"
-                                :value "urn:1234"
-                                :source "https://rems.example/"
-                                :by "dac"
-                                :asserted (clj-time.coerce/to-epoch "2009")}}
-               (#'ga4gh/entitlement->visa-claims {:resid "urn:1234" :start (time/date-time 2009) :end (time/date-time 2010 6 2) :userid "user@example.com"})))))))
+      (is (= {:iss "https://rems.example/"
+              :sub "user@example.com"
+              :iat (clj-time.coerce/to-epoch "2010")
+              :exp (clj-time.coerce/to-epoch "2011")
+              :ga4gh_visa_v1 {:type "ControlledAccessGrants"
+                              :value "urn:1234"
+                              :source "https://rems.example/"
+                              :by "dac"
+                              :asserted (clj-time.coerce/to-epoch "2009")}}
+             (#'ga4gh/entitlement->visa-claims {:resid "urn:1234" :start (time/date-time 2009) :userid "user@example.com"})))
+      (is (= {:iss "https://rems.example/"
+              :sub "user@example.com"
+              :iat (clj-time.coerce/to-epoch "2010")
+              :exp (clj-time.coerce/to-epoch "2010-06-02")
+              :ga4gh_visa_v1 {:type "ControlledAccessGrants"
+                              :value "urn:1234"
+                              :source "https://rems.example/"
+                              :by "dac"
+                              :asserted (clj-time.coerce/to-epoch "2009")}}
+             (#'ga4gh/entitlement->visa-claims {:resid "urn:1234" :start (time/date-time 2009) :end (time/date-time 2010 6 2) :userid "user@example.com"}))))))
diff --git a/test/clj/rems/test_pdf.clj b/test/clj/rems/test_pdf.clj
index 40ebfc546..f6d938dc4 100644
--- a/test/clj/rems/test_pdf.clj
+++ b/test/clj/rems/test_pdf.clj
@@ -34,11 +34,9 @@
              [[[:paragraph {:spacing-before 8, :style :bold} "Table field"]
                [:paragraph "No rows"]]]]]
            (with-language :en
-             (fn []
-               (with-fixed-time (time/date-time 2010)
-                 (fn []
-                   (#'pdf/render-fields data)))))))
-    (is (some? (with-language :en #(pdf/application-to-pdf-bytes data))))))
+             (with-fixed-time (time/date-time 2010)
+               (#'pdf/render-fields data)))))
+    (is (some? (with-language :en (pdf/application-to-pdf-bytes data))))))
 
 (deftest test-pdf-private-form-fields
   (test-helpers/create-user! {:userid "alice" :name "Alice Applicant" :email "alice@example.com"})
@@ -154,10 +152,8 @@
                  [[:phrase "2000-01-01 00:00" " " "Alice Applicant skapade ansökan 2000/1." nil nil nil]
                   [:phrase "2001-01-01 00:00" " " "Alice Applicant lämnade in ansökan." nil nil nil]]]]]]
              (with-language :sv
-               (fn []
-                 (with-fixed-time (time/date-time 2010)
-                   (fn []
-                     (#'pdf/render-application (applications/get-application-for-user "alice" application-id)))))))))
+               (with-fixed-time (time/date-time 2010)
+                 (#'pdf/render-application (applications/get-application-for-user "alice" application-id)))))))
     (testing "handler should see complete application"
       (is (= [{}
               [[:heading pdf/heading-style "Application 2000/1: "]
@@ -219,10 +215,8 @@
                    "\nComment: I have decided"
                    nil]]]]]]
              (with-language :en
-               (fn []
-                 (with-fixed-time (time/date-time 2010)
-                   (fn []
-                     (#'pdf/render-application (applications/get-application-for-user "developer" application-id)))))))))
+               (with-fixed-time (time/date-time 2010)
+                 (#'pdf/render-application (applications/get-application-for-user "developer" application-id)))))))
     (testing "decider should see complete application"
       (is (= [{}
               [[:heading pdf/heading-style "Hakemus 2000/1: "]
@@ -284,10 +278,8 @@
                    "\nKommentti: I have decided"
                    nil]]]]]]
              (with-language :fi
-               (fn []
-                 (with-fixed-time (time/date-time 2010)
-                   (fn []
-                     (#'pdf/render-application (applications/get-application-for-user "david" application-id)))))))))
+               (with-fixed-time (time/date-time 2010)
+                 (#'pdf/render-application (applications/get-application-for-user "david" application-id)))))))
     (testing "reviewer should not see private fields"
       (is (= [{}
               [[:heading pdf/heading-style "Ansökan 2000/1: "]
@@ -338,10 +330,8 @@
                    "\nKommentar: I have decided"
                    nil]]]]]]
              (with-language :sv
-               (fn []
-                 (with-fixed-time (time/date-time 2010)
-                   (fn []
-                     (#'pdf/render-application (applications/get-application-for-user "carl" application-id)))))))))))
+               (with-fixed-time (time/date-time 2010)
+                 (#'pdf/render-application (applications/get-application-for-user "carl" application-id)))))))))
 
 (deftest test-pdf-gold-standard
   (test-helpers/create-user! {:userid "alice" :name "Alice Applicant" :email "alice@example.com"})
@@ -551,14 +541,11 @@
                   [:phrase "2003-01-01 00:00" " " "David Decider filed a decision for the application." "\nDavid Decider approved the application." "\nComment: I have decided" nil]
                   [:phrase "2003-01-01 00:00" " " "Developer approved the application." nil "\nComment: approved" "\nAttachments: file1.txt, file2.pdf"]]]]]]
              (with-language :en
-               (fn []
-                 (with-fixed-time (time/date-time 2010)
-                   (fn []
-                     (#'pdf/render-application (applications/get-application-for-user handler application-id)))))))))
+               (with-fixed-time (time/date-time 2010)
+                 (#'pdf/render-application (applications/get-application-for-user handler application-id)))))))
     (testing "pdf rendering succeeds"
       (is (some?
            (with-language :en
-             #(do
-                ;; uncomment this to get a pdf file to look at
-                #_(pdf/application-to-pdf (applications/get-application-for-user handler application-id) "/tmp/example-application.pdf")
-                (pdf/application-to-pdf-bytes (applications/get-application-for-user handler application-id)))))))))
+             ;; uncomment this to get a pdf file to look at
+             #_(pdf/application-to-pdf (applications/get-application-for-user handler application-id) "/tmp/example-application.pdf")
+             (pdf/application-to-pdf-bytes (applications/get-application-for-user handler application-id))))))))
diff --git a/test/clj/rems/test_text.clj b/test/clj/rems/test_text.clj
index 7abd02e05..f4100f716 100644
--- a/test/clj/rems/test_text.clj
+++ b/test/clj/rems/test_text.clj
@@ -29,11 +29,10 @@
               (map keyword)
               (sort))))
   (with-language :en
-    (fn []
-      (is (not (valid-localization? (localize-state "foobar"))))
-      (doseq [s application-util/states]
-        (testing s
-          (is (valid-localization? (localize-state s))))))))
+    (is (not (valid-localization? (localize-state "foobar"))))
+    (doseq [s application-util/states]
+      (testing s
+        (is (valid-localization? (localize-state s)))))))
 
 (deftest test-all-event-localizations
   (let [event-types (keys events/event-schemas)]
@@ -46,61 +45,59 @@
                 (map keyword)
                 (sort))))
     (with-language :en
-      (fn []
-        (is (not (valid-localization? (localize-event {:event/type "foobar"}))))
-        (doseq [event-type event-types]
-          (testing event-type
-            (is (valid-localization? (localize-event
-                                      (merge {:event/type event-type}
-                                             (when (= event-type :application.event/decided)
-                                               {:application/decision :approved})
-                                             (when (= event-type :application.event/voted)
-                                               {:vote/value "accept"})))))))))))
+      (is (not (valid-localization? (localize-event {:event/type "foobar"}))))
+      (doseq [event-type event-types]
+        (testing event-type
+          (is (valid-localization? (localize-event
+                                    (merge {:event/type event-type}
+                                           (when (= event-type :application.event/decided)
+                                             {:application/decision :approved})
+                                           (when (= event-type :application.event/voted)
+                                             {:vote/value "accept"}))))))))))
 
 (deftest test-localize-event
   ;; check some event types that have special logic
   (with-language :en
-    (fn []
-      (is (= "Bob Bond added User Urquhart to the application."
-             (localize-event {:event/type :application.event/member-added
-                              :event/actor "bob"
-                              :event/actor-attributes {:userid "bob"
-                                                       :name "Bob Bond"}
-                              :application/member {:userid "User"
-                                                   :email "user@example.com"
-                                                   :name "User Urquhart"}})))
-      (is (= "Bob Bond changed the applicant to User Urquhart."
-             (localize-event {:event/type :application.event/applicant-changed
-                              :event/actor "bob"
-                              :event/actor-attributes {:userid "bob"
-                                                       :name "Bob Bond"}
-                              :application/applicant {:userid "User"
-                                                      :email "user@example.com"
-                                                      :name "User Urquhart"}})))
-      (is (= "Bob Bond invited User Urquhart <user@example.com> to the application."
-             (localize-event {:event/type :application.event/member-invited
-                              :event/actor "bob"
-                              :event/actor-attributes {:userid "bob"
-                                                       :name "Bob Bond"}
-                              :application/member {:email "user@example.com"
-                                                   :name "User Urquhart"}})))
-      (is (= "Bob Bond invited User Urquhart <user@example.com> to review the application."
-             (localize-event {:event/type :application.event/reviewer-invited
-                              :event/actor "bob"
-                              :event/actor-attributes {:userid "bob"
-                                                       :name "Bob Bond"}
-                              :application/reviewer {:email "user@example.com"
-                                                     :name "User Urquhart"}})))
-      (is (= "Bob Bond invited User Urquhart <user@example.com> to decide."
-             (localize-event {:event/type :application.event/decider-invited
-                              :event/actor "bob"
-                              :event/actor-attributes {:userid "bob"
-                                                       :name "Bob Bond"}
-                              :application/decider {:email "user@example.com"
+    (is (= "Bob Bond added User Urquhart to the application."
+           (localize-event {:event/type :application.event/member-added
+                            :event/actor "bob"
+                            :event/actor-attributes {:userid "bob"
+                                                     :name "Bob Bond"}
+                            :application/member {:userid "User"
+                                                 :email "user@example.com"
+                                                 :name "User Urquhart"}})))
+    (is (= "Bob Bond changed the applicant to User Urquhart."
+           (localize-event {:event/type :application.event/applicant-changed
+                            :event/actor "bob"
+                            :event/actor-attributes {:userid "bob"
+                                                     :name "Bob Bond"}
+                            :application/applicant {:userid "User"
+                                                    :email "user@example.com"
                                                     :name "User Urquhart"}})))
-      (is (= "Bob Bond approved the application. Access rights end 2020-01-02."
-             (localize-event {:event/type :application.event/approved
-                              :event/actor "bob"
-                              :event/actor-attributes {:userid "bob"
-                                                       :name "Bob Bond"}
-                              :entitlement/end (time/date-time 2020 1 2)}))))))
+    (is (= "Bob Bond invited User Urquhart <user@example.com> to the application."
+           (localize-event {:event/type :application.event/member-invited
+                            :event/actor "bob"
+                            :event/actor-attributes {:userid "bob"
+                                                     :name "Bob Bond"}
+                            :application/member {:email "user@example.com"
+                                                 :name "User Urquhart"}})))
+    (is (= "Bob Bond invited User Urquhart <user@example.com> to review the application."
+           (localize-event {:event/type :application.event/reviewer-invited
+                            :event/actor "bob"
+                            :event/actor-attributes {:userid "bob"
+                                                     :name "Bob Bond"}
+                            :application/reviewer {:email "user@example.com"
+                                                   :name "User Urquhart"}})))
+    (is (= "Bob Bond invited User Urquhart <user@example.com> to decide."
+           (localize-event {:event/type :application.event/decider-invited
+                            :event/actor "bob"
+                            :event/actor-attributes {:userid "bob"
+                                                     :name "Bob Bond"}
+                            :application/decider {:email "user@example.com"
+                                                  :name "User Urquhart"}})))
+    (is (= "Bob Bond approved the application. Access rights end 2020-01-02."
+           (localize-event {:event/type :application.event/approved
+                            :event/actor "bob"
+                            :event/actor-attributes {:userid "bob"
+                                                     :name "Bob Bond"}
+                            :entitlement/end (time/date-time 2020 1 2)})))))
diff --git a/test/clj/rems/testing_util.clj b/test/clj/rems/testing_util.clj
index d4b403ef4..037866bc3 100644
--- a/test/clj/rems/testing_util.clj
+++ b/test/clj/rems/testing_util.clj
@@ -9,7 +9,7 @@
   (:import [ch.qos.logback.classic Level Logger]
            [java.nio.file Files]
            [java.nio.file.attribute FileAttribute]
-           [org.joda.time DateTimeZone DateTimeUtils]
+           [org.joda.time DateTime DateTimeZone DateTimeUtils]
            [org.slf4j LoggerFactory]))
 
 (defn utc-fixture [f]
@@ -18,18 +18,19 @@
     (f)
     (DateTimeZone/setDefault old)))
 
-(defn with-fixed-time [date f]
-  (DateTimeUtils/setCurrentMillisFixed (.getMillis date))
-  (try
-    (f)
-    (finally
-      (DateTimeUtils/setCurrentMillisSystem))))
+(defmacro with-fixed-time [^DateTime date & body]
+  `(try
+     (DateTimeUtils/setCurrentMillisFixed (.getMillis ~date))
+     ~@body
+     (finally
+       (DateTimeUtils/setCurrentMillisSystem))))
 
 (defn fixed-time-fixture [date]
   (fn [f]
-    (with-fixed-time date f)))
+    (with-fixed-time date
+      (f))))
 
-(defn suppress-logging [^String logger-name]
+(defn suppress-logging-fixture [^String logger-name]
   (fn [f]
     (let [^Logger logger (LoggerFactory/getLogger logger-name)
           original-level (.getLevel logger)]