Merge branch 'master' into fix/malli-swagger-defs

This commit is contained in:
Wes Morgan 2023-04-17 09:44:36 -06:00
commit f237b0942e
No known key found for this signature in database
GPG key ID: 5639E4CBFA17DC84
26 changed files with 318 additions and 61 deletions

View file

@ -18,7 +18,9 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
* Updated dependencies:
```clojure
[metosin/malli "0.10.4"] is available but we use "0.10.1"
[metosin/ring-swagger-ui "4.18.1"] is available but we use "4.15.5"
[metosin/malli "0.11.0"] is available but we use "0.10.1"
[ring/ring-core "1.10.0"] is available but we use "1.9.6"
```
## 0.6.0 (2023-02-21)

View file

@ -2,8 +2,16 @@
Reitit includes two browser history integrations.
Functions follow HTML5 History API: `push-state` to change route, `replace-state`
to change route without leaving previous entry in browser history.
Main functions are `navigate` and `set-query`. Navigate is used to navigate
to named routes, and the options parameter can be used to control all
parameters and if `pushState` or `replaceState` should be used to control
browser history stack. The `set-query` function can be used to change
or modify query parameters for the current route, it takes either map of
new query params or function from old params to the new params.
There are also secondary functions following HTML5 History API:
`push-state` to navigate to new route adding entry to the history and
`replace-state` to change route without leaving previous entry in browser history.
## Fragment router

View file

