Skip to content

Commit

Permalink
feat: add devcards and react testing library
Browse files Browse the repository at this point in the history
  • Loading branch information
filipesilva committed Nov 23, 2019
1 parent 015cf3c commit dc74704
Show file tree
Hide file tree
Showing 16 changed files with 179 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
node_modules
dist
out
test*
test*/
.shadow-cljs
.nrepl-port
yarn-error.log
Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@ my-app
| └── favicon.ico
└── src
├── app
| ├── cards
| | ├── devcards_runner.cljs
| | ├── helpers.cljs
| | └── test_runner.cljs
| ├── core.cljs
| └── core_spec.cljs
| ├── hello.cljs
| └── hello_cards.cljs
└── e2e
└── core.cljs
└── core.cljs
```

No configuration or complicated folder structures, just the files you need to build your app.<br>
Once the installation is done, you can open your project folder:

```sh
Expand All @@ -94,6 +98,13 @@ You can use existing npm React components directly via a [interop call](http://r
Builds use [Shadow CLJS](https://github.com/thheller/shadow-cljs) for maximum compatibility with NPM libraries. You'll need a [Java SDK](https://adoptopenjdk.net/) (Version 8+, Hotspot) to use it. <br>
You can [import npm libraries](https://shadow-cljs.github.io/docs/UsersGuide.html#js-deps) using Shadow CLJS. See the [user manual](https://shadow-cljs.github.io/docs/UsersGuide.html) for more information.

### `npm run cards` or `yarn cards`

Runs the interactive live development enviroment.<br>
You can use it to design, test, and think about parts of your app in isolation.

This environment uses [Devcards](https://github.com/bhauman/devcards) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro).

### `npm test` or `yarn test`, and `npm run e2e` or `yarn e2e`

`test` launches the test runner in the interactive watch mode.<br>
Expand Down
5 changes: 3 additions & 2 deletions src/create_cljs_app/template.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ Will likely need to be replaced with a proper templating library."
"public/index.html" [{:from "__NAME__" :to name}]
"src/app/core.cljs" [{:from "__NAME__" :to name}]
"README.md" [{:from "__START__" :to (:start commands)}
{:from "__CARDS__" :to (:cards commands)}
{:from "__SERVER__" :to (:server commands)}
{:from "__TEST__" :to (:test commands)}
{:from "__TEST:ONCE__" :to (:test:once commands)}
{:from "__TEST:WATCH__" :to (:test commands)}
{:from "__TEST__" :to (:test:once commands)}
{:from "__E2E__" :to (:e2e commands)}
{:from "__LINT__" :to (:lint commands)}
{:from "__FORMAT__" :to (:format commands)}
Expand Down
6 changes: 4 additions & 2 deletions src/create_cljs_app/utils.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@
[use-yarn]
(if use-yarn
{:start "yarn start"
:cards "yarn cards"
:server "yarn server"
:build "yarn build"
:test "yarn test"
:test:once "yarn test:once"
:test:watch "yarn test:watch"
:e2e "yarn e2e"
:lint "yarn lint"
:format "yarn format"}
{:start "npm start"
:cards "npm run cards"
:server "npm run server"
:build "npm run build"
:test "npm test"
:test:once "npm run test:once"
:test:watch "npm run test:watch"
:e2e "npm run e2e"
:lint "npm run lint"
:format "npm run format"}))
Expand Down
5 changes: 3 additions & 2 deletions src/e2e/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,17 @@
(is (not (fileIncludes "./public/index.html" "__NAME__")))
(is (not (fileIncludes "./src/app/core.cljs" "__NAME__")))
(is (not (fileIncludes "./README.md" "__START__")))
(is (not (fileIncludes "./README.md" "__CARDS__")))
(is (not (fileIncludes "./README.md" "__SERVER__")))
(is (not (fileIncludes "./README.md" "__TEST__")))
(is (not (fileIncludes "./README.md" "__TEST:ONCE__")))
(is (not (fileIncludes "./README.md" "__TEST:WATCH__")))
(is (not (fileIncludes "./README.md" "__E2E__")))
(is (not (fileIncludes "./README.md" "__BUILD__")))
(is (not (fileIncludes "./README.md" "__LINT__")))
(is (not (fileIncludes "./README.md" "__FORMAT__"))))
(testing "Commands"
(is (= (.-code (silent-exec "yarn sc start")) 0) "Should start background server")
(is (= (.-code (silent-exec "yarn test:once")) 0) "Should test")
(is (= (.-code (silent-exec "yarn test")) 0) "Should test")
(is (= (.-code (silent-exec "yarn build")) 0) "Should build")
(is (existsSync "./public/js/main.js"))
"Should output public/js/main.js")
Expand Down
3 changes: 2 additions & 1 deletion template/.clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{:lint-as {reagent.core/with-let clojure.core/let}}
{:lint-as {devcards.core/defcard cljs.core/def
devcards.core/deftest cljs.core/def}}
13 changes: 10 additions & 3 deletions template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ In the project directory, you can run:

### `__START__`

Runs the app in the development mode.<br>
Runs the app in development mode.<br>
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.

Expand All @@ -16,10 +16,17 @@ You can use existing npm React components directly via a [interop call](http://r
Builds use [Shadow CLJS](https://github.com/thheller/shadow-cljs) for maximum compatibility with NPM libraries. You'll need a [Java SDK](https://adoptopenjdk.net/) (Version 8+, Hotspot) to use it. <br>
You can [import npm libraries](https://shadow-cljs.github.io/docs/UsersGuide.html#js-deps) using Shadow CLJS. See the [user manual](https://shadow-cljs.github.io/docs/UsersGuide.html) for more information.

### `__CARDS__`

Runs the interactive live development enviroment.<br>
You can use it to design, test, and think about parts of your app in isolation.

This environment uses [Devcards](https://github.com/bhauman/devcards) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro).

### `__TEST__` and `__E2E__`

`__TEST__` launches the test runner in the interactive watch mode.<br>
You can use `__TEST:ONCE__` to run the tests a single time, and `__E2E__` to run end-to-end tests.
You can use `__TEST__` to run tests a single time, and `__E2E__` to run the end-to-end test app.
`__TEST:WATCH__` launches tests in interactive watch mode.<br>

See the ClojureScript [testing page](https://clojurescript.org/tools/testing) for more information. E2E tests use [Taiko](https://github.com/getgauge/taiko) to interact with a headless browser.

Expand Down
15 changes: 11 additions & 4 deletions template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@
"sc": "shadow-cljs",
"server": "shadow-cljs stop && shadow-cljs start",
"start": "shadow-cljs watch app",
"cards": "shadow-cljs watch cards",
"build": "yarn clean && shadow-cljs release app",
"test": "shadow-cljs watch test --config-merge \"{:autorun true}\"",
"test:once": "shadow-cljs compile test && node out/test.js",
"test": "shadow-cljs compile test && node out/test.js",
"test:watch": "shadow-cljs watch test --config-merge \"{:autorun true}\"",
"e2e": "shadow-cljs compile e2e && node out/e2e.js",
"lint": "clj-kondo --lint src",
"format": "zprint-clj --hang -i \"./src/**/*.{clj,cljs,cljc,edn}\" -o ./ && zprint-clj -i \"./*.edn\" -o ./",
"clean": "rimraf public/js"
},
"devDependencies": {
"@testing-library/dom": "^6.10.1",
"@testing-library/react": "^9.3.2",
"clj-kondo": "2019.11.23",
"highlight.js": "9.15.10",
"jsdom": "^15.2.1",
"jsdom-global": "^3.0.2",
"marked": "^0.7.0",
"rimraf": "~3.0.0",
"serve-handler": "~6.1.2",
"shadow-cljs": "~2.8.74",
Expand All @@ -25,7 +32,7 @@
},
"dependencies": {
"create-react-class": "~15.6.3",
"react": "~16.12.0",
"react-dom": "~16.12.0"
"react": "~16.8.0",
"react-dom": "~16.8.0"
}
}
16 changes: 11 additions & 5 deletions template/shadow-cljs.edn
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@
:modules {:main {:init-fn app.core/main}}
:output-dir "public/js"
:target :browser}
:cards {:asset-path "/js"
:modules {:main {:init-fn app.cards.devcards-runner/main}}
:compiler-options {:devcards true}
:output-dir "public/js"
:target :browser}
:test {:main app.cards.test-runner/main
:output-to "out/test.js"
:target :node-test}
:e2e {:ns-regexp "e2e.*"
:output-to "out/e2e.js"
:target :node-test}
:test {:ns-regexp "app.*-spec$"
:output-to "out/test.js"
:target :node-test}}
:dependencies [[reagent "0.8.1"]]
:target :node-test}}
:dependencies [[reagent "0.8.1"]
[devcards "0.2.6"]]
:dev-http {3000 "public"}
:nrepl {:port 3333}
:source-paths ["src"]}
18 changes: 18 additions & 0 deletions template/src/app/cards/devcards_runner.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
(ns app.cards.devcards-runner
(:require [cljsjs.react]
[cljsjs.react.dom]
; devcards needs cljsjs.react and cljsjs.react.dom to be imported
; separately for shadow-cljs to add shims.
[devcards.core :refer [start-devcard-ui!]]
; Import all namespaces with cards here to load them.
[app.hello-cards]))

(defn ^:export main
"Start the devcards UI."
[]
; Add a special class to the body to signal we're in devcards mode.
; We want to mostly use the same styles as the app, but might need to make
; some exceptions.
(js/document.body.classList.add "using-devcards")
; Start the devcards UI.
(start-devcard-ui!))
9 changes: 9 additions & 0 deletions template/src/app/cards/helpers.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(ns app.cards.helpers)

(defn testing-container
"The container that should be used to render testing-library react components.
We want to provide our own container so that the rendered devcards aren't used."
[]
(let [app-div (js/document.createElement "div")]
(.setAttribute app-div "id" "testing-lib")
(js/document.body.appendChild app-div)))
26 changes: 26 additions & 0 deletions template/src/app/cards/test_runner.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(ns app.cards.test-runner
{:dev/always true}
(:require [shadow.test.env :as env]
[cljs.test :as ct]
[shadow.test :as st]
["jsdom-global" :as jsdom-global]
; Import the devcards-runner ns to get all the tests imported by it.
[app.cards.devcards-runner]))

(defmethod ct/report [::ct/default :end-run-tests] [m]
(if (ct/successful? m)
(js/process.exit 0)
(js/process.exit 1)))

(defn run-tests []
(-> (env/get-test-data)
(env/reset-test-data!))
(st/run-all-tests))

(defn main
"Run tests in a jsom environment."
[]
; Set jsdom to mock a dom environment.
(jsdom-global)
; Run the tests
(run-tests))
8 changes: 3 additions & 5 deletions template/src/app/core.cljs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
(ns app.core
(:require [reagent.core :as r]))

(defn app []
[:div "__NAME__ is running!"])
(:require [reagent.core :as r]
[app.hello :refer [hello]]))

