From c31f3a0fc388a0baa7c865d78aa3737f21ff8547 Mon Sep 17 00:00:00 2001 From: Nick Van Doorn Date: Fri, 10 Sep 2021 15:13:39 -0700 Subject: ahhhh --- .gitignore | 18 ++++++ .vscode/settings.json | 35 +++++++++++ Capstanfile | 28 +++++++++ Dockerfile | 7 +++ Procfile | 1 + README.md | 21 +++++++ project.clj | 72 +++++++++++++++++++++++ resources/docs/docs.md | 96 +++++++++++++++++++++++++++++++ resources/html/about.html | 4 ++ resources/html/base.html | 58 +++++++++++++++++++ resources/html/error.html | 49 ++++++++++++++++ resources/html/home.html | 6 ++ resources/public/css/screen.css | 35 +++++++++++ resources/public/favicon.ico | Bin 0 -> 1150 bytes resources/public/img/warning_clojure.png | Bin 0 -> 21846 bytes src/clj/nicktodo/config.clj | 13 +++++ src/clj/nicktodo/core.clj | 59 +++++++++++++++++++ src/clj/nicktodo/handler.clj | 35 +++++++++++ src/clj/nicktodo/layout.clj | 39 +++++++++++++ src/clj/nicktodo/middleware.clj | 49 ++++++++++++++++ src/clj/nicktodo/middleware/formats.clj | 14 +++++ src/clj/nicktodo/nrepl.clj | 27 +++++++++ src/clj/nicktodo/routes/home.clj | 21 +++++++ test/clj/nicktodo/handler_test.clj | 27 +++++++++ 24 files changed, 714 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 Capstanfile create mode 100644 Dockerfile create mode 100644 Procfile create mode 100644 README.md create mode 100644 project.clj create mode 100644 resources/docs/docs.md create mode 100644 resources/html/about.html create mode 100644 resources/html/base.html create mode 100644 resources/html/error.html create mode 100644 resources/html/home.html create mode 100644 resources/public/css/screen.css create mode 100644 resources/public/favicon.ico create mode 100644 resources/public/img/warning_clojure.png create mode 100644 src/clj/nicktodo/config.clj create mode 100644 src/clj/nicktodo/core.clj create mode 100644 src/clj/nicktodo/handler.clj create mode 100644 src/clj/nicktodo/layout.clj create mode 100644 src/clj/nicktodo/middleware.clj create mode 100644 src/clj/nicktodo/middleware/formats.clj create mode 100644 src/clj/nicktodo/nrepl.clj create mode 100644 src/clj/nicktodo/routes/home.clj create mode 100644 test/clj/nicktodo/handler_test.clj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7656fce --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +/target +/lib +/classes +/checkouts +pom.xml +dev-config.edn +test-config.edn +*.jar +*.class +/.lein-* +profiles.clj +/.env +.nrepl-port + +/node_modules +/log + + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..23ef5b0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,35 @@ +{ + "calva.customREPLCommandSnippets": [ + { + "name": "Start nicktodo Server", + "ns": "user", + "repl": "clj", + "snippet": "(start)" + }, + { + "name": "Stop nicktodo Server", + "ns": "user", + "repl": "clj", + "snippet": "(stop)" + }, + { + "name": "Restart nicktodo Server", + "ns": "user", + "repl": "clj", + "snippet": "(restart)" + } + ], + "calva.replConnectSequences": [ + { + "name": "nicktodo Server", + "projectType": "Leiningen", + "afterCLJReplJackInCode": "(in-ns 'user) (start) (println \"Access the server at http://localhost:3000\")", + "cljsType": "none", + "menuSelections": { + "leinProfiles": [ + "dev" + ] + } + } + ] +} diff --git a/Capstanfile b/Capstanfile new file mode 100644 index 0000000..e494ed3 --- /dev/null +++ b/Capstanfile @@ -0,0 +1,28 @@ + +# +# Name of the base image. Capstan will download this automatically from +# Cloudius S3 repository. +# +#base: cloudius/osv +base: cloudius/osv-openjdk8 + +# +# The command line passed to OSv to start up the application. +# +cmdline: /java.so -jar /nicktodo/app.jar + +# +# The command to use to build the application. +# You can use any build tool/command (make/rake/lein/boot) - this runs locally on your machine +# +# For Leiningen, you can use: +#build: lein uberjar +# For Boot, you can use: +#build: boot build + +# +# List of files that are included in the generated image. +# +files: + /nicktodo/app.jar: ./target/uberjar/nicktodo.jar + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2b972e2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:8-alpine + +COPY target/uberjar/nicktodo.jar /nicktodo/app.jar + +EXPOSE 3000 + +CMD ["java", "-jar", "/nicktodo/app.jar"] diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..4fa2aa5 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: java -Dclojure.main.report=stderr -cp target/uberjar/nicktodo.jar clojure.main -m nicktodo.core diff --git a/README.md b/README.md new file mode 100644 index 0000000..dc6f7cb --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# nicktodo + +generated using Luminus version "4.19" + +FIXME + +## Prerequisites + +You will need [Leiningen][1] 2.0 or above installed. + +[1]: https://github.com/technomancy/leiningen + +## Running + +To start a web server for the application, run: + + lein run + +## License + +Copyright © 2021 FIXME diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..69cf015 --- /dev/null +++ b/project.clj @@ -0,0 +1,72 @@ +(defproject nicktodo "0.1.0-SNAPSHOT" + + :description "FIXME: write description" + :url "http://example.com/FIXME" + + :dependencies [[ch.qos.logback/logback-classic "1.2.5"] + [clojure.java-time "0.3.3"] + [cprop "0.1.19"] + [expound "0.8.9"] + [funcool/struct "1.4.0"] + [json-html "0.4.7"] + [luminus-transit "0.1.2"] + [luminus-undertow "0.1.11"] + [luminus/ring-ttl-session "0.3.3"] + [markdown-clj "1.10.6"] + [metosin/muuntaja "0.6.8"] + [metosin/reitit "0.5.15"] + [metosin/ring-http-response "0.9.3"] + [mount "0.1.16"] + [nrepl "0.8.3"] + [org.clojure/clojure "1.10.3"] + [org.clojure/tools.cli "1.0.206"] + [org.clojure/tools.logging "1.1.0"] + [org.webjars.npm/bulma "0.9.2"] + [org.webjars.npm/material-icons "1.0.0"] + [org.webjars/webjars-locator "0.41"] + [org.webjars/webjars-locator-jboss-vfs "0.1.0"] + [ring-webjars "0.2.0"] + [ring/ring-core "1.9.4"] + [ring/ring-defaults "0.3.3"] + [selmer "1.12.44"]] + + :min-lein-version "2.0.0" + + :source-paths ["src/clj"] + :test-paths ["test/clj"] + :resource-paths ["resources"] + :target-path "target/%s/" + :main ^:skip-aot nicktodo.core + + :plugins [] + + :profiles + {:uberjar {:omit-source true + :aot :all + :uberjar-name "nicktodo.jar" + :source-paths ["env/prod/clj" ] + :resource-paths ["env/prod/resources"]} + + :dev [:project/dev :profiles/dev] + :test [:project/dev :project/test :profiles/test] + + :project/dev {:jvm-opts ["-Dconf=dev-config.edn" ] + :dependencies [[org.clojure/tools.namespace "1.1.0"] + [pjstadig/humane-test-output "0.11.0"] + [prone "2021-04-23"] + [ring/ring-devel "1.9.4"] + [ring/ring-mock "0.4.0"]] + :plugins [[com.jakemccrary/lein-test-refresh "0.24.1"] + [jonase/eastwood "0.3.5"] + [cider/cider-nrepl "0.26.0"]] + + :source-paths ["env/dev/clj" ] + :resource-paths ["env/dev/resources"] + :repl-options {:init-ns user + :timeout 120000} + :injections [(require 'pjstadig.humane-test-output) + (pjstadig.humane-test-output/activate!)]} + :project/test {:jvm-opts ["-Dconf=test-config.edn" ] + :resource-paths ["env/test/resources"] } + :profiles/dev {} + :profiles/test {}}) diff --git a/resources/docs/docs.md b/resources/docs/docs.md new file mode 100644 index 0000000..53502cf --- /dev/null +++ b/resources/docs/docs.md @@ -0,0 +1,96 @@ +

