diff --git a/deps/publish/deps.edn b/deps/publish/deps.edn index a16b052345..39dd76a6eb 100644 --- a/deps/publish/deps.edn +++ b/deps/publish/deps.edn @@ -1,4 +1,4 @@ -{:paths ["src" "../../resources"] +{:paths ["src" "test" "../../resources"] :deps {org.clojure/clojure {:mvn/version "1.12.4"} rum/rum {:git/url "https://github.com/logseq/rum" ;; fork diff --git a/deps/publish/shadow-cljs.edn b/deps/publish/shadow-cljs.edn index 396ea96b6e..c418f99d60 100644 --- a/deps/publish/shadow-cljs.edn +++ b/deps/publish/shadow-cljs.edn @@ -9,4 +9,9 @@ PublishMetaDO logseq.publish.worker/PublishMetaDO}}} :js-options {:js-provider :import} :closure-defines {shadow.cljs.devtools.client.env/enabled false} - :devtools {:enabled false}}}} + :devtools {:enabled false}} + :publish-test {:target :node-test + :output-to "worker/dist/worker-test.js" + :devtools {:enabled false} + :compiler-options {:static-fns false} + :main logseq.publish.test-runner/main}}} diff --git a/deps/publish/src/logseq/publish/routes.cljs b/deps/publish/src/logseq/publish/routes.cljs index 5a38ed3598..b24d09e01d 100644 --- a/deps/publish/src/logseq/publish/routes.cljs +++ b/deps/publish/src/logseq/publish/routes.cljs @@ -606,6 +606,13 @@ (publish-render/render-page-html transit page-uuid refs-json tagged-nodes) #js {:headers headers})))))))))))))) +(defn- rewrite-request-path + [request new-path] + (let [request-url (js/URL. (.-url request)) + new-url (js/URL. (str (.-origin request-url) new-path))] + (set! (.-search new-url) (.-search request-url)) + (js/Request. (str new-url) request))) + (defn ^:large-vars/cleanup-todo handle-fetch [request env] (let [url (js/URL. (.-url request)) path (.-pathname url) @@ -709,7 +716,9 @@ (js/Response. (.-body object) #js {:headers headers})))))))) - (and (string/starts-with? path "/p/") (= method "GET")) + (and (or (string/starts-with? path "/p/") + (string/starts-with? path "/s/")) + (= method "GET")) (let [parts (string/split path #"/") short-id (nth parts 2 nil)] (if (string/blank? short-id) @@ -727,11 +736,9 @@ (publish-common/not-found) (let [graph-uuid (aget row "graph_uuid") page-uuid (aget row "page_uuid") - location (str "/page/" graph-uuid "/" page-uuid)] - (js/Response. nil #js {:status 302 - :headers (publish-common/merge-headers - #js {"location" location} - (publish-common/cors-headers))}))))))))) + page-path (str "/page/" graph-uuid "/" page-uuid) + page-request (rewrite-request-path request page-path)] + (handle-page-html page-request env))))))))) (and (string/starts-with? path "/u/") (= method "GET")) (let [parts (string/split path #"/") diff --git a/deps/publish/test/logseq/publish/routes_test.cljs b/deps/publish/test/logseq/publish/routes_test.cljs new file mode 100644 index 0000000000..0de872c449 --- /dev/null +++ b/deps/publish/test/logseq/publish/routes_test.cljs @@ -0,0 +1,91 @@ +(ns logseq.publish.routes-test + (:require [cljs.test :refer [async deftest is testing]] + [logseq.publish.routes :as routes] + [promesa.core :as p])) + +(defn- json-response + [data] + (js/Response. + (js/JSON.stringify data) + #js {:status 200 + :headers #js {"content-type" "application/json"}})) + +(defn- short-url-env + [] + (let [do-stub #js {:fetch (fn [url _opts] + (cond + (= "https://publish/short/abc123" url) + (js/Promise.resolve + (json-response + #js {:page #js {"graph_uuid" "graph-1" + "page_uuid" "page-1"}})) + + (re-matches #"https://publish/pages/[^/]+/[^/]+/password" url) + (js/Promise.resolve (json-response #js {})) + + (re-matches #"https://publish/pages/[^/]+/[^/]+" url) + (js/Promise.resolve + (json-response + #js {"content_hash" "etag-1" + "r2_key" "publish/graph-1/page-1.transit"})) + + :else + (js/Promise.resolve + (js/Response. "not found" #js {:status 404}))))} + do-ns #js {:idFromName (fn [_name] "index") + :get (fn [_id] do-stub)} + r2 #js {:get (fn [_key] + (js/Promise.resolve + #js {:arrayBuffer (fn [] + (let [payload (.encode (js/TextEncoder.) "{}")] + (js/Promise.resolve (.-buffer payload))))}))}] + #js {"PUBLISH_META_DO" do-ns + "PUBLISH_R2" r2})) + +(deftest short-url-does-not-redirect-to-uuid-url + (testing "short URL should not redirect to /page/:graph/:page" + (async done + (let [request (js/Request. "https://publish.example/p/abc123?password=s3cr3t") + env (short-url-env)] + (-> (p/let [response (routes/handle-fetch request env) + body (.text response)] + (is (= 200 (.-status response))) + (is (nil? (.get (.-headers response) "location"))) + (is (re-find #"" body)) + (is (not (re-find #"Page not found" body))) + (done)) + (p/catch (fn [error] + (is nil (str error)) + (done)))))))) + +(deftest legacy-s-short-url-is-supported + (testing "legacy /s/:short-id should render page html" + (async done + (let [request (js/Request. "https://publish.example/s/abc123") + env (short-url-env)] + (-> (p/let [response (routes/handle-fetch request env) + body (.text response)] + (is (= 200 (.-status response))) + (is (nil? (.get (.-headers response) "location"))) + (is (re-find #"" body)) + (is (not (re-find #"Page not found" body))) + (done)) + (p/catch (fn [error] + (is nil (str error)) + (done)))))))) + +(deftest page-uuid-route-is-still-supported + (testing "legacy /page/:graph-uuid/:page-uuid should still render page html" + (async done + (let [request (js/Request. "https://publish.example/page/3bc00ad3-f421-41e7-8c65-40861c298be5/6954ee2a-506b-4dd9-bd6d-0dc24db9c055") + env (short-url-env)] + (-> (p/let [response (routes/handle-fetch request env) + body (.text response)] + (is (= 200 (.-status response))) + (is (nil? (.get (.-headers response) "location"))) + (is (re-find #"" body)) + (is (not (re-find #"Page not found" body))) + (done)) + (p/catch (fn [error] + (is nil (str error)) + (done)))))))) diff --git a/deps/publish/test/logseq/publish/test_runner.cljs b/deps/publish/test/logseq/publish/test_runner.cljs new file mode 100644 index 0000000000..d8cfe6eeae --- /dev/null +++ b/deps/publish/test/logseq/publish/test_runner.cljs @@ -0,0 +1,21 @@ +(ns logseq.publish.test-runner + (:require [cljs.test :as ct] + [logseq.publish.routes-test] + [shadow.test :as st] + [shadow.test.env :as env])) + +(derive ::node ::ct/default) + +(defmethod ct/report [::node :end-run-tests] [m] + (if (ct/successful? m) + (js/process.exit 0) + (js/process.exit 1))) + +(defn ^:dev/after-load reset-test-data! [] + (-> (env/get-test-data) + (env/reset-test-data!))) + +(defn main [& _args] + (reset-test-data!) + (let [test-env (ct/empty-env ::node)] + (st/run-all-tests test-env nil)))