clojurescript unit testing recommendations - unit-testing

Trying to setup basic unit testing with clojurescript. Looked at:
https://github.com/clojure/clojurescript/wiki/Testing
In my project.clj file I have:
:cljsbuild {
:builds [{:id "dev"
:source-paths ["src" "test"]
:figwheel { :on-jsload "my-proj.core/on-js-reload" }
:compiler {:main figreag.router
:asset-path "js/compiled/out"
:output-to "resources/public/js/compiled/my_proj.js"
:output-dir "resources/public/js/compiled/out"
:source-map-timestamp true }}
The main point is I add "test" into the :source-paths.
Then in: test/my-proj/tests.cljs I have:
(ns ^:figwheel-always my-proj.tests
(deftest all-tests
(run-tests 'my-proj.core-test)
(run-tests 'my-proj.util-test))
Then in my REPL I do (run-tests). Is this the idiomatic way? I am also using figwheel too, obviously.

Related

lein uberjar - not setting main class properly?

On a fresh lein new re-frame bc +handler app, if I lein uberjar or lein jar it doesnt seem to set the main class correctly. At the end of the compillation it tells me
Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method, or the namespace has not been AOT-compiled.
Here is the server.clj and project.clj that is created using the re-frame +handler template:
server.clj:
(ns bc.server
(:require [bc.handler :refer [handler]]
[config.core :refer [env]]
[ring.adapter.jetty :refer [run-jetty]])
(:gen-class))
(defn -main [& args]
(let [port (Integer/parseInt (or (env :port) "3000"))]
(run-jetty handler {:port port :join? false})))
project.clj:
(defproject bc "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.10.1"]
[org.clojure/clojurescript "1.10.597"
:exclusions [com.google.javascript/closure-compiler-unshaded
org.clojure/google-closure-library
org.clojure/google-closure-library-third-party]]
[thheller/shadow-cljs "2.8.83"]
[reagent "0.8.1"]
[re-frame "0.10.9"]
[compojure "1.6.1"]
[yogthos/config "1.1.7"]
[ring "1.7.1"]]
:plugins [
[lein-shell "0.5.0"]]
:min-lein-version "2.5.3"
:source-paths ["src/clj" "src/cljs"]
:clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
:shell {:commands {"open" {:windows ["cmd" "/c" "start"]
:macosx "open"
:linux "xdg-open"}}}
:aliases {"dev" ["with-profile" "dev" "do"
["clean"]
["run" "-m" "shadow.cljs.devtools.cli" "watch" "app"]]
"prod" ["with-profile" "prod" "do"
["clean"]
["run" "-m" "shadow.cljs.devtools.cli" "release" "app"]]
"build-report" ["with-profile" "prod" "do"
["clean"]
["run" "-m" "shadow.cljs.devtools.cli" "run" "shadow.cljs.build-report" "app" "target/build-report.html"]
["shell" "open" "target/build-report.html"]]
"karma" ["with-profile" "prod" "do"
["clean"]
["run" "-m" "shadow.cljs.devtools.cli" "compile" "karma-test"]
["shell" "karma" "start" "--single-run" "--reporters" "junit,dots"]]}
:profiles
{:dev
{:dependencies [[binaryage/devtools "0.9.11"]]}
:prod { }
:uberjar {:source-paths ["env/prod/clj"]
:omit-source true
:main bc.server
:aot [bc.server]
:uberjar-name "bc.jar"
:prep-tasks ["compile" ["prod"]]}
})
It does generate a jar file when I lein uberjar but when I try to run it it errors out telling me that it does not include a main class.
What am I doing incorrectly?
Your uberjar profile calls ["compile" ["prod"]] in :prep-tasks. Your "prod" alias calls "clean" and "target" is listed in :clean-targets.
In essence, your uberjar deletes your compiled Clojure code.
You need to tell leiningen what namespace has your main function. In project.clj:
:main my.service.runner
from:
https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L222

Auto-refresh/ Auto-reload assets

I'm new to clojure and i'm having a hard time figuring out how to reload/ refresh the browser when changes have been made to either html/ js/ css etc.
this is my current setup project.clj
(defproject app2 "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "http://exampl.com/FIXME"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.89"]
[ring/ring-core "1.5.0"]
[ring/ring-jetty-adapter "1.5.0"]
[enfocus "2.0.0-SNAPSHOT"]]
:plugins [[lein-cljsbuild "1.1.3"]
[lein-ring "0.9.7"]]
:cljsbuild {:builds [{:source-paths ["src/cljs"],
:compiler {
:main "scripts.client"
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js/out"
:asset-path "js/out"
;;:pretty-print true
;;:optimizations :none
}}]}
:main app2.server/app
:ring {:handler app2.server/app :auto-reload? true :auto-refresh? true :reload-paths ["src" "resources"]}
:profiles {
:dev {
:ring {
:nrepl {
:start? true
:port 9000
}
}
}
}
)
This is my server.clj
(ns app2.server
(:use [ring.middleware.resource :only [wrap-resource]]
[ring.middleware.file-info :only [wrap-file-info]]
[ring.middleware.reload :refer [wrap-reload]])
;;(:require app2.repl)
)
(defn handler
[request]
{:status 200}
)
;handling routing "/" -> "/index.html"
(defn wrap-index [handler]
(fn [req]
(println (pr-str req))
(if (= (:uri req) "/")
(handler (assoc req :uri "/index.html"))
(handler req))))
;setting up a simple resource handler for ring
(def app (-> handler
(wrap-resource "public")
(wrap-file-info)
(wrap-index)
(wrap-reload app {:dirs ["src" "resources"]})
))
How can this be accomplished?
I'm used to developing in node and you have tools like browser sync, weinre and supervisor. What are the equivalents in clojure?
I suggest you have a look at figwheel, which lets you do hot reloading of your ClojureScript and CSS in the browser.
There is of course not one good way of setting up your build, but my way to go for languages like SASS etc. is to watch and compile them as a separate process, and have Figwheel watch the generated CSS.
For example, on one of my ClojureScript projects, I had a script file for LESS compilation which used the LESS compiler and the wr utility directly:
#!/usr/bin/env bash
lessc src/styles/main.main.less resources/public/css/main.css --source-map && cp src/styles/*.less resources/public/css
wr "lessc src/styles/main.main.less resources/public/css/main.css --source-map && cp src/styles/*.less resources/public/css" src/**/*.less
Of course you can also use things like Gulp, Webpack - or any tool you're used to.
The alternative is to use Leiningen plugins, see the list here.

Slow loading of cljsbuild in Clojure

I'm new to Clojure and I'm trying to setup a development environment where I can dynamically load my web project files using ring-server and cljsbuild
i have the following snippet in my project file
:ring {
:handler cjohansen-no.web/app
;;:auto-refresh true
;;:auto-reload? true
;;:reload-paths ["resources","src"]
;;:refresh-paths ["resources","src"]
}
:aliases {
"start-server" ["ring" "server-headless"]
"build-site" ["run" "-m" "cjohansen-no.web/export"]
"build-html" ["run" "-m" "cjohansen-no.web/export-pages"]
"build-js" ["cljsbuild" "auto" "dev"]
"build-web" ["do" ["build-site"] ["build-js"]]
"build-dev" ["pdo" ["build-web"] ["start-server"] ["auto" "build-html"]]
}
:source-paths ["src"]
:test-paths ["test/cjohansen_no" "test/cljs" "spec"]
:clean-targets [:target-path "./build/js/out"
:compile-path "classes"
:output-paths "./build/js/output"
"build/js/main.js.map"
]
:main cjohansen-no.web
:clean-non-project-classes true
:figwheel {
;;:server-port 3000
:css-dirs ["resources/public/css"]
:reload-clj-files {:clj true :cljc false}
:ring-handler cjohansen-no.web/app
:repl false
}
:cljsbuild {
:builds [
{
;; :notify-command ["growlnotify" "-m"]
:id "dev"
:source-paths ["src/cljs"]
:figwheel {
:websocket-host :js-client-host
:autoload false
:reload-dependents true
:debug true
}
:compiler {
:main scripts.core
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js/out"
:optimizations :none
:source-map true
:source-map-timestamp true
:recompile-dependents false
:pretty-print true
:asset-path "js/out"
;;:notify-command ["bin/phantomjs" "bin/speclj.js" "resources/public/js/main.js"]
}
},
....
}
:profiles {
:dev {
:dependencies [
;;[figwheel "0.5.4-7"]
]
:plugins [
[lein-pdo "0.1.1"]
[lein-ring "0.9.7"]
[lein-cljsbuild "1.1.3"]
[lein-figwheel "0.5.4-7"]
]
}
I use this snippet to run my server
(def app (->
(stasis/serve-pages get-pages)
(optimus/wrap get-assets optimizations/all serve-live-assets)
;;(wrap-cljsbuild "/js/" cljsbuild)
wrap-content-type
;; wrap-reload
wrap-utf-8))
I'm loading my assets using Optimus
(defn get-assets []
(concat (assets/load-bundle "public" "styles.css" [#"css/.+\.css$"])
(assets/load-assets "public" [#"img/.*" "/questions.json"])
(assets/load-bundle "public" "main.js" [#"js/.+\.js"])
))
when I run lein with-profile dev pdf start-server, cljsbuild auto and bring up my website the js files and its dependants as compiled by the "dev" build takes FOREVER to complete loading. Why is the ring server so slow?
Should I be referencing the build files in this manner? should i bundle it into one file?
The profile used is for development purposes.
That is a pretty complex project.clj file if your just starting up and are new to clojure/clojurescript. It is possible that starting with just the bare lein figwheel template might be a good way to get a basic environment and then just add to it once you know you need additional bits. It could be that simply parsing your project file is slowing things down.
The basic figwheel template will set things up so that it all reloads when necessary - there really isn't much extra you need to worry about.

Automating tasks in Clojure

I have the following in my project.clj
:aliases {
"start-server" ["ring" "server-headless"]
"build-site" ["run" "-m" "cjohansen-no.web/export"]
"build-html" ["run" "-m" "cjohansen-no.web/export-pages"]
"build-prod" ["do" ["build-site"] ["cljsbuild" "once" "prod"]]
"build-js" ["cljsbuild" "auto" "dev"]
"watch-stuff" [ "do" ["start-server"] ["auto" "build-html"]]
"build-dev" ["do" ["build-site"] ["build-js"] ["watch-stuff"]]
}
:clean-targets [:target-path "./build/js/out"
:compile-path "classes"
:output-paths "./build/js/output"
"build/js/main.js.map"
]
:auto {"build-html" {:file-pattern #"\.(clj|hiccup)$" :paths ["src" "resources"]}}
:clean-non-project-classes true
:cljsbuild {
:builds [{
:id "dev"
:source-paths ["src/cljs"]
; :figwheel {
; :http-server-root "build"
; :css-dirs ["resources/public/css"]
; }
:compiler {
:main scripts.core,
:output-to "build/js/main.js",
:output-dir "build/js/out",
:optimizations :none,
:source-map true,
:source-map-timestamp true,
:recompile-dependents false
}
},
{
:id "prod"
:source-paths ["src/cljs"]
:compiler {
:main scripts.core,
:output-to "build/js/main.js",
:output-dir "build/js/output"
:optimizations :simple,
:source-map "build/js/main.js.map",
:asset-path "js/out"
:pretty-print true
}
}
]
}
I'm trying to automate my build by using aliases but don't seem to have it quite together...
running lein build-dev gets everything going except the "watch-stuff" which runs a [lien-auto] plugin and ring server but the it doesn't seem to function.
in the build output the last thing that happens is
Watching for changes before compiling ClojureScript...
Compiling "build/js/main.js" from ["src/cljs"]...
WARNING: test already refers to: cljs.core/test being replaced by: > scripts.core/test at line 5 src/cljs/scripts/core.cljs
Successfully compiled "build/js/main.js" in 4.54 seconds.
is there anything stopping this? how do I automate this in clojure?
Update
I've been moving stuff around and it seems that in some instances the specific task usually enters into its process....not sure if this causes the task executing afterwards to be suspended...does it?
e.g. if "ring" "server-headless" runs before "build-site" build-site does get run...
How do I then pass through the task and go on to the next one?
P.S. Gulp and Grunt was never this hard sigh

reloading from clojure file

I'm new to clojure and I'm trying to wrap my head around live reload in in clojure I want to be able to monitor/ watch all/ any project file and update the browser automatically
So far I have the following
(defproject app2 "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "http://exampl.com/FIXME"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.89"]
[ring "1.5.0"]
[stasis "2.2.0"]
[hiccup "1.0.5"]
[clj-tagsoup "0.3.0"]
[optimus "0.18.5"]
[ring/ring-jetty-adapter "1.5.0"]
[cljs-ajax "0.5.8"]
[enfocus "2.1.1"]]
:plugins [[lein-cljsbuild "1.1.3"]
[lein-ring "0.9.7"]]
:cljsbuild {:builds [
{:id "dev"
:incremental true
:source-paths ["src/cljs"]
:compiler {
:main "scripts.client"
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js/out"
:asset-path "js/out"
}}]}
:aliases {
"start-dev" ["pdo" ["cljsbuild" "auto"] ["ring" "server-headless"]]
}
:source-paths ["src"]
:resource-paths ["resources"]
:main app2.server
:repl-options {
:prompt (fn [ns] (str "your command for <" ns ">, master? " ))
:welcome (println "Welcome to the magical world of the repl!")
:init-ns app2.hawk
:init (app2.hawk/init)
:caught clj-stacktrace.repl/pst+
:skip-default-init false
:host "0.0.0.0"
:port 9000
:timeout 40000
}
:ring {
:init app2.hawk/init
:handler app2.server/app
:auto-reload? true :auto-refresh? true :reload-paths ["resources/public"]
:refresh-paths ["resrouces/public"]
}
:profiles {
:dev {
:repl-options {
:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]
}
:source-paths ["src"]
:ring {
:nrepl {
:start? true
:port 9000
:host "0.0.0.0"
}
}
:dependencies [
[ring-refresh "0.1.1"]
[http-kit "2.0.0"]
[org.clojure/tools.nrepl "0.2.11"]
[com.cemerick/piggieback "0.2.1"]
[hawk "0.2.10"]
]
:plugins [
[lein-pdo "0.1.1"]
]
}
}
)
for my handler I have
(ns app2.server
(:use [ring.middleware.resource :only [wrap-resource]]
[ring.middleware.file-info :only [wrap-file-info]]
[ring.middleware.file :only [wrap-file]]
[ring.middleware.reload :refer [wrap-reload]]
[ring.middleware.content-type :refer [wrap-content-type]]
[ring.middleware.refresh :refer [wrap-refresh]]
[ring.util.response :refer [file-response]]
)
(defn wrap-utf-8
"This function works around the fact that Ring simply chooses the default JVM
encoding for the response encoding. This is not desirable, we always want to
send UTF-8."
[handler]
(fn [request]
(when-let [response (handler request)]
(if (.contains (get-in response [:headers "Content-Type"]) ";")
response
(if (string? (:body response))
(update-in response [:headers "Content-Type"] #(str % "; charset=utf-8"))
response)))))
(defn handler [request]
(file-response (:uri request) {:root "resources/public"}))
(def app (-> handler
wrap-content-type
wrap-reload
wrap-refresh []
wrap-utf-8))
And then I am running hawk from repl
(ns app2.hawk
(:require [hawk.core :as hawk])
(:require [app2.server :refer [export-pages]]))
(defn init
[]
(export-pages)
(hawk/watch! [{:paths ["src/app2/templates" "resources/templates"]
:filter hawk/modified?
:handler (fn [ctx e]
(export-pages) ;; i'm compiling html pages dynamically to the server root but how do I then notify browser than html has changed? can i force server to reload from here?
ctx)}]))
If you don't mind using Boot instead of Leiningen, the system project will give you all the reload goodness you can expect from a Lisp, with plenty of examples.
Be sure to check the Holy Grail demo, which leverages system, to get started with minimal fuss.
It sounds like you have put together a great setup so far.
and for managing this workflow Figwheel is the logical next step. If you are doing any Clojurescript + clojure-web stuff you almost certainly should start with figwheel, you will have a much more pleasant experience.