From f2bf5a3111cc43ad9fac357dd1aa96b97ade7fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 22 Jun 2026 12:25:29 +0200 Subject: [PATCH] :wrench: Add more tests for all cases and fix text token application in tests --- .../src/app/common/test_helpers/tokens.cljc | 17 +- common/src/app/common/types/text.cljc | 6 +- .../common_tests/logic/token_apply_test.cljc | 43 ++++- common/test/common_tests/types/text_test.cljc | 166 +++++++++++++++++- 4 files changed, 218 insertions(+), 14 deletions(-) diff --git a/common/src/app/common/test_helpers/tokens.cljc b/common/src/app/common/test_helpers/tokens.cljc index 21a8dd4f04..02becdc27a 100644 --- a/common/src/app/common/test_helpers/tokens.cljc +++ b/common/src/app/common/test_helpers/tokens.cljc @@ -6,12 +6,14 @@ (ns app.common.test-helpers.tokens (:require + [app.common.data :as d] [app.common.test-helpers.files :as thf] [app.common.test-helpers.shapes :as ths] [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.common.types.pages-list :as ctpl] [app.common.types.shape-tree :as ctst] + [app.common.types.text :as ctt] [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob])) @@ -81,11 +83,16 @@ :token {:name token-name} :attributes token-attrs}) (reduce (fn [shape attr] - (case attr - :stroke-width (set-stroke-width shape resolved-value) - :stroke-color (set-stroke-color shape resolved-value) - :fill (set-fill-color shape resolved-value) - (ctn/set-shape-attr shape attr resolved-value {:ignore-touched true}))) + (if (ctt/text-node-attr? attr) + (let [value (if (sequential? resolved-value) (first resolved-value) resolved-value)] + (ctt/update-text-content shape + ctt/is-content-node? + d/txt-merge {attr value})) + (case attr + :stroke-width (set-stroke-width shape resolved-value) + :stroke-color (set-stroke-color shape resolved-value) + :fill (set-fill-color shape resolved-value) + (ctn/set-shape-attr shape attr resolved-value {:ignore-touched true})))) $ shape-attrs)))] diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index c2fc8f1ab3..e0330b3264 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -78,6 +78,10 @@ text-transform-attrs text-fills)) +(defn text-node-attr? + [attr] + (d/index-of text-node-attrs attr)) + (def text-all-attrs (d/concat-set shape-attrs root-attrs paragraph-attrs text-node-attrs)) (def text-style-attrs @@ -210,7 +214,7 @@ - Normalize numeric values (legacy) into strings. - No value is equal than the default value." [key value1 value2] - (when (d/index-of text-node-attrs key) + (when (text-node-attr? key) (let [default-value (get default-text-attrs key) normalize-value (fn [value] (as-> value $ diff --git a/common/test/common_tests/logic/token_apply_test.cljc b/common/test/common_tests/logic/token_apply_test.cljc index 93829cf0f5..9715b7f235 100644 --- a/common/test/common_tests/logic/token_apply_test.cljc +++ b/common/test/common_tests/logic/token_apply_test.cljc @@ -111,8 +111,8 @@ (tht/apply-token-to-shape :frame1 "token-color" [:stroke-color] [:stroke-color] "#00ff00") (tht/apply-token-to-shape :frame1 "token-color" [:fill] [:fill] "#00ff00") (tht/apply-token-to-shape :frame1 "token-dimensions" [:width :height] [:width :height] 100) - (tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] 24) - (tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] 2) + (tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] "24") + (tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] "2") (tht/apply-token-to-shape :text1 "token-font-family" [:font-family] [:font-family] ["Helvetica" "Arial" "sans-serif"]) (tht/apply-token-to-shape :circle1 "token-sizing" @@ -331,7 +331,7 @@ d/txt-merge {:fills (ths/sample-fills-color :fill-color "#fabada") :font-size "1" - :letter-spacing "2" + :letter-spacing "3" :font-family "Arial"})) (:objects page) {}) @@ -360,3 +360,40 @@ (t/is (= (count applied-tokens-frame') 0)) (t/is (= (count applied-tokens-text') 0)) (t/is (= (count applied-tokens-circle') 0)))) + +(t/deftest dont-unapply-automatic-when-null-change + (let [;; ==== Setup + file (-> (setup-file) + (tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] "14") + (tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] "2") + (tht/apply-token-to-shape :text1 "token-font-family" [:font-family] [:font-family] ["Helvetica" "Arial" "sans-serif"])) + page (thf/current-page file) + text1 (ths/get-shape file :text1) + + ;; ==== Action + changes (-> (-> (pcb/empty-changes nil) + (pcb/with-page page) + (pcb/with-objects (:objects page))) + ;; Some changes in text content are not semantic changes + ;; and thus they don't unapply tokens (e.g. adding an attribute + ;; with value nil or with the default value). + (cls/generate-update-shapes [(:id text1)] + (fn [shape] + (txt/update-text-content + shape + txt/is-content-node? + d/txt-merge + {:font-size nil + :line-height "3" + :nonexistent-attr "sample value"})) + (:objects page) + {})) + + file' (thf/apply-changes file changes) + + ;; ==== Get + text1' (ths/get-shape file' :text1) + applied-tokens-text' (:applied-tokens text1')] + + ;; ==== Check + (t/is (= (count applied-tokens-text') 3)))) \ No newline at end of file diff --git a/common/test/common_tests/types/text_test.cljc b/common/test/common_tests/types/text_test.cljc index be4424ef27..f6dea90560 100644 --- a/common/test/common_tests/types/text_test.cljc +++ b/common/test/common_tests/types/text_test.cljc @@ -16,6 +16,8 @@ (get :content) (cttx/change-text "hello world"))) +;; Normal happy-path changes + (def content-changed-text (assoc-in content-base [:children 0 :children 0 :children 0 :text] "changed")) @@ -34,22 +36,127 @@ (update-in content-base [:children 0 :children 0 :children] #(conj % (assoc line :font-weight "700")))) - (def content-changed-structure-same-attrs (update-in content-base [:children 0 :children 0 :children] #(conj % line))) +;; Special cases + +;; Numeric value (legacy): number 14 should normalize to string "14", +;; which equals the default value in content-base +(def content-numeric-font-size-default + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] 14)) + +;; Numeric value (legacy): number 32 should normalize to string "32", +;; matching content-changed-attr (which uses string "32") +(def content-numeric-font-size-32 + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] 32)) + +;; Attribute set to nil (removed) +(def content-nil-font-size + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] nil)) + +;; Attribute set to empty string +(def content-empty-string-font-size + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] "")) + +;; Attribute set to empty vector +(def content-empty-list-font-size + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] [])) + +;; Attribute set to its default value (font-size default is "14") +(def content-default-font-size + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] "14")) + +;; Non-text-node-attr key change (grow-type is not in text-node-attrs) +(def content-non-text-node-attr + (assoc-in content-base [:children 0 :children 0 :children 0 :grow-type] "auto-height")) + +;; Other text-node-attr categories +(def content-changed-font-family + (assoc-in content-base [:children 0 :children 0 :children 0 :font-family] "Arial")) + +(def content-changed-line-height + (assoc-in content-base [:children 0 :children 0 :children 0 :line-height] "1.5")) + +(def content-changed-letter-spacing + (assoc-in content-base [:children 0 :children 0 :children 0 :letter-spacing] "2")) + +(def content-changed-text-decoration + (assoc-in content-base [:children 0 :children 0 :children 0 :text-decoration] "underline")) + +(def content-changed-text-transform + (assoc-in content-base [:children 0 :children 0 :children 0 :text-transform] "uppercase")) + +(def content-changed-typography-ref-id + (assoc-in content-base [:children 0 :children 0 :children 0 :typography-ref-id] "new-typography-id")) + +(def content-changed-fills + (assoc-in content-base [:children 0 :children 0 :children 0 :fills] + [{:fill-color "#ff0000" :fill-opacity 1}])) + + (t/deftest test-get-diff-type (let [diff-text (cttx/get-diff-type content-base content-changed-text) diff-attr (cttx/get-diff-type content-base content-changed-attr) diff-both (cttx/get-diff-type content-base content-changed-both) diff-structure (cttx/get-diff-type content-base content-changed-structure) - diff-structure-same-attrs (cttx/get-diff-type content-base content-changed-structure-same-attrs)] + diff-structure-same-attrs (cttx/get-diff-type content-base content-changed-structure-same-attrs) + ;; Numeric normalization: number 14 → string "14" → default → nil (same as base) + diff-numeric-default (cttx/get-diff-type content-base content-numeric-font-size-default) + ;; Numeric normalization: number 32 → string "32" (different from base's "14") + diff-numeric-different (cttx/get-diff-type content-base content-numeric-font-size-32) + ;; Numeric 32 vs string "32": should be equal after normalization + diff-numeric-vs-string (cttx/get-diff-type content-changed-attr content-numeric-font-size-32) + + ;; nil / empty-string / empty-list / default → all normalize to nil + diff-nil-attr (cttx/get-diff-type content-base content-nil-font-size) + diff-empty-string (cttx/get-diff-type content-base content-empty-string-font-size) + diff-empty-list (cttx/get-diff-type content-base content-empty-list-font-size) + diff-default-value (cttx/get-diff-type content-base content-default-font-size) + + ;; Non-text-node-attr key: should be ignored + diff-non-text-node (cttx/get-diff-type content-base content-non-text-node-attr) + + ;; Other text-node-attr categories + diff-font-family (cttx/get-diff-type content-base content-changed-font-family) + diff-line-height (cttx/get-diff-type content-base content-changed-line-height) + diff-letter-spacing (cttx/get-diff-type content-base content-changed-letter-spacing) + diff-text-decoration (cttx/get-diff-type content-base content-changed-text-decoration) + diff-text-transform (cttx/get-diff-type content-base content-changed-text-transform) + diff-typography-ref (cttx/get-diff-type content-base content-changed-typography-ref-id) + diff-fills (cttx/get-diff-type content-base content-changed-fills)] + + ;; Basic cases (t/is (= #{:text-content-text} diff-text)) (t/is (= #{:text-content-attribute} diff-attr)) (t/is (= #{:text-content-text :text-content-attribute} diff-both)) (t/is (= #{:text-content-structure} diff-structure)) - (t/is (= #{:text-content-structure} diff-structure-same-attrs)))) + (t/is (= #{:text-content-structure} diff-structure-same-attrs)) + + ;; Numeric normalization + (t/is (= #{} diff-numeric-default)) + (t/is (= #{:text-content-attribute} diff-numeric-different)) + (t/is (= #{} diff-numeric-vs-string)) + + ;; nil / empty / default normalization (content-base has default font-size "14", + ;; which normalizes to nil; nil also normalizes to nil → equal) + (t/is (= #{} diff-nil-attr)) + (t/is (= #{} diff-empty-string)) + (t/is (= #{} diff-empty-list)) + (t/is (= #{} diff-default-value)) + + ;; Non-text-node-attr key is ignored + (t/is (= #{} diff-non-text-node)) + + ;; Each text-node-attr category triggers attribute diff + (t/is (= #{:text-content-attribute} diff-font-family)) + (t/is (= #{:text-content-attribute} diff-line-height)) + (t/is (= #{:text-content-attribute} diff-letter-spacing)) + (t/is (= #{:text-content-attribute} diff-text-decoration)) + (t/is (= #{:text-content-attribute} diff-text-transform)) + (t/is (= #{:text-content-attribute} diff-typography-ref)) + (t/is (= #{:text-content-attribute} diff-fills)))) (t/deftest test-get-diff-attrs @@ -57,13 +164,62 @@ attrs-attr (cttx/get-diff-attrs content-base content-changed-attr) attrs-both (cttx/get-diff-attrs content-base content-changed-both) attrs-structure (cttx/get-diff-attrs content-base content-changed-structure) - attrs-structure-same-attrs (cttx/get-diff-attrs content-base content-changed-structure-same-attrs)] + attrs-structure-same-attrs (cttx/get-diff-attrs content-base content-changed-structure-same-attrs) + ;; Numeric normalization: number 14 → string "14" → default → nil (same as base) + attrs-numeric-default (cttx/get-diff-attrs content-base content-numeric-font-size-default) + ;; Numeric normalization: number 32 → string "32" (different from base's "14") + attrs-numeric-different (cttx/get-diff-attrs content-base content-numeric-font-size-32) + ;; Numeric 32 vs string "32": should be equal after normalization + attrs-numeric-vs-string (cttx/get-diff-attrs content-changed-attr content-numeric-font-size-32) + + ;; nil / empty-string / empty-list / default → all normalize to nil + attrs-nil-attr (cttx/get-diff-attrs content-base content-nil-font-size) + attrs-empty-string (cttx/get-diff-attrs content-base content-empty-string-font-size) + attrs-empty-list (cttx/get-diff-attrs content-base content-empty-list-font-size) + attrs-default-value (cttx/get-diff-attrs content-base content-default-font-size) + + ;; Non-text-node-attr key: should be ignored + attrs-non-text-node (cttx/get-diff-attrs content-base content-non-text-node-attr) + + ;; Other text-node-attr categories + attrs-font-family (cttx/get-diff-attrs content-base content-changed-font-family) + attrs-line-height (cttx/get-diff-attrs content-base content-changed-line-height) + attrs-letter-spacing (cttx/get-diff-attrs content-base content-changed-letter-spacing) + attrs-text-decoration (cttx/get-diff-attrs content-base content-changed-text-decoration) + attrs-text-transform (cttx/get-diff-attrs content-base content-changed-text-transform) + attrs-typography-ref (cttx/get-diff-attrs content-base content-changed-typography-ref-id) + attrs-fills (cttx/get-diff-attrs content-base content-changed-fills)] + + ;; Basic cases (t/is (= #{} attrs-text)) (t/is (= #{:font-size} attrs-attr)) (t/is (= #{:font-size} attrs-both)) (t/is (= #{} attrs-structure)) - (t/is (= #{} attrs-structure-same-attrs)))) + (t/is (= #{} attrs-structure-same-attrs)) + + ;; Numeric normalization + (t/is (= #{} attrs-numeric-default)) + (t/is (= #{:font-size} attrs-numeric-different)) + (t/is (= #{} attrs-numeric-vs-string)) + + ;; nil / empty / default normalization + (t/is (= #{} attrs-nil-attr)) + (t/is (= #{} attrs-empty-string)) + (t/is (= #{} attrs-empty-list)) + (t/is (= #{} attrs-default-value)) + + ;; Non-text-node-attr key is ignored + (t/is (= #{} attrs-non-text-node)) + + ;; Each text-node-attr category reports correct attr key + (t/is (= #{:font-family} attrs-font-family)) + (t/is (= #{:line-height} attrs-line-height)) + (t/is (= #{:letter-spacing} attrs-letter-spacing)) + (t/is (= #{:text-decoration} attrs-text-decoration)) + (t/is (= #{:text-transform} attrs-text-transform)) + (t/is (= #{:typography-ref-id} attrs-typography-ref)) + (t/is (= #{:fills} attrs-fills)))) (t/deftest test-equal-structure