@ -19,10 +19,17 @@
[:ul
[:li [:a {:href (rfe/href ::item {:id 1})} "Item 1"]]
[:li [:a {:href (rfe/href ::item {:id 2} {:foo "bar"})} "Item 2"]]]
(if id
(when id
[:h2 "Selected item " id])
(if (:foo query)
[:p "Optional foo query param: " (:foo query)])]))
[:p "Query params: " [:pre (pr-str query)]]
[:ul
[:li [:a {:on-click #(rfe/set-query {:a 1})} "set a=1"]]
[:li [:a {:on-click #(rfe/set-query {:a 2} {:replace true})} "set a=2 and replaceState"]]
[:li [:a {:on-click (fn [_] (rfe/set-query #(assoc % :foo "zzz")))} "add foo=zzz"]]]
[:button
{:on-click #(rfe/navigate ::item {:path-params {:id 3}
:query-params {:foo "aaa"}})}
"Navigate example, go to item 3"]]))
(defonce match (r/atom nil))
@ -31,9 +38,8 @@
[:ul
[:li [:a {:href (rfe/href ::frontpage)} "Frontpage"]]
[:li
[:a {:href (rfe/href ::item-list)} "Item list"]
]]
(if @match
[:a {:href (rfe/href ::item-list)} "Item list"]]]
(when @match
(let [view (:view (:data @match))]
[view @match]))
[:pre (with-out-str (fedn/pprint @match))]])
@ -63,7 +69,8 @@
["/:id"
{:name ::item
:parameters {:path {:id s/Int}
:query {(s/optional-key :foo) s/Keyword}}
:query {(s/optional-key :a) s/Int
(s/optional-key :foo) s/Keyword}}
:controllers [{:parameters {:path [:id]}
:start (fn [{:keys [path]}]
(js/console.log "start" "item controller" (:id path)))

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:java-source-paths ["java-src"]

View file

@ -5,7 +5,7 @@
:url "http://www.eclipse.org/legal/epl-v10.html"}
:scm {:name "git"
:url "https://github.com/metosin/reitit"}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]])

View file

@ -1,25 +1,41 @@
(ns reitit.frontend
(:require [clojure.set :as set]
[reitit.coercion :as coercion]
[reitit.core :as r])
(:import goog.Uri
goog.Uri.QueryData))
[reitit.core :as r]
goog.Uri
goog.Uri.QueryData))
(defn- query-param [^QueryData q k]
(defn- query-param [^goog.uri.QueryData q k]
(let [vs (.getValues q k)]
(if (< (alength vs) 2)
(aget vs 0)
(vec vs))))
(defn query-params
"Given goog.Uri, read query parameters into Clojure map."
[^Uri uri]
"Given goog.Uri, read query parameters into a Clojure map."
[^goog.Uri uri]
(let [q (.getQueryData uri)]
(->> q
(.getKeys)
(map (juxt keyword #(query-param q %)))
(into {}))))
(defn set-query-params
"Given Reitit-frontend path, update the query params
with given function and arguments.
Note: coercion is not applied to the query params"
[path new-query-or-update-fn]
(let [^goog.Uri uri (goog.Uri/parse path)
new-query (if (fn? new-query-or-update-fn)
(new-query-or-update-fn (query-params uri))
new-query-or-update-fn)]
;; NOTE: Differences to reitit.impl/query-string?
;; reitit fn adds "=" even if value is empty string
;; reitit encodes " " as "+" while browser and goog.Uri encode as "%20"
(.setQueryData uri (goog.Uri.QueryData/createFromMap (clj->js new-query)))
(.toString uri)))
(defn match-by-path
"Given routing tree and current path, return match with possibly
coerced parameters. Return nil if no match found.
@ -27,7 +43,7 @@
:on-coercion-error - a sideeffecting fn of `match exception -> nil`"
([router path] (match-by-path router path nil))
([router path {:keys [on-coercion-error]}]
(let [uri (.parse Uri path)
(let [uri (.parse goog.Uri path)
coerce! (if on-coercion-error
(fn [match]
(try (coercion/coerce! match)

View file

@ -101,3 +101,44 @@
(rfh/replace-state @history name path-params nil))
([name path-params query-params]
(rfh/replace-state @history name path-params query-params)))
;; This duplicates previous two, but the map parameter will be easier way to
;; extend the functions, e.g. to work with fragment string. Toggling push vs
;; replace can be also simpler with a flag.
;; Navigate and set-query are also similer to react-router API.
(defn
^{:see-also ["reitit.frontend.history/navigate"]}
navigate
"Updates the browser location and either pushes new entry to the history stack
or replaces the latest entry in the the history stack (controlled by
`replace` option) using URL built from a route defined by name given
parameters.
Will also trigger on-navigate callback on Reitit frontend History handler.
Note: currently collections in query-parameters are encoded as field-value
pairs separated by &, i.e. \"?a=1&a=2\", if you want to encode them
differently, convert the collections to strings first.
See also:
https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState"
([name]
(rfh/navigate @history name))
([name {:keys [path-params query-params replace] :as opts}]
(rfh/navigate @history name opts)))
(defn
^{:see-also ["reitit.frontend.history/set-query"]}
set-query
"Update query parameters for the current route.
New query params can be given as a map, or a function taking
the old params and returning the new modified params.
Note: The query parameter values aren't coereced, so the
update fn will see string values for all query params."
([new-query-or-update-fn]
(rfh/set-query @history new-query-or-update-fn))
([new-query-or-update-fn {:keys [replace] :as opts}]
(rfh/set-query @history new-query-or-update-fn opts)))

View file

@ -3,15 +3,15 @@
events."
(:require [goog.events :as gevents]
[reitit.core :as reitit]
[reitit.frontend :as rf])
(:import goog.Uri))
[reitit.frontend :as rf]
goog.Uri))
(defprotocol History
(-init [this] "Create event listeners")
(-stop [this] "Remove event listeners")
(-on-navigate [this path])
(-get-path [this])
(-href [this path]))
(-on-navigate [this path] "Find a match for current routing path and call on-navigate callback")
(-get-path [this] "Get the current routing path")
(-href [this path] "Converts given routing path to browser location"))
;; This version listens for both pop-state and hash-change for
;; compatibility for old browsers not supporting History API.
@ -78,7 +78,7 @@
the page location is updated using History API."
[router e el uri]
(let [current-domain (if (exists? js/location)
(.getDomain (.parse Uri js/location)))]
(.getDomain (.parse goog.Uri js/location)))]
(and (or (and (not (.hasScheme uri)) (not (.hasDomain uri)))
(= current-domain (.getDomain uri)))
(not (.-altKey e))
@ -109,7 +109,7 @@
ignore-anchor-click (fn [e]
;; Returns the next matching ancestor of event target
(when-let [el (closest-by-tag (event-target e) "a")]
(let [uri (.parse Uri (.-href el))]
(let [uri (.parse goog.Uri (.-href el))]
(when (ignore-anchor-click-predicate router e el uri)
(.preventDefault e)
(let [path (str (.getPath uri)
@ -177,7 +177,9 @@
(if history
(-stop history)))
(defn href
(defn
^{:see-also ["reitit.core/match->path"]}
href
"Generate a URL for a route defined by name, with given path-params and query-params.
The URL is formatted using Reitit frontend history handler, so using it with
@ -219,7 +221,9 @@
(.pushState js/window.history nil "" (-href history path))
(-on-navigate history path))))
(defn replace-state
(defn
^{:see-also ["reitit.core/match->path"]}
replace-state
"Updates the browser location and replaces latest entry in the history stack
using URL built from a route defined by name, with given path-params and
query-params.
@ -241,3 +245,50 @@
path (reitit/match->path match query-params)]
(.replaceState js/window.history nil "" (-href history path))
(-on-navigate history path))))
(defn
^{:see-also ["reitit.core/match->path"]}
navigate
"Updates the browser location and either pushes new entry to the history stack
or replaces the latest entry in the the history stack (controlled by
`replace` option) using URL built from a route defined by name given
parameters.
Will also trigger on-navigate callback on Reitit frontend History handler.
Note: currently collections in query-parameters are encoded as field-value
pairs separated by &, i.e. \"?a=1&a=2\", if you want to encode them
differently, convert the collections to strings first.
See also:
https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState"
([history name]
(navigate history name nil))
([history name {:keys [path-params query-params replace] :as opts}]
(let [match (rf/match-by-name! (:router history) name path-params)
path (reitit/match->path match query-params)]
(if replace
(.replaceState js/window.history nil "" (-href history path))
(.pushState js/window.history nil "" (-href history path)))
(-on-navigate history path))))
(defn
^{:see-also ["reitit.frontend/set-query-params"]}
set-query
"Update query parameters for the current route.
New query params can be given as a map, or a function taking
the old params and returning the new modified params.
Note: The query parameter values aren't coereced, so the
update fn will see string values for all query params."
([history new-query-or-update-fn]
(set-query history new-query-or-update-fn nil))
([history new-query-or-update-fn {:keys [replace] :as opts}]
(let [current-path (-get-path history)
new-path (rf/set-query-params current-path new-query-or-update-fn)]
(if replace
(.replaceState js/window.history nil "" (-href history new-path))
(.pushState js/window.history nil "" (-href history new-path)))
(-on-navigate history new-path))))

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-ring]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:scm "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-ring]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.8"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]])

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[io.pedestal/pedestal.service]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-ring]

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]])

View file

@ -6,7 +6,7 @@
:scm {:name "git"
:url "https://github.com/metosin/reitit"
:dir "../.."}
:plugins [[lein-parent "0.3.2"]]
:plugins [[lein-parent "0.3.9"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]

View file

@ -31,13 +31,13 @@
[metosin/reitit-frontend "0.6.0"]
[metosin/reitit-sieppari "0.6.0"]
[metosin/reitit-pedestal "0.6.0"]
[metosin/ring-swagger-ui "4.15.5"]
[metosin/ring-swagger-ui "4.18.1"]
[metosin/spec-tools "0.10.5"]
[metosin/schema-tools "0.13.0"]
[metosin/muuntaja "0.6.8"]
[metosin/jsonista "0.3.7"]
[metosin/sieppari "0.0.0-alpha13"]
[metosin/malli "0.10.4"]
[metosin/malli "0.11.0"]
;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111
[com.fasterxml.jackson.core/jackson-core "2.14.2"]
@ -48,12 +48,13 @@
[expound "0.9.0"]
[lambdaisland/deep-diff "0.0-47"]
[com.bhauman/spell-spec "0.1.2"]
[ring/ring-core "1.9.6"]
[ring/ring-core "1.10.0"]
[io.pedestal/pedestal.service "0.5.10"]]
:plugins [[jonase/eastwood "1.3.0"]
;[lein-virgil "0.1.7"]
[lein-ancient "1.0.0-RC3"]
[lein-doo "0.1.11"]
[lein-cljsbuild "1.1.8"]
[lein-cloverage "1.2.4"]
@ -91,7 +92,7 @@
[metosin/muuntaja "0.6.8"]
[metosin/sieppari "0.0.0-alpha13"]
[metosin/jsonista "0.3.7"]
[metosin/malli "0.10.4"]
[metosin/malli "0.11.0"]
[lambdaisland/deep-diff "0.0-47"]
[meta-merge "1.0.0"]
[com.bhauman/spell-spec "0.1.2"]
@ -100,21 +101,21 @@
[orchestra "2021.01.01-1"]
[ring "1.9.6"]
[ring "1.10.0"]
[ikitommi/immutant-web "3.0.0-alpha1"]
[metosin/ring-http-response "0.9.3"]
[metosin/ring-swagger-ui "4.15.5"]
[metosin/ring-swagger-ui "4.18.1"]
[criterium "0.4.6"]
[org.clojure/test.check "1.1.1"]
[org.clojure/tools.namespace "1.4.4"]
[com.gfredericks/test.chuck "0.2.14"]
[nubank/matcher-combinators "3.8.4"]
[nubank/matcher-combinators "3.8.5"]
[io.pedestal/pedestal.service "0.5.10"]
[org.clojure/core.async "1.6.673"]
[manifold "0.3.0"]
[manifold "0.4.0"]
[funcool/promesa "10.0.594"]
[com.clojure-goes-fast/clj-async-profiler "1.0.3"]
@ -133,7 +134,7 @@
[io.pedestal/pedestal.jetty "0.5.10"]
[calfpath "0.8.1"]
[org.clojure/core.async "1.6.673"]
[manifold "0.3.0"]
[manifold "0.4.0"]
[funcool/promesa "10.0.594"]
[metosin/sieppari]
[yada "1.2.16"]

View file

@ -614,3 +614,59 @@
keys))))
(testing "spec is valid"
(is (nil? (validate spec))))))))))
(deftest recursive-test
;; Recursive schemas only properly supported for malli
;; See https://github.com/metosin/schema-tools/issues/41
(let [app (ring/ring-handler
(ring/router
[["/parameters"
{:post {:description "parameters"
:coercion malli/coercion
:parameters {:request
{:body
[:schema
{:registry {"friend" [:map
[:age int?]
[:pet [:ref "pet"]]]
"pet" [:map
[:name :string]
[:friends [:vector [:ref "friend"]]]]}}
"friend"]}}
:handler (fn [req]
{:status 200
:body (-> req :parameters :request)})}}]
["/openapi.json"
{:get {:handler (openapi/create-openapi-handler)
:openapi {:info {:title "" :version "0.0.1"}}
:no-doc true}}]]
{:validate reitit.ring.spec/validate
:data {:middleware [openapi/openapi-feature
rrc/coerce-request-middleware
rrc/coerce-response-middleware]}}))
spec (-> {:request-method :get
:uri "/openapi.json"}
app
:body)]
(is (= {:info {:title "" :version "0.0.1"}
:openapi "3.1.0"
:x-id #{:reitit.openapi/default}
:paths {"/parameters"
{:post
{:description "parameters"
:requestBody
{:content
{"application/json"
{:schema {:$ref "#/definitions/friend"
:definitions {"friend" {:properties {:age {:type "integer"}
:pet {:$ref "#/definitions/pet"}}
:required [:age :pet]
:type "object"}
"pet" {:properties {:friends {:items {:$ref "#/definitions/friend"}
:type "array"}
:name {:type "string"}}
:required [:name :friends]
:type "object"}}}}}}}}}}
spec))
(testing "spec is valid"
(is (nil? (validate spec))))))

