diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 78a3c161b6..0bd732d13f 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -1811,9 +1811,6 @@ (not (string? value)) (u/not-valid plugin-id :value value) - (not (r/check-permission plugin-id "content:write")) - (u/not-valid plugin-id :switchVariant "Plugin doesn't have 'content:write' permission") - :else (let [shape (u/locate-shape file-id page-id id)] (if (dwv/valid-variant-switch? @st/state shape pos value) diff --git a/frontend/test/frontend_tests/plugins/page_test.cljs b/frontend/test/frontend_tests/plugins/page_test.cljs index c7fe33e643..1e5ffd3315 100644 --- a/frontend/test/frontend_tests/plugins/page_test.cljs +++ b/frontend/test/frontend_tests/plugins/page_test.cljs @@ -177,17 +177,20 @@ (first @errors))))))) (t/deftest flow-starting-board-setter-checks-permission - (let [plugin-id "test-plugin" - file-id (uuid/next) - page-id (uuid/next) - flow-id (uuid/next) - errors (atom [])] + ;; The board must be a valid flow starting frame, otherwise the setter + ;; rejects the value before it ever checks the permission. + (let [result (setup-with-board) + file-id (:id (:file result)) + page-id (cthf/current-page-id (:file result)) + board-id (:board-id result) + flow-id (uuid/next) + errors (atom [])] (with-redefs [r/check-permission (constantly false) u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg]))) - st/emit! mock/noop - shape/shape-proxy? (constantly true)] - (let [proxy (page/flow-proxy plugin-id file-id page-id flow-id)] - (set! (.-startingBoard proxy) #js {}) + st/emit! mock/noop] + (let [proxy (page/flow-proxy plugin-id file-id page-id flow-id) + board (shape/shape-proxy plugin-id file-id page-id board-id)] + (set! (.-startingBoard proxy) board) (t/is (= 1 (count @errors))) (t/is (= [plugin-id :startingBoard "Plugin doesn't have 'content:write' permission"] (first @errors))))))) @@ -208,16 +211,18 @@ (first @errors))))))) (t/deftest create-flow-checks-permission - (let [plugin-id "test-plugin" - file-id (uuid/next) - page-id (uuid/next) - errors (atom [])] + ;; The frame must be a valid flow starting frame, otherwise createFlow + ;; rejects the argument before it ever checks the permission. + (let [result (setup-with-board) + file-id (:id (:file result)) + page-id (cthf/current-page-id (:file result)) + board-id (:board-id result) + errors (atom [])] (with-redefs [r/check-permission (constantly false) u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg]))) - st/emit! mock/noop - shape/shape-proxy? (constantly true)] + st/emit! mock/noop] (let [proxy (page/page-proxy plugin-id file-id page-id) - frame #js {"$id" (uuid/next)}] + frame (shape/shape-proxy plugin-id file-id page-id board-id)] (.createFlow proxy "flow-name" frame) (t/is (= 1 (count @errors))) (t/is (= [plugin-id :createFlow "Plugin doesn't have 'content:write' permission"] diff --git a/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs b/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs index b85f471c13..7dca8b7af8 100644 --- a/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs +++ b/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs @@ -176,6 +176,7 @@ (with-redefs [u/locate-shape (fn [_file _page id] {:id id :component-id id}) u/locate-library-component (constantly {:id (uuid/next)}) ctk/is-variant? (constantly false) + dwv/valid-components-for-variants? (constantly true) dwv/combine-as-variants (fn [ids opts] (reset! captured {:ids ids :opts opts}) @@ -381,6 +382,7 @@ errors (atom [])] (with-redefs [u/locate-shape (constantly {:id shape-id :component-id shape-id}) u/locate-library-component (constantly {:id (uuid/next)}) + u/page-active? (constantly true) u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg]))) r/check-permission (constantly false) st/emit! mock/noop] diff --git a/frontend/test/frontend_tests/plugins/text_test.cljs b/frontend/test/frontend_tests/plugins/text_test.cljs index 3f4d96be9d..49b4dc4ea3 100644 --- a/frontend/test/frontend_tests/plugins/text_test.cljs +++ b/frontend/test/frontend_tests/plugins/text_test.cljs @@ -22,29 +22,42 @@ ;; Regression coverage for issue #9780. ;; ;; `letterSpacing` accepts negative tracking in the product UI (-200..200, -;; see typography.cljs), but the plugin validator regex rejected any leading -;; minus, so negative values were refused. `letter-spacing-re` is the shared -;; predicate behind both the shape- and range-level setters; pin its -;; accept/reject contract here. +;; see typography.cljs), but the plugin setter rejected any leading minus, +;; so negative values were refused. Pin the accept/reject contract of the +;; plugin setter here. -(def ^:private letter-spacing-re @#'plugins.text/letter-spacing-re) +(defn- apply-letter-spacing + "Sets `letterSpacing` on a text range proxy and returns the attributes sent + to the update event, or nil when the plugin rejected the value." + [value] + (let [captured (atom nil) + range (plugins.text/text-range-proxy + plugin-id (random-uuid) (random-uuid) (random-uuid) 0 4)] + (with-redefs [r/check-permission (constantly true) + u/page-active? (constantly true) + u/not-valid (fn [_ _ _] nil) + dwt/update-text-range + (fn [_ _ _ attrs] + (reset! captured attrs) + :update-text-range) + st/emit! mock/noop] + (set! (.-letterSpacing range) value) + @captured))) -(defn- valid? [s] (boolean (re-matches letter-spacing-re s))) +(t/deftest letter-spacing-accepts-negative-values + (t/is (= {:letter-spacing "-0.56"} (apply-letter-spacing "-0.56"))) + (t/is (= {:letter-spacing "-12"} (apply-letter-spacing "-12"))) + (t/is (= {:letter-spacing "-200"} (apply-letter-spacing "-200")))) -(t/deftest letter-spacing-re-accepts-negative-values - (t/is (valid? "-0.56")) - (t/is (valid? "-12")) - (t/is (valid? "-200"))) +(t/deftest letter-spacing-accepts-non-negative-values + (t/is (= {:letter-spacing "0"} (apply-letter-spacing "0"))) + (t/is (= {:letter-spacing "12"} (apply-letter-spacing "12"))) + (t/is (= {:letter-spacing "1.5"} (apply-letter-spacing "1.5")))) -(t/deftest letter-spacing-re-accepts-non-negative-values - (t/is (valid? "0")) - (t/is (valid? "12")) - (t/is (valid? "1.5"))) - -(t/deftest letter-spacing-re-rejects-non-numeric - (t/is (not (valid? "abc"))) - (t/is (not (valid? "1-2"))) - (t/is (not (valid? "--1")))) +(t/deftest letter-spacing-rejects-non-numeric + (t/is (nil? (apply-letter-spacing "abc"))) + (t/is (nil? (apply-letter-spacing "1-2"))) + (t/is (nil? (apply-letter-spacing "--1")))) (t/deftest font-apply-to-text-uses-font-id-not-shape-id diff --git a/frontend/test/frontend_tests/plugins/tokens_test.cljs b/frontend/test/frontend_tests/plugins/tokens_test.cljs index 3f4f56f6d9..8c50fc189d 100644 --- a/frontend/test/frontend_tests/plugins/tokens_test.cljs +++ b/frontend/test/frontend_tests/plugins/tokens_test.cljs @@ -142,7 +142,7 @@ (ctob/make-token :id token-id :name "spacing.medium" :type :spacing - :value 16))))) + :value "16"))))) store (ths/setup-store file) _ (set! st/state store) _ (set! st/stream (ptk/input-stream store)) @@ -341,15 +341,29 @@ (t/is (not (contains? (-> @captured second :theme :sets) "Primitives")))))) (t/deftest font-family-token-value-accepts-a-string - (let [file-id (cthi/new-id! :file) - set-id (cthi/new-id! :set) - token-id (cthi/new-id! :token) + ;; The setter validates the candidate token against the file tokens library, + ;; so the token has to live in a real library. + (let [set-id (cthi/new-id! :token-set) + token-id (cthi/new-id! :font-token) + file (-> (cthf/sample-file :file1 :page-label :page1) + (ctht/add-tokens-lib) + (ctht/update-tokens-lib + #(-> % + (ctob/add-set + (ctob/make-token-set :id set-id + :name "fonts")) + (ctob/add-token + set-id + (ctob/make-token :id token-id + :name "font.primary" + :type :font-family + :value ["Inter"]))))) + store (ths/setup-store file) + _ (set! st/state store) + _ (set! st/stream (ptk/input-stream store)) + file-id (:id file) captured (atom nil)] (with-redefs [r/check-permission (constantly true) - u/locate-token (constantly {:id token-id - :name "font.primary" - :type :font-family - :value ["Inter"]}) dwtl/update-token (mock/stub (fn [set-id token-id attrs] (reset! captured {:set-id set-id :token-id token-id