diff --git a/common/src/app/common/test_helpers/composable/comp/nodes.cljc b/common/src/app/common/test_helpers/composable/comp/nodes.cljc index 5c66625ce6..9d47e02b80 100644 --- a/common/src/app/common/test_helpers/composable/comp/nodes.cljc +++ b/common/src/app/common/test_helpers/composable/comp/nodes.cljc @@ -91,7 +91,8 @@ ;; --------------------------------------------------------------------------- (def scalar-properties - #{:strokes :hidden :blocked :r1 :blend-mode :hide-fill-on-export :show-content + #{:strokes :shadow :blur :background-blur :hidden :blocked :r1 :r2 :r3 :r4 + :blend-mode :hide-fill-on-export :show-content :fixed-scroll :constraints-h :constraints-v :layout-item-margin :layout-gap :layout-padding :layout-align-items}) diff --git a/common/src/app/common/test_helpers/composable/gen.cljc b/common/src/app/common/test_helpers/composable/gen.cljc index 3aab239e14..95486a9f27 100644 --- a/common/src/app/common/test_helpers/composable/gen.cljc +++ b/common/src/app/common/test_helpers/composable/gen.cljc @@ -373,7 +373,28 @@ [:layout-item-margin [{:m1 0 :m2 0 :m3 0 :m4 0} {:m1 4 :m2 4 :m3 4 :m4 4}]] [:layout-gap [{:row-gap 0 :column-gap 0} {:row-gap 8 :column-gap 8}]] [:layout-padding [{:p1 0 :p2 0 :p3 0 :p4 0} {:p1 8 :p2 8 :p3 8 :p4 8}]] - [:layout-align-items [:start :center :end]]]) + [:layout-align-items [:start :center :end]] + [:shadow [[] [{:id #uuid "10000000-0000-0000-0000-000000000001" + :style :drop-shadow :color {:color "#000000" :opacity 0.5} + :offset-x 2 :offset-y 3 :blur 4 :spread 1 :hidden false}] + [{:id #uuid "10000000-0000-0000-0000-000000000001" + :style :inner-shadow :color {:color "#ff0000" :opacity 0.75} + :offset-x -2 :offset-y 4 :blur 8 :spread 2 :hidden false}]]] + [:blur [{:id #uuid "10000000-0000-0000-0000-000000000002" + :type :layer-blur :value 0 :hidden true} + {:id #uuid "10000000-0000-0000-0000-000000000002" + :type :layer-blur :value 4 :hidden false} + {:id #uuid "10000000-0000-0000-0000-000000000002" + :type :layer-blur :value 12 :hidden false}]] + [:background-blur [{:id #uuid "10000000-0000-0000-0000-000000000003" + :type :background-blur :value 0 :hidden true} + {:id #uuid "10000000-0000-0000-0000-000000000003" + :type :background-blur :value 6 :hidden false} + {:id #uuid "10000000-0000-0000-0000-000000000003" + :type :background-blur :value 16 :hidden false}]] + [:r2 [0 8 16]] + [:r3 [0 8 16]] + [:r4 [0 8 16]]]) (def text-style-edits "All twelve style units, independent of the production text group table." diff --git a/common/src/app/common/test_helpers/composable/shadow.cljc b/common/src/app/common/test_helpers/composable/shadow.cljc index 0c008e23a1..fc0ec16218 100644 --- a/common/src/app/common/test_helpers/composable/shadow.cljc +++ b/common/src/app/common/test_helpers/composable/shadow.cljc @@ -19,7 +19,9 @@ (def groups {:fills :fill-group :opacity :layer-effects-group :name :name-group :strokes :stroke-group :hidden :visibility-group :blocked :modifiable-group - :r1 :radius-group :blend-mode :layer-effects-group :hide-fill-on-export :fill-group + :r1 :radius-group :r2 :radius-group :r3 :radius-group :r4 :radius-group + :shadow :shadow-group :blur :blur-group :background-blur :blur-group + :blend-mode :layer-effects-group :hide-fill-on-export :fill-group :show-content :show-content :fixed-scroll :constraints-group :constraints-h :constraints-group :constraints-v :constraints-group :layout-item-margin :layout-item-margin :layout-gap :layout-gap diff --git a/common/test/common_tests/logic/composable_gen_test.cljc b/common/test/common_tests/logic/composable_gen_test.cljc index 0d06a59425..5018c66e93 100644 --- a/common/test/common_tests/logic/composable_gen_test.cljc +++ b/common/test/common_tests/logic/composable_gen_test.cljc @@ -85,6 +85,74 @@ (t/is (= :frame (get-in resolved [:shape :type])) (str "property " property ", scope " scope)))))) +(t/deftest generated-effect-and-corner-edits-have-distinct-inputs + (let [situation (cg/world [2 1 {}])] + (doseq [[index attr] [[14 :shadow] [15 :blur] [16 :background-blur] + [17 :r2] [18 :r3] [19 :r4]]] + (let [resolved (cg/resolve-op situation {} [:style 0 index 1 1])] + (t/is (= attr (:property resolved))) + (t/is (some? (:op resolved))) + (when (= attr (:property resolved)) + (t/is (not= (get (:shape resolved) attr) (:value resolved)))))))) + +(t/deftest effect-and-corner-overrides-reject-lost-values-or-groups + (doseq [[index attr group] [[14 :shadow :shadow-group] [15 :blur :blur-group] + [16 :background-blur :blur-group] [17 :r2 :radius-group] + [18 :r3 :radius-group] [19 :r4 :radius-group]]] + (let [initial (cg/initial-state [1 0 {}]) + resolved (cg/resolve-op (:situation initial) {} [:style 0 index 1 1]) + shape (:shape resolved) + expected (shadow/values (assoc shape attr (:value resolved)) group) + edited (-> initial (cg/step [:style 0 index 1 1]) cg/settle-state) + situation (:situation edited) + model (:model edited) + file (tm/file situation) + path [:data :pages-index (:id (thf/current-page file)) :objects (:id shape)] + invariant (fn [file] + (try (oracle/check (tm/with-file situation file) model) nil + (catch #?(:clj Exception :cljs js/Error) error + (:invariant (ex-data error)))))] + (t/is (= expected (get-in model [(:id shape) group]))) + (t/is (= :I9 (invariant (update-in file path + #(merge (dissoc % attr) (select-keys shape [attr])))))) + (t/is (= :I3 (invariant (update-in file (conj path :touched) disj group))))))) + +(t/deftest main-effect-and-corner-edits-reach-clean-copies-and-spare-overrides + (doseq [property (range 14 20)] + (let [initial (cg/initial-state [1 0 {}]) + situation (:situation initial) + resolved (cg/resolve-op situation {} [:style 0 property 1 1]) + copy (:shape resolved) + attr (:property resolved) + main-index (first (keep-indexed (fn [index entry] + (when (= (:shape-ref copy) (get-in entry [:shape :id])) index)) + (cg/candidates situation {} :edit 0))) + main-edit [:style main-index property 0 0] + copies (filter #(= (:shape-ref copy) (get-in % [:shape :shape-ref])) (cg/tree situation)) + inherited (-> initial (cg/step main-edit) cg/settle-state) + overridden (-> inherited (cg/step [:style 0 property 1 1]) cg/settle-state) + updated (-> overridden (cg/step (assoc main-edit 3 2)) cg/settle-state) + requested (:value (cg/resolve-op situation {} (assoc main-edit 3 2)))] + (t/is (some? main-index)) + (t/is (= 2 (count copies))) + (t/is (not= requested (:value resolved))) + (doseq [{:keys [shape]} copies] + (let [actual (tm/shape-by-id (:situation updated) (:id shape))] + (t/is (= (if (= (:id copy) (:id shape)) (:value resolved) requested) (get actual attr))) + (t/is (= (= (:id copy) (:id shape)) (boolean (seq (:touched actual))))))) + (t/is (map? (cg/run {:world [1 0 {}] + :ops [main-edit [:style 0 property 1 1] (assoc main-edit 3 2) + [:undo] [:redo]]})))))) + +(t/deftest generated-effects-and-corners-survive-component-operations + (doseq [property (range 14 20)] + (t/is (map? (cg/run {:world [2 1 {:variants true :rich-variants true}] + :ops [[:style 0 property 1 1] [:style 1 property 1 0] + [:undo] [:redo] [:update-main 0] + [:style 0 property 0 1] [:reset 0] + [:style 0 property 1 1] [:detach 0] + [:undo] [:redo]]}))))) + (t/deftest text-style-edits-cover-every-style-unit (doseq [[unit group] (map-indexed vector [:text-content-family :text-content-weight :text-content-size diff --git a/frontend/test/frontend_tests/composable_tests/generated_test.cljs b/frontend/test/frontend_tests/composable_tests/generated_test.cljs index 8a6b69a191..9652362516 100644 --- a/frontend/test/frontend_tests/composable_tests/generated_test.cljs +++ b/frontend/test/frontend_tests/composable_tests/generated_test.cljs @@ -93,6 +93,15 @@ :ops [[:delete 9 9 1 2] [:text 5 9 1 3] [:style 3 1 1] [:restore 5 8 1 6] [:nest 5 6 0 2] [:undo] [:redo]]}))) +(t/deftest ^:async generated-effects-and-corners-survive-component-operations + (doseq [property (range 14 20)] + (await (replay {:world [2 1 {:variants true :rich-variants true}] + :ops [[:style 0 property 1 1] [:style 1 property 1 0] + [:undo] [:redo] [:update-main 0] + [:style 0 property 0 1] [:reset 0] + [:style 0 property 1 1] [:detach 0] + [:undo] [:redo]]})))) + (t/deftest ^:async swapping-a-copy-with-authored-position-constraints-stays-settled (await (replay {:world [2 1 {:library true :variants true :rich-variants true :text true :text-styles true :layout :flex :layout-copies true}]