View file

@ -6,7 +6,21 @@
[schema.core :as s]
[reitit.coercion.schema :as rcs]
[reitit.coercion.malli :as rcm]
[reitit.frontend.test-utils :refer [capture-console]]))
[reitit.frontend.test-utils :refer [capture-console]]
[reitit.impl :as impl]))
(deftest query-params-test
(is (= {:foo "1"}
(rf/query-params (.parse goog.Uri "?foo=1"))))
(is (= {:foo "1" :bar "aaa"}
(rf/query-params (.parse goog.Uri "?foo=1&bar=aaa"))))
(is (= {:foo ""}
(rf/query-params (.parse goog.Uri "?foo="))))
(is (= {:foo ""}
(rf/query-params (.parse goog.Uri "?foo")))))
(defn m [x]
(assoc x :data nil :result nil))
@ -227,3 +241,44 @@
:token_type "bearer"
:expires_in 3600}}})
(m (rf/match-by-path router "/5?mode=foo#access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600"))))))))
(deftest set-query-params-test
(is (= "foo?bar=1"
(rf/set-query-params "foo" {:bar 1})
(rf/set-query-params "foo" #(assoc % :bar 1))
;; Also compare to reitit.impl version which is used by match->path (and history fns)
(str "foo?" (impl/query-string {:bar 1}))))
(testing "Encoding"
(is (= "foo?bar=foo%20bar"
(rf/set-query-params "foo" {:bar "foo bar"})
(rf/set-query-params "foo" #(assoc % :bar "foo bar"))
;; FIXME: Reitit.impl encodes space as "+"
; (str "foo?" (impl/query-string {:bar "foo bar"}))
)))
(testing "Keep fragment"
(is (= "foo?bar=1&zzz=2#aaa"
(rf/set-query-params "foo?bar=1#aaa" #(assoc % :zzz 2)))))
(is (= "foo?asd=1&bar=1"
(rf/set-query-params "foo?asd=1" #(assoc % :bar 1))))
(is (= "foo?bar=1"
(rf/set-query-params "foo?asd=1&bar=1" #(dissoc % :asd))))
(is (= "foo?bar"
(rf/set-query-params "foo?asd=1&bar" #(dissoc % :asd))))
(is (= "foo?bar"
(rf/set-query-params "foo" #(assoc % :bar ""))
;; FIXME: Reitit.impl adds "=" for empty string values
; (str "foo?" (impl/query-string {:bar ""}))
))
(is (= "foo"
(rf/set-query-params "foo?asd=1" #(dissoc % :asd))))
(testing "Need to coerce current values manually"
(is (= "foo?foo=2"
(rf/set-query-params "foo?foo=1" (fn [q] (update q :foo #(inc (js/parseInt %)))))))))

View file

@ -30,33 +30,53 @@
(is (= "/" url)
"start at root")
(rfe/push-state ::foo))
;; 0. /
;; 1. /foo
2 (do (is (= "/foo" url)
"push-state")
(.back js/window.history))
;; 0. /
3 (do (is (= "/" url)
"go back")
(rfe/push-state ::bar {:id 1}))
(rfe/navigate ::bar {:path-params {:id 1}}))
;; 0. /
;; 1. /bar/1
4 (do (is (= "/bar/1" url)
"push-state 2")
(rfe/replace-state ::bar {:id 2}))
;; 0. /
;; 1. /bar/2
5 (do (is (= "/bar/2" url)
"replace-state")
(.back js/window.history))
6 (do (is (= "/" url)
"go back after replace state")
(rfe/set-query {:a 1}))
;; 0. /
;; 1. /bar/2
;; 2. /bar/2?a=1
6 (do (is (= "/bar/2?a=1" url)
"update-query with map")
(rfe/set-query #(assoc % :b "foo") {:replace true}))
;; 0. /
;; 1. /bar/2
;; 2. /bar/2?a=1&b=foo
7 (do (is (= "/bar/2?a=1&b=foo" url)
"update-query with fn")
(.go js/window.history -2))
;; 0. /
8 (do (is (= "/" url)
"go back two events")
;; Reset to ensure old event listeners aren't called
(rfe/start! router
(fn on-navigate [match history]
(let [url (rfh/-get-path history)]
(case (swap! n inc)
7 (do (is (= "/" url)
9 (do (is (= "/" url)
"start at root")
(rfe/push-state ::foo))
8 (do (is (= "/foo" url)
"push-state")
(rfh/stop! @rfe/history)
(done))
10 (do (is (= "/foo" url)
"push-state")
(rfh/stop! @rfe/history)
(done))
(do
(is false (str "extra event 2" {:n @n, :url url}))
(done)))))