mirror of
https://github.com/penpot/penpot.git
synced 2026-11-01 15:40:41 +00:00
The variant events had almost no frontend tests, and several switch, paste, token and restore paths never ran. - Variant property edits (AR) and adding a variant (AS), in both runners, through the common generators and the dwv events. - A frontend-only node for the variant management events: transform (AT), combine (AU), rename (AV), rename in layers, removal of empty properties and member errors (AW), and the shortcuts (AX). Each case has copies of the members; direct tests cover the remaining branches. AV and AT confirm F6: the copies' name sync lands in an undo entry of its own (pinned). - Tests for valid-components-for-variants? and valid-variant-switch?. - The WASM variant switch test is registered in the runner; it never ran. - Token apply and remove nodes and case AY. Its undo confirms F55, an empty :applied-tokens map after undo (pinned). The interpreter waits for the token, since apply-token opens no pending work (F54). - A paste-to-root node and case AZ: F17 does not show through paste. The frontend copy helper merges touched groups as the clipboard does. - Switches that carry real geometry, path and text-structure overrides, resized through a transform. - Restoring a component whose page was deleted.
208 lines
8.3 KiB
Clojure
208 lines
8.3 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 SUBSIDIARY SL
|
|
|
|
(ns frontend-tests.data.workspace-variants-test
|
|
"The checks the workspace runs before combining components as variants
|
|
and before a variant switch, and the branches of the variant events that
|
|
the composable cases (`frontend-tests.composable-tests.comp.sync-test`)
|
|
do not reach: a combine on another page, a switch that would nest a
|
|
component in itself, the shortcuts with no variant selected and the
|
|
rename of a plain component."
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.test-helpers.components :as cthc]
|
|
[app.common.test-helpers.compositions :as ctho]
|
|
[app.common.test-helpers.files :as cthf]
|
|
[app.common.test-helpers.ids-map :as cthi]
|
|
[app.common.test-helpers.shapes :as cths]
|
|
[app.common.test-helpers.variants :as cthv]
|
|
[app.common.types.components-list :as ctkl]
|
|
[app.common.uuid :as uuid]
|
|
[app.main.data.common :as dcm]
|
|
[app.main.data.workspace.selection :as dws]
|
|
[app.main.data.workspace.undo :as dwu]
|
|
[app.main.data.workspace.variants :as dwv]
|
|
[beicon.v2.core :as rx]
|
|
[cljs.test :as t :include-macros true]
|
|
[frontend-tests.helpers.mock :as mock]
|
|
[frontend-tests.helpers.state :as ths]
|
|
[potok.v2.core :as ptk]))
|
|
|
|
(t/use-fixtures :each {:before cthi/reset-idmap!})
|
|
|
|
(defn- setup-file
|
|
"A variant set (members :m01 and :m02, each with a child), a copy of :m01,
|
|
two plain components and a copy of the first."
|
|
[]
|
|
(-> (cthf/sample-file :file1)
|
|
(cthv/add-variant-with-child :v01 :c01 :m01 :c02 :m02 :m01-child :m02-child)
|
|
(cthc/instantiate-component :c01 :copy01 :children-labels [:copy01-child])
|
|
(ctho/add-simple-component :plain1 :plain1-root :plain1-child)
|
|
(ctho/add-simple-component :plain2 :plain2-root :plain2-child)
|
|
(cthc/instantiate-component :plain1 :plain1-copy)))
|
|
|
|
(defn- state-of
|
|
[file]
|
|
@(ths/setup-store file))
|
|
|
|
(t/deftest valid-components-for-variants
|
|
(let [file (setup-file)
|
|
state (state-of file)
|
|
page-id (:current-page-id state)
|
|
valid? #(dwv/valid-components-for-variants? state page-id (mapv cthi/id %))]
|
|
(t/testing "two plain main roots"
|
|
(t/is (valid? [:plain1-root :plain2-root])))
|
|
(t/testing "fewer than two distinct components"
|
|
(t/is (not (valid? [:plain1-root])))
|
|
(t/is (not (valid? [:plain1-root :plain1-root]))))
|
|
(t/testing "a variant main"
|
|
(t/is (not (valid? [:plain1-root :m01]))))
|
|
(t/testing "a copy"
|
|
(t/is (not (valid? [:plain1-root :plain1-copy]))))
|
|
(t/testing "a page that is not the current one"
|
|
(t/is (not (dwv/valid-components-for-variants?
|
|
state (uuid/next) [(cthi/id :plain1-root) (cthi/id :plain2-root)]))))))
|
|
|
|
(t/deftest valid-variant-switch
|
|
(let [file (setup-file)
|
|
state (state-of file)
|
|
valid? (fn [label pos val]
|
|
(dwv/valid-variant-switch? state (cths/get-shape file label) pos val))]
|
|
(t/testing "a variant copy head and a value some member holds"
|
|
(t/is (valid? :copy01 0 "Value2"))
|
|
(t/is (valid? :copy01 0 "Value1")))
|
|
(t/testing "a value no member holds"
|
|
(t/is (not (valid? :copy01 0 "Value3"))))
|
|
(t/testing "a position outside the properties"
|
|
(t/is (not (valid? :copy01 1 "Value2")))
|
|
(t/is (not (valid? :copy01 -1 "Value2"))))
|
|
(t/testing "a value that is not a string"
|
|
(t/is (not (valid? :copy01 0 2))))
|
|
(t/testing "not a variant copy head"
|
|
(t/is (not (valid? :m01 0 "Value2")))
|
|
(t/is (not (valid? :copy01-child 0 "Value2")))
|
|
(t/is (not (valid? :plain1-copy 0 "Value2"))))))
|
|
|
|
(defn- all-transactions-committed
|
|
"A `run-store` stopper: the first undo commit after which no transaction
|
|
is pending, for events that commit their transaction asynchronously."
|
|
[store]
|
|
(fn [stream]
|
|
(->> stream
|
|
(rx/filter (ptk/type? ::dwu/commit-undo-transaction))
|
|
(rx/filter #(empty? (get-in @store [:workspace-undo :transactions-pending]))))))
|
|
|
|
(defn- go-to-page
|
|
"Stands in for `dcm/go-to-workspace`, which needs the router: makes
|
|
`page-id` the current page and announces it as initialized."
|
|
[& {:keys [page-id]}]
|
|
(ptk/reify ::go-to-page
|
|
ptk/UpdateEvent
|
|
(update [_ state]
|
|
(assoc state :current-page-id page-id))
|
|
|
|
ptk/WatchEvent
|
|
(watch [_ _ _]
|
|
(rx/of (ptk/data-event :app.main.data.workspace.pages/initialize-page {})))))
|
|
|
|
(t/deftest combine-on-another-page
|
|
(t/async
|
|
done
|
|
(mock/with-mocks
|
|
{dcm/go-to-workspace go-to-page}
|
|
(fn [inner-done]
|
|
(let [file (cthf/sample-file :file1)
|
|
page-1 (cthf/current-page-id file)
|
|
file (-> file
|
|
(cthf/add-sample-page :page2)
|
|
(ctho/add-simple-component :plain1 :plain1-root :plain1-child)
|
|
(ctho/add-simple-component :plain2 :plain2-root :plain2-child)
|
|
(vary-meta assoc :current-page-id page-1))
|
|
store (ths/setup-store file)
|
|
ids [(cthi/id :plain1-root) (cthi/id :plain2-root)]]
|
|
(ths/run-store
|
|
store inner-done
|
|
[(dwv/combine-as-variants ids {:page-id (cthi/id :page2)
|
|
:trigger "plugin:combine-as-variants"})]
|
|
(fn [state]
|
|
(let [data (:data (ths/get-file-from-state state))
|
|
c1 (ctkl/get-component data (cthi/id :plain1))
|
|
c2 (ctkl/get-component data (cthi/id :plain2))]
|
|
(t/is (= (cthi/id :page2) (:current-page-id state)))
|
|
(t/is (some? (:variant-id c1)))
|
|
(t/is (= (:variant-id c1) (:variant-id c2)))))
|
|
(all-transactions-committed store))))
|
|
done)))
|
|
|
|
(t/deftest switch-into-a-nesting-loop
|
|
(t/async
|
|
done
|
|
(let [file (-> (cthf/sample-file :file1)
|
|
(cthv/add-variant :v01 :c01 :m01 :c02 :m02)
|
|
(cthc/instantiate-component :c01 :nested :parent-label :m02))
|
|
store (ths/setup-store file)
|
|
errors (atom 0)
|
|
params (with-meta {:shapes [(cths/get-shape file :nested)] :pos 0 :val "Value2"}
|
|
{:on-error #(swap! errors inc)})]
|
|
(ths/run-store
|
|
store done
|
|
[(dwv/variants-switch params)]
|
|
(fn [state]
|
|
(t/is (= 1 @errors))
|
|
(t/is (= (cthi/id :c01)
|
|
(:component-id (cths/get-shape (ths/get-file-from-state state) :nested)))))))))
|
|
|
|
(defn- object-count
|
|
[file]
|
|
(count (:objects (cthf/current-page file))))
|
|
|
|
(defn- run-selected
|
|
"Run `event` on a store for `file` with the shapes `labels` selected, then
|
|
`check` the resulting file."
|
|
[done file labels event check]
|
|
(ths/run-store
|
|
(ths/setup-store file) done
|
|
[(dws/select-shapes (into (d/ordered-set) (map cthi/id) labels)) event]
|
|
#(check (ths/get-file-from-state %))))
|
|
|
|
(defn- file-with-a-rect
|
|
[]
|
|
(-> (cthf/sample-file :file1)
|
|
(cths/add-sample-shape :rect)))
|
|
|
|
(t/deftest duplicate-shortcut-with-nothing-selected
|
|
(t/async
|
|
done
|
|
(let [file (file-with-a-rect)]
|
|
(run-selected done file [] (dwv/duplicate-or-add-variant)
|
|
#(t/is (= (object-count file) (object-count %)))))))
|
|
|
|
(t/deftest duplicate-shortcut-on-a-plain-shape
|
|
(t/async
|
|
done
|
|
(let [file (file-with-a-rect)]
|
|
(run-selected done file [:rect] (dwv/duplicate-or-add-variant)
|
|
#(t/is (= (inc (object-count file)) (object-count %)))))))
|
|
|
|
(t/deftest create-component-shortcut-on-a-plain-shape
|
|
(t/async
|
|
done
|
|
(run-selected done (file-with-a-rect) [:rect] (dwv/add-component-or-variant)
|
|
#(t/is (= 1 (count (ctkl/components-seq (:data %))))))))
|
|
|
|
(t/deftest rename-of-a-plain-component
|
|
(t/async
|
|
done
|
|
(let [file (-> (cthf/sample-file :file1)
|
|
(ctho/add-simple-component :plain1 :plain1-root :plain1-child))]
|
|
(ths/run-store
|
|
(ths/setup-store file) done
|
|
[(dwv/rename-comp-or-variant-and-main (cthi/id :plain1) "Renamed")]
|
|
(fn [state]
|
|
(let [file' (ths/get-file-from-state state)]
|
|
(t/is (= "Renamed" (:name (ctkl/get-component (:data file') (cthi/id :plain1)))))
|
|
(t/is (= "Renamed" (:name (cths/get-shape file' :plain1-root))))))))))
|