🔧 Add more tests for all cases and fix text token application in tests

This commit is contained in:
Andrés Moya 2026-06-22 12:25:29 +02:00
parent 5f8d9740d6
commit f2bf5a3111
4 changed files with 218 additions and 14 deletions

View File

@ -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)))]

View File

@ -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 $

View File

@ -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))))

View File

@ -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