Merge pull request #717 from metosin/shadow-cljs

Update CI tests and add shadow-cljs to run cljs tests
This commit is contained in:
Juho Teperi 2025-01-22 14:05:10 +02:00 committed by GitHub
commit a19b6034dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 2030 additions and 2704 deletions

View file

@ -16,25 +16,32 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Cache dependencies - name: Cache dependencies
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: ~/.m2/repository path: ~/.m2/repository
key: ${{ runner.os }}-clj-${{ hashFiles('**/project.clj') }} key: ${{ runner.os }}-clj-${{ hashFiles('**/project.clj') }}
restore-keys: | restore-keys: |
${{ runner.os }}-clj- ${{ runner.os }}-clj-
- name: Setup Java ${{ matrix.jdk }} - name: Setup Java ${{ matrix.jdk }}
uses: actions/setup-java@v1.4.3 uses: actions/setup-java@v4
with: with:
distribution: temurin
java-version: ${{ matrix.jdk }} java-version: ${{ matrix.jdk }}
- name: Setup Clojure - name: Setup Clojure
uses: DeLaGuardo/setup-clojure@3.1 uses: DeLaGuardo/setup-clojure@13.1
with: with:
lein: 2.9.5 lein: 2.9.5
# Install openapi-schema-validator for openapi-tests
# Uses node version from the ubuntu-latest
- name: Install dependencies - name: Install dependencies
run: | run: npm ci
npm ci
- name: Run tests - name: Run tests
run: ./scripts/test.sh clj run: ./scripts/test.sh clj
@ -42,33 +49,37 @@ jobs:
name: ClojureScript name: ClojureScript
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Cache dependencies - name: Cache dependencies
uses: actions/cache@v2 uses: actions/cache@v2
with: with:
path: | path: |
~/.m2/repository ~/.m2/repository
**/node_modules key: ${{ runner.os }}-cljs-${{ hashFiles('**/project.clj') }}
key: ${{ runner.os }}-cljs-${{ hashFiles('**/project.clj', '**/package-lock.json') }}
restore-keys: | restore-keys: |
${{ runner.os }}-cljs- ${{ runner.os }}-cljs-
- name: Setup Java 11
uses: actions/setup-java@v1.4.3 - name: Setup Java
uses: actions/setup-java@v4
with: with:
java-version: 11 distribution: temurin
java-version: 21
- name: Setup Clojure - name: Setup Clojure
uses: DeLaGuardo/setup-clojure@3.1 uses: DeLaGuardo/setup-clojure@13.1
with: with:
lein: 2.9.5 lein: 2.9.5
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v2.1.2 uses: actions/setup-node@v4
with: with:
node-version: 18 node-version: 22
cache: npm
- name: Install dependencies - name: Install dependencies
run: | run: npm ci
npm ci
- name: Install modules
run: ./scripts/lein-modules install
- name: Run tests - name: Run tests
run: ./scripts/test.sh cljs run: ./scripts/test.sh cljs
@ -76,7 +87,8 @@ jobs:
name: Lint cljdoc.edn name: Lint cljdoc.edn
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Verify cljdoc.edn - name: Verify cljdoc.edn
run: curl -fsSL https://raw.githubusercontent.com/cljdoc/cljdoc/master/script/verify-cljdoc-edn | bash -s doc/cljdoc.edn run: curl -fsSL https://raw.githubusercontent.com/cljdoc/cljdoc/master/script/verify-cljdoc-edn | bash -s doc/cljdoc.edn
@ -84,13 +96,16 @@ jobs:
name: Check cljdoc analysis name: Check cljdoc analysis
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v4
- name: Setup Clojure - name: Setup Clojure
uses: DeLaGuardo/setup-clojure@11.0 uses: DeLaGuardo/setup-clojure@13.1
with: with:
lein: 2.9.5 lein: 2.9.5
cli: 1.11.0.1100 cli: 1.11.0.1100
- name: Install cljdoc analyzer - name: Install cljdoc analyzer
run: clojure -Ttools install io.github.cljdoc/cljdoc-analyzer '{:git/tag "RELEASE"}' :as cljdoc-analyzer run: clojure -Ttools install io.github.cljdoc/cljdoc-analyzer '{:git/tag "RELEASE"}' :as cljdoc-analyzer
- name: CljDoc Check - name: CljDoc Check
run: ./scripts/cljdoc-check.sh run: ./scripts/cljdoc-check.sh

1
.gitignore vendored
View file

@ -14,3 +14,4 @@ pom.xml.asc
figwheel_server.log figwheel_server.log
/.idea /.idea
.clj-kondo .clj-kondo
.shadow-cljs

