mirror of
https://github.com/penpot/penpot.git
synced 2025-01-10 00:40:30 -05:00
610 lines
24 KiB
Clojure
610 lines
24 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.logic.comp-creation-test
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.files.changes-builder :as pcb]
|
|
[app.common.files.shapes-helpers :as cfsh]
|
|
[app.common.geom.point :as gpt]
|
|
[app.common.logic.libraries :as cll]
|
|
[app.common.logic.shapes :as cls]
|
|
[app.common.types.component :as ctk]
|
|
[app.common.types.components-list :as ctkl]
|
|
[app.common.types.shape-tree :as ctst]
|
|
[clojure.test :as t]
|
|
[common-tests.helpers.components :as thc]
|
|
[common-tests.helpers.compositions :as tho]
|
|
[common-tests.helpers.files :as thf]
|
|
[common-tests.helpers.ids-map :as thi]
|
|
[common-tests.helpers.shapes :as ths]))
|
|
|
|
(t/use-fixtures :each thi/test-fixture)
|
|
|
|
(t/deftest test-add-component-from-single-frame
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(ths/add-sample-shape :frame1 :type :frame))
|
|
|
|
page (thf/current-page file)
|
|
frame1 (ths/get-shape file :frame1)
|
|
|
|
;; ==== Action
|
|
[_ component-id changes]
|
|
(cll/generate-add-component (pcb/empty-changes)
|
|
[frame1]
|
|
(:objects page)
|
|
(:id page)
|
|
(:id file)
|
|
true
|
|
nil
|
|
nil)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component (thc/get-component-by-id file' component-id)
|
|
root (ths/get-shape-by-id file' (:main-instance-id component))
|
|
frame1' (ths/get-shape file' :frame1)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? component))
|
|
(t/is (some? root))
|
|
(t/is (some? frame1'))
|
|
(t/is (= (:id root) (:id frame1')))
|
|
(t/is (ctk/main-instance? root))
|
|
(t/is (ctk/main-instance-of? (:id root) (:id page) component))))
|
|
|
|
(t/deftest test-add-component-from-single-shape
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(ths/add-sample-shape :shape1 :type :rect))
|
|
|
|
page (thf/current-page file)
|
|
shape1 (ths/get-shape file :shape1)
|
|
|
|
;; ==== Action
|
|
[_ component-id changes]
|
|
(cll/generate-add-component (pcb/empty-changes)
|
|
[shape1]
|
|
(:objects page)
|
|
(:id page)
|
|
(:id file)
|
|
true
|
|
nil
|
|
cfsh/prepare-create-artboard-from-selection)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component (thc/get-component-by-id file' component-id)
|
|
root (ths/get-shape-by-id file' (:main-instance-id component))
|
|
shape1' (ths/get-shape file' :shape1)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? component))
|
|
(t/is (some? root))
|
|
(t/is (some? shape1'))
|
|
(t/is (ctst/parent-of? root shape1'))
|
|
(t/is (= (:type root) :frame))
|
|
(t/is (ctk/main-instance? root))
|
|
(t/is (ctk/main-instance-of? (:id root) (:id page) component))))
|
|
|
|
(t/deftest test-add-component-from-several-shapes
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(ths/add-sample-shape :shape1 :type :rect)
|
|
(ths/add-sample-shape :shape2 :type :rect))
|
|
|
|
page (thf/current-page file)
|
|
shape1 (ths/get-shape file :shape1)
|
|
shape2 (ths/get-shape file :shape2)
|
|
|
|
;; ==== Action
|
|
[_ component-id changes]
|
|
(cll/generate-add-component (pcb/empty-changes)
|
|
[shape1 shape2]
|
|
(:objects page)
|
|
(:id page)
|
|
(:id file)
|
|
true
|
|
nil
|
|
cfsh/prepare-create-artboard-from-selection)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component (thc/get-component-by-id file' component-id)
|
|
root (ths/get-shape-by-id file' (:main-instance-id component))
|
|
shape1' (ths/get-shape file' :shape1)
|
|
shape2' (ths/get-shape file' :shape2)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? component))
|
|
(t/is (some? root))
|
|
(t/is (some? shape1'))
|
|
(t/is (some? shape2'))
|
|
(t/is (ctst/parent-of? root shape1'))
|
|
(t/is (ctst/parent-of? root shape2'))
|
|
(t/is (= (:type root) :frame))
|
|
(t/is (ctk/main-instance? root))
|
|
(t/is (ctk/main-instance-of? (:id root) (:id page) component))))
|
|
|
|
(t/deftest test-add-component-from-several-frames
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(ths/add-sample-shape :frame1 :type :frame)
|
|
(ths/add-sample-shape :frame2 :type :frame))
|
|
|
|
page (thf/current-page file)
|
|
frame1 (ths/get-shape file :frame1)
|
|
frame2 (ths/get-shape file :frame2)
|
|
|
|
;; ==== Action
|
|
[_ component-id changes]
|
|
(cll/generate-add-component (pcb/empty-changes)
|
|
[frame1 frame2]
|
|
(:objects page)
|
|
(:id page)
|
|
(:id file)
|
|
true
|
|
nil
|
|
cfsh/prepare-create-artboard-from-selection)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component (thc/get-component-by-id file' component-id)
|
|
root (ths/get-shape-by-id file' (:main-instance-id component))
|
|
frame1' (ths/get-shape file' :frame1)
|
|
frame2' (ths/get-shape file' :frame2)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? component))
|
|
(t/is (some? root))
|
|
(t/is (some? frame1'))
|
|
(t/is (some? frame2'))
|
|
(t/is (ctst/parent-of? root frame1'))
|
|
(t/is (ctst/parent-of? root frame2'))
|
|
(t/is (= (:type root) :frame))
|
|
(t/is (ctk/main-instance? root))
|
|
(t/is (ctk/main-instance-of? (:id root) (:id page) component))))
|
|
|
|
(t/deftest test-add-component-from-frame-with-children
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(ths/add-sample-shape :frame1 :type :frame)
|
|
(ths/add-sample-shape :shape1 :type :rect :parent-label :frame1)
|
|
(ths/add-sample-shape :shape2 :type :rect :parent-label :frame1))
|
|
|
|
page (thf/current-page file)
|
|
frame1 (ths/get-shape file :frame1)
|
|
|
|
;; ==== Action
|
|
[_ component-id changes]
|
|
(cll/generate-add-component (pcb/empty-changes)
|
|
[frame1]
|
|
(:objects page)
|
|
(:id page)
|
|
(:id file)
|
|
true
|
|
nil
|
|
nil)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component (thc/get-component-by-id file' component-id)
|
|
root (ths/get-shape-by-id file' (:main-instance-id component))
|
|
frame1' (ths/get-shape file' :frame1)
|
|
shape1' (ths/get-shape file' :shape1)
|
|
shape2' (ths/get-shape file' :shape2)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? component))
|
|
(t/is (some? root))
|
|
(t/is (some? frame1'))
|
|
(t/is (= (:id root) (:id frame1')))
|
|
(t/is (ctst/parent-of? frame1' shape1'))
|
|
(t/is (ctst/parent-of? frame1' shape2'))
|
|
(t/is (ctk/main-instance? root))
|
|
(t/is (ctk/main-instance-of? (:id root) (:id page) component))))
|
|
|
|
(t/deftest test-add-component-from-copy
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component-with-copy :component1
|
|
:main1-root
|
|
:main1-child
|
|
:copy1-root))
|
|
|
|
page (thf/current-page file)
|
|
copy1-root (ths/get-shape file :copy1-root)
|
|
|
|
;; ==== Action
|
|
[_ component2-id changes]
|
|
(cll/generate-add-component (pcb/empty-changes)
|
|
[copy1-root]
|
|
(:objects page)
|
|
(:id page)
|
|
(:id file)
|
|
true
|
|
nil
|
|
cfsh/prepare-create-artboard-from-selection)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component2' (thc/get-component-by-id file' component2-id)
|
|
root2' (ths/get-shape-by-id file' (:main-instance-id component2'))
|
|
copy1-root' (ths/get-shape file' :copy1-root)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? component2'))
|
|
(t/is (some? root2'))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (ctst/parent-of? root2' copy1-root'))
|
|
(t/is (ctk/main-instance? root2'))
|
|
(t/is (ctk/main-instance-of? (:id root2') (:id page) component2'))))
|
|
|
|
(t/deftest test-rename-component
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component :component1
|
|
:main1-root
|
|
:main1-child
|
|
:name "Test component before"))
|
|
|
|
component (thc/get-component file :component1)
|
|
|
|
;; ==== Action
|
|
changes (cll/generate-rename-component (pcb/empty-changes)
|
|
(:id component)
|
|
"Test component after"
|
|
(:data file)
|
|
true)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component' (thc/get-component file' :component1)]
|
|
|
|
;; ==== Check
|
|
(t/is (= (:name component') "Test component after"))))
|
|
|
|
(t/deftest test-duplicate-component
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component :component1
|
|
:main1-root
|
|
:main1-child))
|
|
|
|
component (thc/get-component file :component1)
|
|
|
|
;; ==== Action
|
|
changes (cll/generate-duplicate-component (pcb/empty-changes)
|
|
file
|
|
(:id component)
|
|
true)
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
components' (ctkl/components-seq (:data file'))
|
|
component1' (d/seek #(= (:id %) (thi/id :component1)) components')
|
|
component2' (d/seek #(not= (:id %) (thi/id :component1)) components')
|
|
root1' (ths/get-shape-by-id file' (:main-instance-id component1'))
|
|
root2' (ths/get-shape-by-id file' (:main-instance-id component2'))
|
|
child1' (ths/get-shape-by-id file' (first (:shapes root1')))
|
|
child2' (ths/get-shape-by-id file' (first (:shapes root2')))]
|
|
|
|
;; ==== Check
|
|
(t/is (= 2 (count components')))
|
|
(t/is (some? component1'))
|
|
(t/is (some? component2'))
|
|
(t/is (some? root1'))
|
|
(t/is (some? root2'))
|
|
(t/is (= (thi/id :main1-root) (:id root1')))
|
|
(t/is (not= (thi/id :main1-root) (:id root2')))
|
|
(t/is (some? child1'))
|
|
(t/is (some? child2'))
|
|
(t/is (= (thi/id :main1-child) (:id child1')))
|
|
(t/is (not= (thi/id :main1-child) (:id child2')))))
|
|
|
|
(t/deftest test-delete-component
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component-with-copy :component1
|
|
:main1-root
|
|
:main1-child
|
|
:copy1-root))
|
|
|
|
page (thf/current-page file)
|
|
root (ths/get-shape file :main1-root)
|
|
|
|
;; ==== Action
|
|
[_ changes]
|
|
(cls/generate-delete-shapes (pcb/empty-changes)
|
|
file
|
|
page
|
|
(:objects page)
|
|
#{(:id root)}
|
|
{:components-v2 true})
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component1' (thc/get-component file' :component1 :include-deleted? true)
|
|
copy1-root' (ths/get-shape file' :copy1-root)
|
|
|
|
main1-root' (ths/get-shape file' :main1-root)
|
|
main1-child' (ths/get-shape file' :main1-child)
|
|
|
|
saved-objects (:objects component1')
|
|
saved-main1-root' (get saved-objects (thi/id :main1-root))
|
|
saved-main1-child' (get saved-objects (thi/id :main1-child))]
|
|
|
|
;; ==== Check
|
|
(t/is (true? (:deleted component1')))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (nil? main1-root'))
|
|
(t/is (nil? main1-child'))
|
|
(t/is (some? saved-main1-root'))
|
|
(t/is (some? saved-main1-child'))))
|
|
|
|
(t/deftest test-restore-component
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component-with-copy :component1
|
|
:main1-root
|
|
:main1-child
|
|
:copy1-root))
|
|
|
|
page (thf/current-page file)
|
|
root (ths/get-shape file :main1-root)
|
|
|
|
;; ==== Action
|
|
[_ changes]
|
|
(cls/generate-delete-shapes (pcb/empty-changes)
|
|
file
|
|
page
|
|
(:objects page)
|
|
#{(:id root)}
|
|
{:components-v2 true})
|
|
|
|
file-deleted (thf/apply-changes file changes)
|
|
page-deleted (thf/current-page file-deleted)
|
|
|
|
changes (cll/generate-restore-component (pcb/empty-changes)
|
|
(:data file-deleted)
|
|
(thi/id :component1)
|
|
(:id file-deleted)
|
|
page-deleted
|
|
(:objects page-deleted))
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component1' (thc/get-component file' :component1 :include-deleted? false)
|
|
copy1-root' (ths/get-shape file' :copy1-root)
|
|
|
|
main1-root' (ths/get-shape file' :main1-root)
|
|
main1-child' (ths/get-shape file' :main1-child)
|
|
|
|
saved-objects' (:objects component1')]
|
|
|
|
;; ==== Check
|
|
(t/is (nil? (:deleted component1')))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (some? main1-root'))
|
|
(t/is (some? main1-child'))
|
|
(t/is (ctk/main-instance? main1-root'))
|
|
(t/is (ctk/main-instance-of? (:id main1-root') (:id page) component1'))
|
|
(t/is (nil? saved-objects'))))
|
|
|
|
(t/deftest test-instantiate-component
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component :component1
|
|
:main1-root
|
|
:main1-child))
|
|
|
|
page (thf/current-page file)
|
|
component (thc/get-component file :component1)
|
|
|
|
;; ==== Action
|
|
[new-shape changes]
|
|
(cll/generate-instantiate-component (-> (pcb/empty-changes nil (:id page)) ;; This may not be moved to generate
|
|
(pcb/with-objects (:objects page))) ;; because in some cases the objects
|
|
(:objects page) ;; not the same as those on the page
|
|
(:id file)
|
|
(:id component)
|
|
(gpt/point 1000 1000)
|
|
page
|
|
{(:id file) file})
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component' (thc/get-component file' :component1)
|
|
main1-root' (ths/get-shape file' :main1-root)
|
|
main1-child' (ths/get-shape file' :main1-child)
|
|
copy1-root' (ths/get-shape-by-id file' (:id new-shape))
|
|
copy1-child' (ths/get-shape-by-id file' (first (:shapes copy1-root')))]
|
|
|
|
;; ==== Check
|
|
(t/is (some? main1-root'))
|
|
(t/is (some? main1-child'))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (some? copy1-child'))
|
|
(t/is (ctk/instance-root? copy1-root'))
|
|
(t/is (ctk/instance-of? copy1-root' (:id file') (:id component')))
|
|
(t/is (ctk/is-main-of? main1-root' copy1-root' true))
|
|
(t/is (ctk/is-main-of? main1-child' copy1-child' true))
|
|
(t/is (ctst/parent-of? copy1-root' copy1-child'))))
|
|
|
|
(t/deftest test-instantiate-component-from-lib
|
|
(let [;; ==== Setup
|
|
library (-> (thf/sample-file :library1)
|
|
(tho/add-simple-component :component1
|
|
:main1-root
|
|
:main1-child))
|
|
|
|
file (thf/sample-file :file1)
|
|
|
|
page (thf/current-page file)
|
|
component (thc/get-component library :component1)
|
|
|
|
;; ==== Action
|
|
[new-shape changes]
|
|
(cll/generate-instantiate-component (-> (pcb/empty-changes nil (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
(:objects page)
|
|
(:id library)
|
|
(:id component)
|
|
(gpt/point 1000 1000)
|
|
page
|
|
{(:id file) file
|
|
(:id library) library})
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component' (thc/get-component library :component1)
|
|
main1-root' (ths/get-shape library :main1-root)
|
|
main1-child' (ths/get-shape library :main1-child)
|
|
copy1-root' (ths/get-shape-by-id file' (:id new-shape))
|
|
copy1-child' (ths/get-shape-by-id file' (first (:shapes copy1-root')))]
|
|
|
|
;; ==== Check
|
|
(t/is (some? main1-root'))
|
|
(t/is (some? main1-child'))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (some? copy1-child'))
|
|
(t/is (ctk/instance-root? copy1-root'))
|
|
(t/is (ctk/instance-of? copy1-root' (:id library) (:id component')))
|
|
(t/is (ctk/is-main-of? main1-root' copy1-root' true))
|
|
(t/is (ctk/is-main-of? main1-child' copy1-child' true))
|
|
(t/is (ctst/parent-of? copy1-root' copy1-child'))))
|
|
|
|
(t/deftest test-instantiate-nested-component
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-nested-component :component1
|
|
:main1-root
|
|
:main1-child
|
|
:component2
|
|
:main2-root
|
|
:main2-nested-head))
|
|
|
|
page (thf/current-page file)
|
|
component (thc/get-component file :component1)
|
|
|
|
;; ==== Action
|
|
[new-shape changes]
|
|
(cll/generate-instantiate-component (-> (pcb/empty-changes nil (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
(:objects page)
|
|
(:id file)
|
|
(:id component)
|
|
(gpt/point 1000 1000)
|
|
page
|
|
{(:id file) file})
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component' (thc/get-component file' :component1)
|
|
main1-root' (ths/get-shape file' :main1-root)
|
|
main1-child' (ths/get-shape file' :main1-child)
|
|
copy1-root' (ths/get-shape-by-id file' (:id new-shape))
|
|
copy1-child' (ths/get-shape-by-id file' (first (:shapes copy1-root')))]
|
|
|
|
;; ==== Check
|
|
(t/is (some? main1-root'))
|
|
(t/is (some? main1-child'))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (some? copy1-child'))
|
|
(t/is (ctk/instance-root? copy1-root'))
|
|
(t/is (ctk/instance-of? copy1-root' (:id file') (:id component')))
|
|
(t/is (ctk/is-main-of? main1-root' copy1-root' true))
|
|
(t/is (ctk/is-main-of? main1-child' copy1-child' true))
|
|
(t/is (ctst/parent-of? copy1-root' copy1-child'))))
|
|
|
|
(t/deftest test-instantiate-nested-component-from-lib
|
|
(let [;; ==== Setup
|
|
library (-> (thf/sample-file :file1)
|
|
(tho/add-nested-component :component1
|
|
:main1-root
|
|
:main1-child
|
|
:component2
|
|
:main2-root
|
|
:main2-nested-head))
|
|
|
|
file (thf/sample-file :file1)
|
|
|
|
page (thf/current-page file)
|
|
component (thc/get-component library :component1)
|
|
|
|
;; ==== Action
|
|
[new-shape changes]
|
|
(cll/generate-instantiate-component (-> (pcb/empty-changes nil (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
(:objects page)
|
|
(:id library)
|
|
(:id component)
|
|
(gpt/point 1000 1000)
|
|
page
|
|
{(:id file) file
|
|
(:id library) library})
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
component' (thc/get-component library :component1)
|
|
main1-root' (ths/get-shape library :main1-root)
|
|
main1-child' (ths/get-shape library :main1-child)
|
|
copy1-root' (ths/get-shape-by-id file' (:id new-shape))
|
|
copy1-child' (ths/get-shape-by-id file' (first (:shapes copy1-root')))]
|
|
|
|
;; ==== Check
|
|
(t/is (some? main1-root'))
|
|
(t/is (some? main1-child'))
|
|
(t/is (some? copy1-root'))
|
|
(t/is (some? copy1-child'))
|
|
(t/is (ctk/instance-root? copy1-root'))
|
|
(t/is (ctk/instance-of? copy1-root' (:id library) (:id component')))
|
|
(t/is (ctk/is-main-of? main1-root' copy1-root' true))
|
|
(t/is (ctk/is-main-of? main1-child' copy1-child' true))
|
|
(t/is (ctst/parent-of? copy1-root' copy1-child'))))
|
|
|
|
(t/deftest test-detach-copy
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-simple-component-with-copy :component1
|
|
:main1-root
|
|
:main1-child
|
|
:copy1-root))
|
|
|
|
page (thf/current-page file)
|
|
copy1-root (ths/get-shape file :copy1-root)
|
|
|
|
;; ==== Action
|
|
changes (cll/generate-detach-component (pcb/empty-changes)
|
|
(:id copy1-root)
|
|
(:data file)
|
|
(:id page)
|
|
{(:id file) file})
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
copy1-root' (ths/get-shape file' :copy1-root)]
|
|
|
|
;; ==== Check
|
|
(t/is (some? copy1-root'))
|
|
(t/is (not (ctk/instance-head? copy1-root')))
|
|
(t/is (not (ctk/in-component-copy? copy1-root')))))
|