mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 19:28:12 +00:00
* 🎉 Add tests for app.common.geom.bounds-map * 🎉 Add tests for app.common.geom and descendant namespaces * 📎 Fix linting issues --------- Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
188 lines
7.6 KiB
Clojure
188 lines
7.6 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS INC
|
|
|
|
(ns common-tests.geom-modifiers-test
|
|
(:require
|
|
[app.common.geom.modifiers :as gm]
|
|
[app.common.geom.point :as gpt]
|
|
[app.common.test-helpers.files :as thf]
|
|
[app.common.test-helpers.ids-map :as thi]
|
|
[app.common.test-helpers.shapes :as ths]
|
|
[app.common.types.modifiers :as ctm]
|
|
[clojure.test :as t]))
|
|
|
|
(t/use-fixtures :each thi/test-fixture)
|
|
|
|
;; ---- Helpers
|
|
|
|
(defn- add-flex-frame
|
|
"Create a flex layout frame"
|
|
[file frame-label & {:keys [width height] :as params}]
|
|
(ths/add-sample-shape file frame-label
|
|
(merge {:type :frame
|
|
:name "FlexFrame"
|
|
:layout-flex-dir :row
|
|
:width (or width 200)
|
|
:height (or height 200)}
|
|
params)))
|
|
|
|
(defn- add-rect-child
|
|
"Create a rectangle child inside a parent"
|
|
[file rect-label parent-label & {:keys [width height x y] :as params}]
|
|
(ths/add-sample-shape file rect-label
|
|
(merge {:type :rect
|
|
:name "Rect"
|
|
:parent-label parent-label
|
|
:width (or width 50)
|
|
:height (or height 50)
|
|
:x (or x 0)
|
|
:y (or y 0)}
|
|
params)))
|
|
|
|
(defn- add-ghost-child-id
|
|
"Add a non-existent child ID to a frame's shapes list.
|
|
This simulates data inconsistency where a child ID is referenced
|
|
but the child shape doesn't exist in objects."
|
|
[file frame-label ghost-id]
|
|
(let [page (thf/current-page file)
|
|
frame-id (thi/id frame-label)]
|
|
(update file :data
|
|
(fn [file-data]
|
|
(update-in file-data [:pages-index (:id page) :objects frame-id :shapes]
|
|
conj ghost-id)))))
|
|
|
|
;; ---- Tests
|
|
|
|
(t/deftest flex-layout-with-normal-children
|
|
(t/testing "set-objects-modifiers processes flex layout children correctly"
|
|
(let [file (-> (thf/sample-file :file1)
|
|
(add-flex-frame :frame1)
|
|
(add-rect-child :rect1 :frame1))
|
|
page (thf/current-page file)
|
|
objects (:objects page)
|
|
rect-id (thi/id :rect1)
|
|
|
|
;; Create a move modifier for the rectangle
|
|
modif-tree {rect-id {:modifiers (ctm/move-modifiers (gpt/point 10 20))}}
|
|
|
|
;; This should not crash
|
|
result (gm/set-objects-modifiers modif-tree objects)]
|
|
|
|
(t/is (some? result))
|
|
;; The rectangle should have modifiers
|
|
(t/is (contains? result rect-id)))))
|
|
|
|
(t/deftest flex-layout-with-nonexistent-child
|
|
(t/testing "set-objects-modifiers handles flex frame with non-existent child in shapes"
|
|
(let [ghost-id (thi/next-uuid)
|
|
file (-> (thf/sample-file :file1)
|
|
(add-flex-frame :frame1)
|
|
(add-rect-child :rect1 :frame1)
|
|
;; Add a non-existent child ID to the frame's shapes
|
|
(add-ghost-child-id :frame1 ghost-id))
|
|
page (thf/current-page file)
|
|
objects (:objects page)
|
|
rect-id (thi/id :rect1)
|
|
|
|
;; Create a move modifier for the existing rectangle
|
|
modif-tree {rect-id {:modifiers (ctm/move-modifiers (gpt/point 10 20))}}
|
|
|
|
;; This should NOT crash even though the flex frame has
|
|
;; a child ID (ghost-id) that doesn't exist in objects
|
|
result (gm/set-objects-modifiers modif-tree objects)]
|
|
|
|
(t/is (some? result))
|
|
(t/is (contains? result rect-id)))))
|
|
|
|
(t/deftest flex-layout-with-all-ghost-children
|
|
(t/testing "set-objects-modifiers handles flex frame with only non-existent children"
|
|
(let [ghost1 (thi/next-uuid)
|
|
ghost2 (thi/next-uuid)
|
|
file (-> (thf/sample-file :file1)
|
|
(add-flex-frame :frame1)
|
|
;; Add only non-existent children to the frame's shapes
|
|
(add-ghost-child-id :frame1 ghost1)
|
|
(add-ghost-child-id :frame1 ghost2))
|
|
page (thf/current-page file)
|
|
objects (:objects page)
|
|
frame-id (thi/id :frame1)
|
|
|
|
;; Create a move modifier for the frame itself
|
|
modif-tree {frame-id {:modifiers (ctm/move-modifiers (gpt/point 5 5))}}
|
|
|
|
;; Should not crash even though the flex frame has
|
|
;; no existing children in its shapes list
|
|
result (gm/set-objects-modifiers modif-tree objects)]
|
|
|
|
(t/is (some? result)))))
|
|
|
|
(t/deftest grid-layout-with-nonexistent-child
|
|
(t/testing "set-objects-modifiers handles grid frame with non-existent child in shapes"
|
|
(let [ghost-id (thi/next-uuid)
|
|
file (-> (thf/sample-file :file1)
|
|
(ths/add-sample-shape :frame1
|
|
{:type :frame
|
|
:name "GridFrame"
|
|
:layout-grid-dir :row
|
|
:width 200
|
|
:height 200})
|
|
(add-rect-child :rect1 :frame1)
|
|
(add-ghost-child-id :frame1 ghost-id))
|
|
page (thf/current-page file)
|
|
objects (:objects page)
|
|
rect-id (thi/id :rect1)
|
|
|
|
modif-tree {rect-id {:modifiers (ctm/move-modifiers (gpt/point 10 20))}}
|
|
|
|
;; Should not crash for grid layout with ghost child
|
|
result (gm/set-objects-modifiers modif-tree objects)]
|
|
|
|
(t/is (some? result))
|
|
(t/is (contains? result rect-id)))))
|
|
|
|
(t/deftest flex-layout-resize-with-nonexistent-child
|
|
(t/testing "resize modifier propagation handles non-existent children"
|
|
(let [ghost-id (thi/next-uuid)
|
|
file (-> (thf/sample-file :file1)
|
|
(add-flex-frame :frame1)
|
|
(add-rect-child :rect1 :frame1)
|
|
(add-ghost-child-id :frame1 ghost-id))
|
|
page (thf/current-page file)
|
|
objects (:objects page)
|
|
frame-id (thi/id :frame1)
|
|
|
|
;; Create a resize modifier for the frame itself
|
|
modif-tree {frame-id {:modifiers (ctm/resize-modifiers
|
|
(gpt/point 2 2)
|
|
(gpt/point 0 0))}}
|
|
|
|
;; Should not crash when propagating resize through flex layout
|
|
;; that has ghost children
|
|
result (gm/set-objects-modifiers modif-tree objects)]
|
|
|
|
(t/is (some? result))
|
|
;; The frame should have modifiers
|
|
(t/is (contains? result frame-id)))))
|
|
|
|
(t/deftest nested-flex-layout-with-nonexistent-child
|
|
(t/testing "nested flex layout handles non-existent children in outer frame"
|
|
(let [ghost-id (thi/next-uuid)
|
|
file (-> (thf/sample-file :file1)
|
|
(add-flex-frame :outer-frame)
|
|
(add-flex-frame :inner-frame :parent-label :outer-frame)
|
|
(add-rect-child :rect1 :inner-frame)
|
|
(add-ghost-child-id :outer-frame ghost-id))
|
|
page (thf/current-page file)
|
|
objects (:objects page)
|
|
rect-id (thi/id :rect1)
|
|
|
|
modif-tree {rect-id {:modifiers (ctm/move-modifiers (gpt/point 5 10))}}
|
|
|
|
result (gm/set-objects-modifiers modif-tree objects)]
|
|
|
|
(t/is (some? result))
|
|
(t/is (contains? result rect-id)))))
|