View file

@ -1,10 +0,0 @@
help:
@just --list
# Initializes lint
init-lint:
clj-kondo --lint $(lein classpath)
# Lints the project
lint:
./lint.sh

26
bb.edn Normal file
View file

@ -0,0 +1,26 @@
{:tasks
{init-lint {:task (shell "sh -c" "clj-kondo --copy-configs --lint $(lein classpath)")}
lint {:doc "Run clj-kondo"
:task (shell "./lint.sh")}
watch-node-test {:doc "Watch files for changes and run Cljs tests on Node.js"
:task (shell "npx shadow-cljs watch node-test")}
node-test {:doc "Compile and run Cljs tests"
:task (shell "npx shadow-cljs compile node-test")}
watch-browser-test-local {:doc "Start watching Cljs tests for changes and start HTTP server for running tests in a local browser"
:task (shell "npx shadow-cljs watch browser-test")}
;; Karma watch needs to file to exist before start
-karma-placeholder (shell "sh -c" "mkdir -p target/karma && touch target/karma/ci.js")
-watch-karma-cljs {:depends [-karma-placeholder]
:task (shell "npx shadow-cljs watch karma")}
-watch-karma-test (shell "npx karma start")
-watch-karma {:depends [-watch-karma-cljs -watch-karma-test]}
watch-karma {:doc "Watch Cljs tests for changes, compile for Karma and run Karma tests on changes"
:task (run '-watch-karma {:parallel true})}
test-karma {:doc "Compile Cljs tests and run using Karma once"
:task (do
(shell "npx shadow-cljs compile karma")
(shell "npx karma start --single-run"))}}}

18
karma.conf.js Normal file
View file

@ -0,0 +1,18 @@
module.exports = function (config) {
config.set({
browsers: ['ChromeHeadless'],
// The directory where the output file lives
basePath: 'target/karma',
// The file itself
files: ['ci.js'],
frameworks: ['cljs-test'],
reporters: ['progress'],
plugins: ['karma-cljs-test', 'karma-chrome-launcher'],
colors: true,
logLevel: config.LOG_INFO,
client: {
args: ["shadow.test.karma.init"],
singleRun: true
},
})
};

View file

@ -15,7 +15,7 @@
(defn query-params (defn query-params
"Given goog.Uri, read query parameters into a Clojure map." "Given goog.Uri, read query parameters into a Clojure map."
[^goog.Uri uri] [^goog.Uri uri]
(let [q (.getQueryData uri)] (let [^goog.Uri.QueryData q (.getQueryData uri)]
(->> q (->> q
(.getKeys) (.getKeys)
(map (juxt keyword #(query-param q %))) (map (juxt keyword #(query-param q %)))
@ -58,7 +58,7 @@
:on-coercion-error - a sideeffecting fn of `match exception -> nil`" :on-coercion-error - a sideeffecting fn of `match exception -> nil`"
([router path] (match-by-path router path nil)) ([router path] (match-by-path router path nil))
([router path {:keys [on-coercion-error]}] ([router path {:keys [on-coercion-error]}]
(let [uri (.parse goog.Uri path) (let [^goog.Uri uri (.parse goog.Uri path)
coerce! (if on-coercion-error coerce! (if on-coercion-error
(fn [match] (fn [match]
(try (coercion/coerce! match) (try (coercion/coerce! match)

View file

@ -65,7 +65,7 @@
(defn- event-target (defn- event-target
"Read event's target from composed path to get shadow dom working, "Read event's target from composed path to get shadow dom working,
fallback to target property if not available" fallback to target property if not available"
[event] [^goog.events.BrowserEvent event]
(let [original-event (.getBrowserEvent event)] (let [original-event (.getBrowserEvent event)]
(if (exists? (.-composedPath original-event)) (if (exists? (.-composedPath original-event))
(aget (.composedPath original-event) 0) (aget (.composedPath original-event) 0)
@ -76,9 +76,9 @@
should be ignored. This logic will ignore the event should be ignored. This logic will ignore the event
if anchor href matches the route tree, and in this case if anchor href matches the route tree, and in this case
the page location is updated using History API." the page location is updated using History API."
[router e el uri] [router e el ^goog.Uri uri]
(let [current-domain (if (exists? js/location) (let [current-domain (if (exists? js/location)
(.getDomain (.parse goog.Uri js/location)))] (.getDomain ^goog.Uri (.parse goog.Uri js/location)))]
(and (or (and (not (.hasScheme uri)) (not (.hasDomain uri))) (and (or (and (not (.hasScheme uri)) (not (.hasDomain uri)))
(= current-domain (.getDomain uri))) (= current-domain (.getDomain uri)))
(not (.-altKey e)) (not (.-altKey e))
@ -110,7 +110,7 @@
ignore-anchor-click (fn [e] ignore-anchor-click (fn [e]
;; Returns the next matching ancestor of event target ;; Returns the next matching ancestor of event target
(when-let [el (closest-by-tag (event-target e) "a")] (when-let [el (closest-by-tag (event-target e) "a")]
(let [uri (.parse goog.Uri (.-href el))] (let [^goog.Uri uri (.parse goog.Uri (.-href el))]
(when (ignore-anchor-click-predicate router e el uri) (when (ignore-anchor-click-predicate router e el uri)
(.preventDefault e) (.preventDefault e)
(let [path (str (.getPath uri) (let [path (str (.getPath uri)

4532
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,11 +2,13 @@
"name": "reitit", "name": "reitit",
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"@seriousme/openapi-schema-validator": "^2.2.1", "@seriousme/openapi-schema-validator": "^2.3.1",
"karma": "^4.1.0", "karma": "^6.4.4",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^3.2.0",
"karma-cli": "^2.0.0", "karma-cli": "^2.0.0",
"karma-cljs-test": "^0.1.0", "karma-cljs-test": "^0.1.0"
"karma-junit-reporter": "^1.2.0" },
"dependencies": {
"shadow-cljs": "^2.28.20"
} }
} }

View file

@ -89,6 +89,7 @@
:java-source-paths ["modules/reitit-core/java-src"] :java-source-paths ["modules/reitit-core/java-src"]
:dependencies [[org.clojure/clojure "1.11.4"] :dependencies [[org.clojure/clojure "1.11.4"]
[thheller/shadow-cljs "2.28.20"]
[org.clojure/clojurescript "1.11.132"] [org.clojure/clojurescript "1.11.132"]
;; modules dependencies ;; modules dependencies
@ -128,6 +129,7 @@
[ring-cors "0.1.13"] [ring-cors "0.1.13"]
[com.bhauman/rebel-readline "0.1.4"]]} [com.bhauman/rebel-readline "0.1.4"]]}
:shadow {:test-paths ["test/cljs"]}
:perf {:jvm-opts ^:replace ["-server" :perf {:jvm-opts ^:replace ["-server"
"-Xmx4096m" "-Xmx4096m"
"-Dclojure.compiler.direct-linking=true"] "-Dclojure.compiler.direct-linking=true"]
@ -156,6 +158,8 @@
:aliases {"all" ["with-profile" "dev,default"] :aliases {"all" ["with-profile" "dev,default"]
"perf" ["with-profile" "default,dev,perf"] "perf" ["with-profile" "default,dev,perf"]
"test-clj" ["all" "do" ["bat-test"] ["check"]] "test-clj" ["all" "do" ["bat-test"] ["check"]]
;; NOTE: These are deprecated, kept around for ensuring shadow-cljs works
;; the same way.
"test-browser" ["doo" "chrome-headless" "test"] "test-browser" ["doo" "chrome-headless" "test"]
"test-advanced" ["doo" "chrome-headless" "advanced-test"] "test-advanced" ["doo" "chrome-headless" "advanced-test"]
"test-node" ["doo" "node" "node-test"]} "test-node" ["doo" "node" "node-test"]}
@ -165,9 +169,7 @@
:output-to "target/results/reitit/junit.xml"}]} :output-to "target/results/reitit/junit.xml"}]}
:doo {:paths {:karma "./node_modules/.bin/karma"} :doo {:paths {:karma "./node_modules/.bin/karma"}
:karma {:config {"plugins" ["karma-junit-reporter"] :karma {:config {"reporters" ["progress"]}}}
"reporters" ["progress", "junit"]
"junitReporter" {"outputDir" "target/results/cljs"}}}}
:cljsbuild {:builds [{:id "test" :cljsbuild {:builds [{:id "test"
:source-paths ["src" "test/cljc" "test/cljs"] :source-paths ["src" "test/cljc" "test/cljs"]

View file

@ -2,7 +2,16 @@
set -e set -e
case $1 in case $1 in
cljs) cljs)
lein "do" test-browser once, test-node once, test-advanced once npx shadow-cljs compile node-test
node target/shadow-node-test/node-tests.js
rm -rf target/karma
npx shadow-cljs compile karma
npx karma start --single-run
rm -rf target/karma
npx shadow-cljs release karma
npx karma start --single-run
;; ;;
clj) clj)
lein test-clj lein test-clj

26
shadow-cljs.edn Normal file
View file

@ -0,0 +1,26 @@
{:lein {:profile "+shadow"}
:dev-http {8021 "target/shadow-browser-test"}
:builds
{:node-test
{:target :node-test
:output-to "target/shadow-node-test/node-tests.js"
:ns-regexp "-test"
;; Watch will also run the tests
:autorun true
:compiler-options {:warnings {:redef-in-file false
:fn-deprecated false}}}
;; For local dev - http://localhost:8021
:browser-test
{:target :browser-test
:test-dir "target/shadow-browser-test"
:compiler-options {:warnings {:redef-in-file false
:fn-deprecated false}}}
:karma
{:target :karma
:output-to "target/karma/ci.js"
:ns-regexp "-test$"
:compiler-options {:warnings {:redef-in-file false
:fn-deprecated false}}}}}

View file

@ -147,6 +147,7 @@
(let [{:keys [status]} (app invalid-request2)] (let [{:keys [status]} (app invalid-request2)]
(is (= 500 status)))))))) (is (= 500 status))))))))
#?(:clj
(deftest schema-coercion-test (deftest schema-coercion-test
(let [create (fn [middleware] (let [create (fn [middleware]
(ring/ring-handler (ring/ring-handler
@ -211,7 +212,7 @@
(testing "invalid response" (testing "invalid response"
(let [{:keys [status]} (app invalid-request2)] (let [{:keys [status]} (app invalid-request2)]
(is (= 500 status)))))))) (is (= 500 status)))))))))
(defn- custom-meta-merge-checking-schema (defn- custom-meta-merge-checking-schema
([] {}) ([] {})
@ -582,6 +583,7 @@
(is (= {:status 200, :body {:total "FOO: this, BAR: that"}} (call m/schema custom-meta-merge-checking-schema))) (is (= {:status 200, :body {:total "FOO: this, BAR: that"}} (call m/schema custom-meta-merge-checking-schema)))
(is (= {:status 200, :body {:total "FOO: this, BAR: that"}} (call identity custom-meta-merge-checking-parameters))))))) (is (= {:status 200, :body {:total "FOO: this, BAR: that"}} (call identity custom-meta-merge-checking-parameters)))))))
#?(:clj
(deftest per-content-type-test (deftest per-content-type-test
(doseq [[coercion json-request edn-request default-request json-response edn-response default-response] (doseq [[coercion json-request edn-request default-request json-response edn-response default-response]
[[malli/coercion [[malli/coercion
@ -675,7 +677,7 @@
(is (= {:type :reitit.coercion/response-coercion :in [:response :body]} (is (= {:type :reitit.coercion/response-coercion :in [:response :body]}
(call (request "application/json" "application/edn" {:request :json :response :json})))) (call (request "application/json" "application/edn" {:request :json :response :json}))))
(is (= {:type :reitit.coercion/response-coercion :in [:response :body]} (is (= {:type :reitit.coercion/response-coercion :in [:response :body]}
(call (request "application/json" "application/transit" {:request :json :response :json}))))))))))) (call (request "application/json" "application/transit" {:request :json :response :json}))))))))))))
#?(:clj #?(:clj

View file

@ -49,22 +49,23 @@
(fn [match history] (fn [match history]
(let [url (rfh/-get-path history)] (let [url (rfh/-get-path history)]
(case (swap! n inc) (case (swap! n inc)
1 (do (is (= "/" url) 1 (rfh/push-state history ::frontpage)
2 (do (is (= "/" url)
"start at root") "start at root")
(rfh/push-state history ::foo)) (rfh/push-state history ::foo))
2 (do (is (= "/foo" url) 3 (do (is (= "/foo" url)
"push-state") "push-state")
(.back js/window.history)) (.back js/window.history))
3 (do (is (= "/" url) 4 (do (is (= "/" url)
"go back") "go back")
(rfh/push-state history ::bar {:id 1})) (rfh/push-state history ::bar {:id 1}))
4 (do (is (= "/bar/1" url) 5 (do (is (= "/bar/1" url)
"push-state 2") "push-state 2")
(rfh/replace-state history ::bar {:id 2})) (rfh/replace-state history ::bar {:id 2}))
5 (do (is (= "/bar/2" url) 6 (do (is (= "/bar/2" url)
"replace-state") "replace-state")
(.back js/window.history)) (.back js/window.history))
6 (do (is (= "/" url) 7 (do (is (= "/" url)
"go back after replace state") "go back after replace state")
(rfh/stop! history) (rfh/stop! history)
(done)) (done))