Congratulations, your Luminus site is ready!

+ +This page will help guide you through the first steps of building your site. + +

Why are you seeing this page?

+ +The `home-routes` handler in the `nicktodo.routes.home` namespace +defines the route that invokes the `home-page` function whenever an HTTP +request is made to the `/` URI using the `GET` method. + +``` +(defn home-routes [] + ["" + {:middleware [middleware/wrap-csrf + middleware/wrap-formats]} + ["/" {:get home-page}] + ["/about" {:get about-page}]]) +``` + +The `home-page` function will in turn call the `nicktodo.layout/render` function +to render the HTML content: + +``` +(defn home-page [request] + (layout/render + request + "home.html" {:docs (-> "docs/docs.md" io/resource slurp)})) +``` + +The `render` function will render the `home.html` template found in the `resources/html` +folder using a parameter map containing the `:docs` key. This key points to the +contents of the `resources/docs/docs.md` file containing these instructions. + +The HTML templates are written using [Selmer](https://github.com/yogthos/Selmer) templating engine. + +``` +
+ {{docs|markdown}} +
+``` + +learn more about HTML templating » + + + +

Organizing the routes

+ +The routes are aggregated and wrapped with middleware in the `nicktodo.handler` namespace: + +``` +(mount/defstate app-routes + :start + (ring/ring-handler + (ring/router + [(home-routes)]) + (ring/routes + (ring/create-resource-handler + {:path "/"}) + (wrap-content-type + (wrap-webjars (constantly nil))) + (ring/create-default-handler + {:not-found + (constantly (error-page {:status 404, :title "404 - Page not found"})) + :method-not-allowed + (constantly (error-page {:status 405, :title "405 - Not allowed"})) + :not-acceptable + (constantly (error-page {:status 406, :title "406 - Not acceptable"}))})))) +``` + +The `app` definition groups all the routes in the application into a single handler. +A default route group is added to handle the `404` case. + +learn more about routing » + +The `home-routes` are wrapped with two middleware functions. The first enables CSRF protection. +The second takes care of serializing and deserializing various encoding formats, such as JSON. + +

Managing your middleware

+ +Request middleware functions are located under the `nicktodo.middleware` namespace. + +This namespace is reserved for any custom middleware for the application. Some default middleware is +already defined here. The middleware is assembled in the `wrap-base` function. + +Middleware used for development is placed in the `nicktodo.dev-middleware` namespace found in +the `env/dev/clj/` source path. + +learn more about middleware » + + + + +

Need some help?

+ +Visit the [official documentation](https://luminusweb.com/docs/guestbook) for examples +on how to accomplish common tasks with Luminus. The `#luminus` channel on the [Clojurians Slack](http://clojurians.net/) and [Google Group](https://groups.google.com/forum/#!forum/luminusweb) are both great places to seek help and discuss projects with other users. diff --git a/resources/html/about.html b/resources/html/about.html new file mode 100644 index 0000000..aff3b2a --- /dev/null +++ b/resources/html/about.html @@ -0,0 +1,4 @@ +{% extends "base.html" %} +{% block content %} + +{% endblock %} diff --git a/resources/html/base.html b/resources/html/base.html new file mode 100644 index 0000000..0b76341 --- /dev/null +++ b/resources/html/base.html @@ -0,0 +1,58 @@ + + + + + + Welcome to nicktodo + + + {% style """/assets/bulma/css/bulma.min.css" %} + {% style """/assets/material-icons/css/material-icons.min.css" %} + + {% style """/css/screen.css" %} + + + + + +
+
+ {% block content %} + {% endblock %} +
+
+ + + + + + {% block page-scripts %} + {% endblock %} + + diff --git a/resources/html/error.html b/resources/html/error.html new file mode 100644 index 0000000..ed0706d --- /dev/null +++ b/resources/html/error.html @@ -0,0 +1,49 @@ + + + + Something Bad Happened + + + {% style """/assets/bulma/css/bulma.min.css" %} + + + +
+
+

Error: {{status}}

+
+ {% if title %} +

{{title}}

+ {% endif %} + {% if message %} +

{{message}}

+ {% endif %} +
+
+ + diff --git a/resources/html/home.html b/resources/html/home.html new file mode 100644 index 0000000..c09946d --- /dev/null +++ b/resources/html/home.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% block content %} +
+ {{docs|markdown}} +
+{% endblock %} diff --git a/resources/public/css/screen.css b/resources/public/css/screen.css new file mode 100644 index 0000000..e90ddb8 --- /dev/null +++ b/resources/public/css/screen.css @@ -0,0 +1,35 @@ +html, +body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url(/assets/material-icons/iconfont/MaterialIcons-Regular.eot); /* For IE6-8 */ + src: local('Material Icons'), + local('MaterialIcons-Regular'), + url(/assets/material-icons/iconfont/MaterialIcons-Regular.woff2) format('woff2'), + url(/assets/material-icons/iconfont/MaterialIcons-Regular.woff) format('woff'), + url(/assets/material-icons/iconfont/MaterialIcons-Regular.ttf) format('truetype'); +} +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; +} + diff --git a/resources/public/favicon.ico b/resources/public/favicon.ico new file mode 100644 index 0000000..0e50cb2 Binary files /dev/null and b/resources/public/favicon.ico differ diff --git a/resources/public/img/warning_clojure.png b/resources/public/img/warning_clojure.png new file mode 100644 index 0000000..78d59e9 Binary files /dev/null and b/resources/public/img/warning_clojure.png differ diff --git a/src/clj/nicktodo/config.clj b/src/clj/nicktodo/config.clj new file mode 100644 index 0000000..a06a39e --- /dev/null +++ b/src/clj/nicktodo/config.clj @@ -0,0 +1,13 @@ +(ns nicktodo.config + (:require + [cprop.core :refer [load-config]] + [cprop.source :as source] + [mount.core :refer [args defstate]])) + +(defstate env + :start + (load-config + :merge + [(args) + (source/from-system-props) + (source/from-env)])) diff --git a/src/clj/nicktodo/core.clj b/src/clj/nicktodo/core.clj new file mode 100644 index 0000000..a6e4b40 --- /dev/null +++ b/src/clj/nicktodo/core.clj @@ -0,0 +1,59 @@ +(ns nicktodo.core + (:require + [nicktodo.handler :as handler] + [nicktodo.nrepl :as nrepl] + [luminus.http-server :as http] + [nicktodo.config :refer [env]] + [clojure.tools.cli :refer [parse-opts]] + [clojure.tools.logging :as log] + [mount.core :as mount]) + (:gen-class)) + +;; log uncaught exceptions in threads +(Thread/setDefaultUncaughtExceptionHandler + (reify Thread$UncaughtExceptionHandler + (uncaughtException [_ thread ex] + (log/error {:what :uncaught-exception + :exception ex + :where (str "Uncaught exception on" (.getName thread))})))) + +(def cli-options + [["-p" "--port PORT" "Port number" + :parse-fn #(Integer/parseInt %)]]) + +(mount/defstate ^{:on-reload :noop} http-server + :start + (http/start + (-> env + (update :io-threads #(or % (* 2 (.availableProcessors (Runtime/getRuntime))))) + (assoc :handler (handler/app)) + (update :port #(or (-> env :options :port) %)) + (select-keys [:handler :host :port]))) + :stop + (http/stop http-server)) + +(mount/defstate ^{:on-reload :noop} repl-server + :start + (when (env :nrepl-port) + (nrepl/start {:bind (env :nrepl-bind) + :port (env :nrepl-port)})) + :stop + (when repl-server + (nrepl/stop repl-server))) + + +(defn stop-app [] + (doseq [component (:stopped (mount/stop))] + (log/info component "stopped")) + (shutdown-agents)) + +(defn start-app [args] + (doseq [component (-> args + (parse-opts cli-options) + mount/start-with-args + :started)] + (log/info component "started")) + (.addShutdownHook (Runtime/getRuntime) (Thread. stop-app))) + +(defn -main [& args] + (start-app args)) diff --git a/src/clj/nicktodo/handler.clj b/src/clj/nicktodo/handler.clj new file mode 100644 index 0000000..e0c9a4c --- /dev/null +++ b/src/clj/nicktodo/handler.clj @@ -0,0 +1,35 @@ +(ns nicktodo.handler + (:require + [nicktodo.middleware :as middleware] + [nicktodo.layout :refer [error-page]] + [nicktodo.routes.home :refer [home-routes]] + [reitit.ring :as ring] + [ring.middleware.content-type :refer [wrap-content-type]] + [ring.middleware.webjars :refer [wrap-webjars]] + [nicktodo.env :refer [defaults]] + [mount.core :as mount])) + +(mount/defstate init-app + :start ((or (:init defaults) (fn []))) + :stop ((or (:stop defaults) (fn [])))) + +(mount/defstate app-routes + :start + (ring/ring-handler + (ring/router + [(home-routes)]) + (ring/routes + (ring/create-resource-handler + {:path "/"}) + (wrap-content-type + (wrap-webjars (constantly nil))) + (ring/create-default-handler + {:not-found + (constantly (error-page {:status 404, :title "404 - Page not found"})) + :method-not-allowed + (constantly (error-page {:status 405, :title "405 - Not allowed"})) + :not-acceptable + (constantly (error-page {:status 406, :title "406 - Not acceptable"}))})))) + +(defn app [] + (middleware/wrap-base #'app-routes)) diff --git a/src/clj/nicktodo/layout.clj b/src/clj/nicktodo/layout.clj new file mode 100644 index 0000000..5a9f097 --- /dev/null +++ b/src/clj/nicktodo/layout.clj @@ -0,0 +1,39 @@ +(ns nicktodo.layout + (:require + [clojure.java.io] + [selmer.parser :as parser] + [selmer.filters :as filters] + [markdown.core :refer [md-to-html-string]] + [ring.util.http-response :refer [content-type ok]] + [ring.util.anti-forgery :refer [anti-forgery-field]] + [ring.middleware.anti-forgery :refer [*anti-forgery-token*]] + [ring.util.response])) + +(parser/set-resource-path! (clojure.java.io/resource "html")) +(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field))) +(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)])) + +(defn render + "renders the HTML template located relative to resources/html" + [request template & [params]] + (content-type + (ok + (parser/render-file + template + (assoc params + :page template + :csrf-token *anti-forgery-token*))) + "text/html; charset=utf-8")) + +(defn error-page + "error-details should be a map containing the following keys: + :status - error status + :title - error title (optional) + :message - detailed error message (optional) + + returns a response map with the error page as the body + and the status specified by the status key" + [error-details] + {:status (:status error-details) + :headers {"Content-Type" "text/html; charset=utf-8"} + :body (parser/render-file "error.html" error-details)}) diff --git a/src/clj/nicktodo/middleware.clj b/src/clj/nicktodo/middleware.clj new file mode 100644 index 0000000..760114b --- /dev/null +++ b/src/clj/nicktodo/middleware.clj @@ -0,0 +1,49 @@ +(ns nicktodo.middleware + (:require + [nicktodo.env :refer [defaults]] + [clojure.tools.logging :as log] + [nicktodo.layout :refer [error-page]] + [ring.middleware.anti-forgery :refer [wrap-anti-forgery]] + [nicktodo.middleware.formats :as formats] + [muuntaja.middleware :refer [wrap-format wrap-params]] + [nicktodo.config :refer [env]] + [ring.middleware.flash :refer [wrap-flash]] + [ring.adapter.undertow.middleware.session :refer [wrap-session]] + [ring.middleware.defaults :refer [site-defaults wrap-defaults]]) + ) + +(defn wrap-internal-error [handler] + (fn [req] + (try + (handler req) + (catch Throwable t + (log/error t (.getMessage t)) + (error-page {:status 500 + :title "Something very bad has happened!" + :message "We've dispatched a team of highly trained gnomes to take care of the problem."}))))) + +(defn wrap-csrf [handler] + (wrap-anti-forgery + handler + {:error-response + (error-page + {:status 403 + :title "Invalid anti-forgery token"})})) + + +(defn wrap-formats [handler] + (let [wrapped (-> handler wrap-params (wrap-format formats/instance))] + (fn [request] + ;; disable wrap-formats for websockets + ;; since they're not compatible with this middleware + ((if (:websocket? request) handler wrapped) request)))) + +(defn wrap-base [handler] + (-> ((:middleware defaults) handler) + wrap-flash + (wrap-session {:cookie-attrs {:http-only true}}) + (wrap-defaults + (-> site-defaults + (assoc-in [:security :anti-forgery] false) + (dissoc :session))) + wrap-internal-error)) diff --git a/src/clj/nicktodo/middleware/formats.clj b/src/clj/nicktodo/middleware/formats.clj new file mode 100644 index 0000000..46cb95b --- /dev/null +++ b/src/clj/nicktodo/middleware/formats.clj @@ -0,0 +1,14 @@ +(ns nicktodo.middleware.formats + (:require + [luminus-transit.time :as time] + [muuntaja.core :as m])) + +(def instance + (m/create + (-> m/default-options + (update-in + [:formats "application/transit+json" :decoder-opts] + (partial merge time/time-deserialization-handlers)) + (update-in + [:formats "application/transit+json" :encoder-opts] + (partial merge time/time-serialization-handlers))))) diff --git a/src/clj/nicktodo/nrepl.clj b/src/clj/nicktodo/nrepl.clj new file mode 100644 index 0000000..d9c3c79 --- /dev/null +++ b/src/clj/nicktodo/nrepl.clj @@ -0,0 +1,27 @@ +(ns nicktodo.nrepl + (:require + [nrepl.server :as nrepl] + [clojure.tools.logging :as log])) + +(defn start + "Start a network repl for debugging on specified port followed by + an optional parameters map. The :bind, :transport-fn, :handler, + :ack-port and :greeting-fn will be forwarded to + clojure.tools.nrepl.server/start-server as they are." + [{:keys [port bind transport-fn handler ack-port greeting-fn]}] + (try + (log/info "starting nREPL server on port" port) + (nrepl/start-server :port port + :bind bind + :transport-fn transport-fn + :handler handler + :ack-port ack-port + :greeting-fn greeting-fn) + + (catch Throwable t + (log/error t "failed to start nREPL") + (throw t)))) + +(defn stop [server] + (nrepl/stop-server server) + (log/info "nREPL server stopped")) diff --git a/src/clj/nicktodo/routes/home.clj b/src/clj/nicktodo/routes/home.clj new file mode 100644 index 0000000..81062db --- /dev/null +++ b/src/clj/nicktodo/routes/home.clj @@ -0,0 +1,21 @@ +(ns nicktodo.routes.home + (:require + [nicktodo.layout :as layout] + [clojure.java.io :as io] + [nicktodo.middleware :as middleware] + [ring.util.response] + [ring.util.http-response :as response])) + +(defn home-page [request] + (layout/render request "home.html" {:docs (-> "docs/docs.md" io/resource slurp)})) + +(defn about-page [request] + (layout/render request "about.html")) + +(defn home-routes [] + [ "" + {:middleware [middleware/wrap-csrf + middleware/wrap-formats]} + ["/" {:get home-page}] + ["/about" {:get about-page}]]) + diff --git a/test/clj/nicktodo/handler_test.clj b/test/clj/nicktodo/handler_test.clj new file mode 100644 index 0000000..72a93d0 --- /dev/null +++ b/test/clj/nicktodo/handler_test.clj @@ -0,0 +1,27 @@ +(ns nicktodo.handler-test + (:require + [clojure.test :refer :all] + [ring.mock.request :refer :all] + [nicktodo.handler :refer :all] + [nicktodo.middleware.formats :as formats] + [muuntaja.core :as m] + [mount.core :as mount])) + +(defn parse-json [body] + (m/decode formats/instance "application/json" body)) + +(use-fixtures + :once + (fn [f] + (mount/start #'nicktodo.config/env + #'nicktodo.handler/app-routes) + (f))) + +(deftest test-app + (testing "main route" + (let [response ((app) (request :get "/"))] + (is (= 200 (:status response))))) + + (testing "not-found route" + (let [response ((app) (request :get "/invalid"))] + (is (= 404 (:status response)))))) -- cgit v1.2.3