(defn ^:dev/after-load start []
(r/render [app] (.getElementById js/document "app")))
(r/render [hello] (.getElementById js/document "app")))

(defn ^:export main []
(start))
7 changes: 0 additions & 7 deletions template/src/app/core_spec.cljs

This file was deleted.

17 changes: 17 additions & 0 deletions template/src/app/hello.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(ns app.hello
(:require [reagent.core :as r]))

(defn click-counter [click-count]
[:div
"The atom " [:code "click-count"] " has value: "
@click-count ". "
[:input {:type "button" :value "Click me!"
:on-click #(swap! click-count inc)}]])

(def click-count (r/atom 0))

(defn hello []
[:<>
[:p "Hello, __NAME__ is running!"]
[:p "Here's an example of using a component with state:"]
[click-counter click-count]])
47 changes: 47 additions & 0 deletions template/src/app/hello_cards.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
(ns app.hello-cards
(:require [reagent.core :as r]
[devcards.core :as dc :refer [defcard deftest]]
[cljs.test :include-macros true :refer [is]]
["@testing-library/react" :refer [render cleanup fireEvent]]
[app.hello :refer [click-counter hello]]
[app.cards.helpers :refer [testing-container]]))

(defcard
"This is a live interactive development environment using [Devcards](https://github.com/bhauman/devcards).
You can use it to design, test, and think about parts of your app in isolation.
The two 'cards' below show the two components in this app.")

(defcard hello-card
(dc/reagent hello))

(defcard click-counter-card
(dc/reagent click-counter)
(r/atom 0)
{:inspect-data true
:frame true
:history true})

(defcard
"You can also add tests here and see their results.
Below are some tests using [React Testing Library](https://testing-library.com/docs/react-testing-library/intro).
Tests will be ran outside the browser when you run the test command.")

(deftest hello-tests-card
(let [tr (render (r/as-element [hello]) #js {:container (testing-container)})]
(is (.queryByText tr #"Hello") "Should say 'Hello'")
(cleanup)))

(deftest click-counter-tests-card
(let [atom (r/atom 0)
element (r/as-element [click-counter atom])
tr (render element #js {:container (testing-container)})]
(is (.queryByText tr #"has value: 0") "Should show the initial value as '0'")
(.click fireEvent (.queryByText tr #"(?i)click me"))
(r/flush)
(is (.queryByText tr #"has value: 1") "Should show the value as '1' after click")
(.click fireEvent (.queryByText tr #"(?i)click me"))
(r/flush)
(is (.queryByText tr #"has value: 2") "Should show the value as '2' after two clicks")
(cleanup)))

0 comments on commit dc74704

Please sign in to comment.