From 97abc1ea18838bf57a6749bde59e2b0da91beb42 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 14 Oct 2026 00:47:28 +0200 Subject: [PATCH] :sparkles: Record a golden master of the component code Before refactoring the component sync code, record the exact files the component tests produce, so a refactor that changes any of them fails. The JVM test common-tests.logic.golden-master-test runs every variant of the composable cases the pure runner runs and every benchmark world. It records the file after each user, undo and redo step (the runner's new :observe option), the final files with the signatures of the undo/redo round trip failures, and each world's file after its timed work. The frontend interpreter records the store's files of every variant of its cases and of the completion contract the same way. app.common.test-helpers.golden-master writes a state as the normalized files in sorted "path value" lines: ids become test labels, or numbers in tree order when unlabelled; grid cells are named after their shape and position; timestamps are left out. So a state is the same in every run whatever ids it draws. Only a digest per state is committed; the full lines go to tmp/golden-master/ and tmp/golden-master-frontend/ (recorded/, and actual/ for a state that differs), so diff -r shows a change. PENPOT_GOLDEN_MASTER=record records them again. Both sides repeat exactly across runs. Dropping :opacity from the attributes sync copies fails the case C variants that edit it. The interpreter's fixture also turns cts/wasm-enabled? off for each composable test and restores it after, as it already restores the store. A test that starts the WASM renderer left the flag on, so in a full frontend run the cases ran on WASM shape proxies, which leave out the attributes that are nil or false, and the frontend golden master differed from a run of the cases alone (:flip-x and :flip-y). AI-assisted-by: claude-opus-5-5 --- .serena/memories/common/testing.md | 18 ++ .../frontend/composable-component-tests.md | 8 + common/dev/bench/component_sync.clj | 33 +- .../test_helpers/composable/comp/runner.cljc | 44 +-- .../common/test_helpers/golden_master.cljc | 296 ++++++++++++++++++ .../src/app/common/test_helpers/ids_map.cljc | 5 + .../test/common_tests/logic/golden_master.edn | 189 +++++++++++ .../common_tests/logic/golden_master_test.clj | 139 ++++++++ .../composable_tests/golden_master.edn | 221 +++++++++++++ .../composable_tests/interpreter.cljs | 93 +++++- 10 files changed, 1009 insertions(+), 37 deletions(-) create mode 100644 common/src/app/common/test_helpers/golden_master.cljc create mode 100644 common/test/common_tests/logic/golden_master.edn create mode 100644 common/test/common_tests/logic/golden_master_test.clj create mode 100644 frontend/test/frontend_tests/composable_tests/golden_master.edn diff --git a/.serena/memories/common/testing.md b/.serena/memories/common/testing.md index 06f729176b..c1172ad872 100644 --- a/.serena/memories/common/testing.md +++ b/.serena/memories/common/testing.md @@ -67,6 +67,24 @@ rewrites the baseline (only on purpose, saying why). It takes about 4 minutes. E touches sync, swap or change application runs it and quotes the table in its message. The lower quantile is compared because the mean moves with background load (devenv watchers) and GC. +## Golden master + +`common-tests.logic.golden-master-test` (JVM only) records the exact files the pure runner's +composable cases and the benchmark worlds produce: per variant, the state after each user, undo +and redo step (the runner's `:observe` option), then the final files with the round trip's +failure signatures. The frontend interpreter records its own for `comp.sync-test` and the +completion contract. Shared code: `app.common.test-helpers.golden-master` (alias `thgm`): ids +named by test label or `:unlabelled/` in tree order, grid cells `:cell/..`, +timestamps `:inst`, written as sorted `path value` lines. Only digests are committed +(`golden_master.edn` next to each test); full lines go to `tmp/golden-master/` and +`tmp/golden-master-frontend/` (`recorded/`, and `actual/` per differing state): read a change with +`diff -r tmp/golden-master/recorded tmp/golden-master/actual`. `recorded/` exists only on the +machine that recorded; elsewhere re-record at the parent commit to get it. A refactor must keep +the golden master; a behavior change records it again on purpose +(`PENPOT_GOLDEN_MASTER=record`, from `common/` for the JVM test, from `frontend/` for +`node target/tests/test.js --focus `; the frontend file is updated per namespace) and says +why in the commit. A new shared case goes into the test's `case-fns` and is recorded. + ## Geometry setup caution For geometry-sensitive tests, read `mem:common/geometry-invariants` before positioning shapes. Use geometry-preserving helpers or production change helpers rather than direct single-field edits. diff --git a/.serena/memories/frontend/composable-component-tests.md b/.serena/memories/frontend/composable-component-tests.md index a7fb840c71..5d14ce8456 100644 --- a/.serena/memories/frontend/composable-component-tests.md +++ b/.serena/memories/frontend/composable-component-tests.md @@ -239,6 +239,9 @@ synchronously); an async hop without a pending task makes steps resolve early. T `frontend-tests.composable-tests.completion-contract-test` (slowed-down sync via a mocked `dwl/sync-file`), `frontend-tests.data.workspace-sync-barrier-test`. Re-reads `:file` each step so the shared accessors keep working. +WASM-SHAPE IMMUNITY: a test that starts the WASM renderer leaves `cts/wasm-enabled?` on, which +makes every later shape a proxy that leaves out nil and false attributes; `fixture` turns it off +for the composable tests and restores it after, so they run on records in any order. STORE-SWAP IMMUNITY: other test namespaces `set!` `st/state`/`st/stream` and never restore, while the `app.main.refs` lenses stay bound to the ORIGINAL atoms — propagation then dies silently. The interpreter captures the atoms at namespace-load time and re-`set!`s them per variant. @@ -248,6 +251,11 @@ Running (frontend): `cd frontend && pnpm run build:test`, then `node target/tests/test.js --focus frontend-tests.composable-tests.comp.sync-test` (var-level focus for one case). +**Golden master:** `check` records the store's files after each user, frontend-only, undo +and redo step and at the end of each variant, keyed by the test var's name, and compares them +with `golden_master.edn` next to the interpreter (see `mem:common/testing`, "Golden master"). +A new case fails until recorded with `PENPOT_GOLDEN_MASTER=record`. + **Fidelity warning:** the harness drives a MINIMALLY-ASSEMBLED app: no file loading, no persistence, no viewport. Edit-reacting subscriptions come from the shared events above; a NEW edit-reacting subscription belongs inside `initialize-edit-watchers` (or diff --git a/common/dev/bench/component_sync.clj b/common/dev/bench/component_sync.clj index 29c46479b1..142520c081 100644 --- a/common/dev/bench/component_sync.clj +++ b/common/dev/bench/component_sync.clj @@ -82,7 +82,8 @@ ;; A world is `{:key :describe :run :reds}`; `run` is the timed work, a ;; function of no arguments returning `[file passes]`, and `reds` how many ;; rects the resulting file must have red, so a world that synced nothing -;; fails instead of timing nothing. +;; fails instead of timing nothing. A world whose file uses libraries lists +;; them under `:libraries`. (defn- red-rects [file] @@ -201,20 +202,28 @@ libraries (:id file))] [(apply-changes file changes) 1]))] - {:key :library-update-into-copies - :describe "a library main changed; a file with 500 copies updates" - :run update - :reds 500})) + {:key :library-update-into-copies + :describe "a library main changed; a file with 500 copies updates" + :run update + :reds 500 + :libraries [library]})) + +(defn world-builders + "One function of no arguments per world, building it. Each world builds + its file with test labels, so the golden master builds one world at a + time and reads its labels before the next one replaces them." + [] + [#(main-edit-into-copies 10) + #(main-edit-into-copies 100) + #(main-edit-into-copies 1000) + deepest-edit-through-three-levels + edit-through-a-chain-of-dependents + variant-switch-into-copies + library-update-into-copies]) (defn- worlds [] - [(main-edit-into-copies 10) - (main-edit-into-copies 100) - (main-edit-into-copies 1000) - (deepest-edit-through-three-levels) - (edit-through-a-chain-of-dependents) - (variant-switch-into-copies) - (library-update-into-copies)]) + (mapv #(%) (world-builders))) ;; ---- Measuring diff --git a/common/src/app/common/test_helpers/composable/comp/runner.cljc b/common/src/app/common/test_helpers/composable/comp/runner.cljc index 5937a957ac..35ca94ca55 100644 --- a/common/src/app/common/test_helpers/composable/comp/runner.cljc +++ b/common/src/app/common/test_helpers/composable/comp/runner.cljc @@ -346,27 +346,31 @@ (run-op (tm/choice-of op) opts)) :else - (let [kind (op-kind op)] - (case kind - :undo - (let [situation (run-undo situation op)] - ;; never undo past the state a case's own undo went back to - (cond-> situation - (and (:undo-check? opts) - (< (undo-depth situation) (:depth (uc/baseline situation)))) - (mark-baseline))) + (let [kind (op-kind op) + situation (case kind + :undo + (let [situation (run-undo situation op)] + ;; never undo past the state a case's own undo went back to + (cond-> situation + (and (:undo-check? opts) + (< (undo-depth situation) (:depth (uc/baseline situation)))) + (mark-baseline))) - :redo - (run-redo situation op) + :redo + (run-redo situation op) - :frontend-only - (throw (ex-info (str "The pure runner cannot run " (pr-str (type op)) - ": its production result needs frontend code. " - "Run the case through the frontend interpreter.") - {:type ::frontend-only - :op op})) + :frontend-only + (throw (ex-info (str "The pure runner cannot run " (pr-str (type op)) + ": its production result needs frontend code. " + "Run the case through the frontend interpreter.") + {:type ::frontend-only + :op op})) - (run-node situation op kind opts))))) + (run-node situation op kind opts))] + (when-let [observe (:observe opts)] + (when (contains? #{:user :undo :redo} kind) + (observe situation))) + situation))) (defn run-variant "Run one concrete (already enumerated) variant: build a fresh situation with @@ -376,7 +380,9 @@ - `:undo-check?` (default true, false when the case map turns the check off) runs the undo/redo round trip of `app.common.test-helpers.composable.comp.undo-check`; its failures are - recorded in the situation for `uc/check!`." + recorded in the situation for `uc/check!`; + - `:observe`, a function called with the situation after each user, + undo and redo operation settles (the golden master records them)." ([case-map] (run-variant case-map {})) ([{:keys [setup operation] :as case-map} opts] (let [opts (merge default-opts diff --git a/common/src/app/common/test_helpers/golden_master.cljc b/common/src/app/common/test_helpers/golden_master.cljc new file mode 100644 index 0000000000..098fb368e3 --- /dev/null +++ b/common/src/app/common/test_helpers/golden_master.cljc @@ -0,0 +1,296 @@ +;; 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 app.common.test-helpers.golden-master + "Golden masters of the component code: the exact files a test produces, + recorded once and compared on every run. + + A state is a list of files, normalized (`thn/normalize-file`) and + written as sorted lines `path value`, with every id replaced by its test + label, or by `:unlabelled/`, numbered in tree order (pages in order, + each from its root; components by label, each from its main), and each + grid cell by `:cell/..`. So the lines are the same + whatever ids a run draws, and timestamps are left out. + + A group (a case, a benchmark world) is a list of variants, each + `{:transcript :states [lines ...]}`. An EDN file keeps a short digest + per state; the full lines go to a directory outside git: `recorded/` + when recording, `actual/` for each state that differs, so + `diff -r /recorded /actual` shows what changed." + (:require + #?(:clj [clojure.edn :as edn]) + #?(:clj [clojure.java.io :as io]) + #?(:cljs [cljs.reader :as reader]) + [app.common.test-helpers.composable.core :as tm] + [app.common.test-helpers.ids-map :as thi] + [app.common.test-helpers.normalize :as thn] + [app.common.time :as ct] + [app.common.uuid :as uuid] + [clojure.string :as str] + [clojure.test :as t] + [clojure.walk :as walk]) + #?(:clj + (:import + java.security.MessageDigest))) + +#?(:cljs + (defn- node-module + "The Node built-in module `name`, in ESM and CommonJS builds alike." + [name] + (.getBuiltinModule js/process (str "node:" name)))) + +;; ---- Names + +(defn- tree-ids + "The ids of `root-id` and of the shapes under it in `objects`, depth first + in `:shapes` order." + [objects root-id] + (loop [stack [root-id] + ids []] + (if (empty? stack) + ids + (let [id (peek stack)] + (recur (into (pop stack) (reverse (get-in objects [id :shapes]))) + (conj ids id)))))) + +(defn- label-key + [label] + (if (keyword? label) (str label) (pr-str label))) + +(defn- test-labels + "The test label of each labelled id; an id with several labels takes the + first one in name order." + [] + (reduce-kv (fn [labels label id] + (let [current (get labels id)] + (if (and current (neg? (compare (label-key current) (label-key label)))) + labels + (assoc labels id label)))) + {} + (thi/labels))) + +(defn- sorted-components + [file labels] + (->> (vals (get-in file [:data :components])) + (sort-by (fn [{:keys [id name path]}] + [(some-> (get labels id) label-key) path name])))) + +(defn- ordered-shapes + "The shapes of `file` in a fixed order: each page's from its root, then, + for each deleted component, its shapes from its main." + [file labels] + (let [data (:data file)] + (concat + (mapcat (fn [page-id] + (let [objects (get-in data [:pages-index page-id :objects])] + (keep objects (tree-ids objects uuid/zero)))) + (:pages data)) + (mapcat (fn [{:keys [main-instance-id objects]}] + (when objects + (keep objects (tree-ids objects main-instance-id)))) + (sorted-components file labels))))) + +(defn- file-ids + "The ids of `file` in a fixed order: the file, its pages, its shapes (see + `ordered-shapes`), then each component and its main." + [file labels] + (concat + [(:id file)] + (get-in file [:data :pages]) + (map :id (ordered-shapes file labels)) + (mapcat (juxt :id :main-instance-id) (sorted-components file labels)))) + +(defn- cell-names + "A name for each grid cell of the shapes in `files`, after the first shape + that holds it in the order of `ordered-shapes` (copies share their main's + cell ids): `:cell/..`." + [files labels names] + (reduce (fn [cells {:keys [id layout-grid-cells]}] + (reduce (fn [cells {cell-id :id :keys [row column]}] + (cond-> cells + (not (contains? cells cell-id)) + (assoc cell-id (keyword "cell" (str (name (get names id)) "." row "." column))))) + cells + (sort-by (juxt :row :column) (vals layout-grid-cells)))) + {} + (mapcat #(ordered-shapes % labels) files))) + +(defn id-names + "A name for every id in `files`: its test label, else `:unlabelled/` in + the order `file-ids` gives, and a name for each grid cell." + [files] + (let [labels (test-labels) + names (reduce (fn [names id] + (cond + (contains? names id) names + (contains? labels id) (assoc names id (get labels id)) + :else (assoc names id (keyword "unlabelled" + (str (count (remove labels (keys names)))))))) + {} + (mapcat #(file-ids % labels) files))] + (merge (cell-names files labels names) names))) + +(defn- rename-ids + "`value` with every uuid named by `names` and every timestamp `:inst`; an + id they miss (one that no tree reaches, such as a reference to a deleted + shape) is `:unreached`." + [value names] + (walk/postwalk #(cond + (uuid? %) (get names % :unreached) + (ct/inst? %) :inst + :else %) + value)) + +(def ^:private uuid-re + #"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") + +(defn- rename-printed-ids + "The string `s` with each id printed in it named by `names`." + [s names] + (str/replace s uuid-re #(name (get names (uuid/uuid %) :unreached)))) + +(defn transcript + "The operations of `situation`, with each id named by `names` and each + function printed as `#fn`." + [situation names] + (-> (tm/describe-applied situation) + (rename-printed-ids names) + (str/replace #"#uuid \"([^\"]+)\"" "$1") + (str/replace #"#object\[[^\]]*\]" "#fn"))) + +;; ---- Lines + +(defn- leaf? + [value] + (not (and (coll? value) (seq value)))) + +(defn- entries + "The children of a collection as `[key value]` pairs: a map's entries in + key order, a set's elements in printed order, a sequence's by index." + [value] + (cond + (map? value) (sort-by (comp pr-str key) value) + (set? value) (map-indexed vector (sort-by pr-str value)) + :else (map-indexed vector value))) + +(defn- lines + "The lines `path value` of `value`, one per leaf. An id printed inside a + leaf (a token theme's id in the tokens library) is named by `names`." + [value names] + (let [out (volatile! (transient []))] + (letfn [(walk [path value] + (if (leaf? value) + (vswap! out conj! (str (pr-str path) " " (rename-printed-ids (pr-str value) names))) + (doseq [[k v] (entries value)] + (walk (conj path k) v))))] + (walk [] value)) + (persistent! @out))) + +(defn state-lines + "The lines of a state: `files` normalized with their ids named, and + `extra`, named too. `opts` go to `thn/normalize-file`." + ([files extra] (state-lines files extra {})) + ([files extra opts] + (let [names (id-names files)] + (lines (rename-ids {:files (into {} (map (fn [file] + [(get names (:id file)) (thn/normalize-file file opts)])) + files) + :extra extra} + names) + names)))) + +(defn digest + "A short digest of `lines`." + [lines] + (let [text (str (str/join "\n" lines) "\n")] + #?(:clj + (let [md (MessageDigest/getInstance "SHA-256")] + (subs (apply str (map #(format "%02x" %) (.digest md (.getBytes ^String text "UTF-8")))) + 0 16)) + :cljs + (let [crypto (node-module "crypto")] + (subs (-> (.createHash crypto "sha256") (.update text "utf8") (.digest "hex")) 0 16))))) + +;; ---- Files + +(defn- state-path + [dir kind group variant state] + (let [pad (fn [n width] (let [s (str n)] (str (apply str (repeat (- width (count s)) "0")) s)))] + (str dir "/" kind "/" (name group) "/" (pad variant 3) "-" (pad state 2) ".txt"))) + +(defn- write-text! + [path text] + #?(:clj + (let [file (io/file path)] + (io/make-parents file) + (spit file text)) + :cljs + (let [fs (node-module "fs") + node-path (node-module "path")] + (.mkdirSync fs (.dirname node-path path) #js {:recursive true}) + (.writeFileSync fs path text)))) + +(defn- write-lines! + [path lines] + (write-text! path (str (str/join "\n" lines) "\n"))) + +(defn read-digests + "The digests recorded in the EDN file at `path`, or nil when there is + none." + [path] + #?(:clj + (let [file (io/file path)] + (when (.exists file) + (edn/read-string (slurp file)))) + :cljs + (let [fs (node-module "fs")] + (when (.existsSync fs path) + (reader/read-string (.readFileSync fs path "utf8")))))) + +(defn write-digests! + "Write `digests`, a map of group keys to variants' digests, to the EDN + file at `path`." + [path digests] + (write-text! path (str ";; Golden master digests, written by the golden master test.\n" + "{" + (str/join "\n " (for [[group variants] (sort-by (comp str key) digests)] + (str (pr-str group) "\n [" + (str/join "\n " (map pr-str variants)) + "]"))) + "}\n"))) + +(defn- variant-digests + [{:keys [transcript states]}] + {:transcript transcript + :states (mapv digest states)}) + +(defn record-group! + "Write the lines of each state of `variants` under `/recorded/` and + return their digests." + [dir group variants] + (doseq [[i {:keys [transcript states]}] (map-indexed vector variants) + [j lines] (map-indexed vector states)] + (write-lines! (state-path dir "recorded" group i j) (cons transcript lines))) + (mapv variant-digests variants)) + +(defn compare-group! + "Assert that `variants` match `recorded`, the digests of `group`, writing + the lines of each state that differs under `/actual/`." + [dir group variants recorded] + (t/testing (str "golden master of " (name group)) + (t/is (some? recorded) "the group has no recorded golden master") + (t/is (= (count recorded) (count variants)) "the number of variants changed") + (doseq [[i variant expected] (map vector (range) variants recorded) + :let [{:keys [transcript states]} variant + actual (variant-digests variant)]] + (t/testing (str "variant " i ":\n " transcript) + (t/is (= (:transcript expected) transcript) "the variant's operations changed") + (t/is (= (count (:states expected)) (count states)) "the number of states changed") + (doseq [[j lines want got] (map vector (range) states (:states expected) (:states actual))] + (let [path (state-path dir "actual" group i j)] + (when (not= want got) + (write-lines! path (cons transcript lines))) + (t/is (= want got) (str "state " j " differs: " path)))))))) diff --git a/common/src/app/common/test_helpers/ids_map.cljc b/common/src/app/common/test_helpers/ids_map.cljc index 9648b42c37..5843e68fe6 100644 --- a/common/src/app/common/test_helpers/ids_map.cljc +++ b/common/src/app/common/test_helpers/ids_map.cljc @@ -35,6 +35,11 @@ [label] (get @idmap label)) +(defn labels + "The current map of labels to ids." + [] + @idmap) + (defn test-fixture ;; Ensure that each test starts with a clean ids map [f] diff --git a/common/test/common_tests/logic/golden_master.edn b/common/test/common_tests/logic/golden_master.edn new file mode 100644 index 0000000000..dffc76d48f --- /dev/null +++ b/common/test/common_tests/logic/golden_master.edn @@ -0,0 +1,189 @@ +;; Golden master digests, written by the golden master test. +{:aa + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n swap-shape {:target #fn, :to \"s2\", :keep-touched? false}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["9019918a02196b8f" "e4acd752d50780bd" "eeff610a27633347" "afa25c45e4855fce"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n swap-shape {:target #fn, :to \"s2\", :keep-touched? false}\n one-of -> skip", :states ["9019918a02196b8f" "e4acd752d50780bd" "e9668e3ed663b3b0"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["9019918a02196b8f" "c4e06e2eab16398f" "9b149917696880e1"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> skip\n one-of -> skip", :states ["9019918a02196b8f" "b5373f3c8cae4fc1"]}] + :ab + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :opacity, :value 0.5}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n reset-overrides {:target #fn, :reset 3}", :states ["2ec7fb83e8335e83" "6a105b37f6ebf73c" "8ec10656f376e332" "4ba9485ff33b0f2c"]}] + :ac + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 3}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :opacity, :value 0.5}\n switch-variant {:target-component sync-vset-v1-component}\n test\n switch-variant {:target-component sync-vset-v2-component}", :states ["9f9ac61ce3c54295" "5bd9620c6fc0cf6e" "387d74ba1c75e52f" "62a55a068ebd6043"]}] + :ad + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["9835a328e680007d" "8cc31cfc15b28449" "40c27ac7ca18d972"]}] + :ae + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["a3cb16fb335bc929" "c59b7ba151b736fb" "ccd586f1f2b263e4" "07eb2229667eeb92"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s1\", :id sync-s1-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n duplicate {:target #fn, :new-head 5}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["a3cb16fb335bc929" "d291c9ca9a187b1b" "99bb6214c05d575b" "0694d4feab3cb633"]}] + :af + [{:transcript "swap-shape {:target :copy-child, :to :other, :keep-touched? false}\n move-to-cell {:board :main-root, :child :main-child, :row 1, :column 3}", :states ["a3bca1c5fd1b9b29" "8a7fa3fde8815d35" "1c786eab89f462da"]} + {:transcript "one-of -> skip\n move-to-cell {:board :main-root, :child :main-child, :row 1, :column 3}", :states ["7f1f0be7424c543f" "7c9214e430ebb4e8"]}] + :ag + [{:transcript "move-child {:target :sub1, :parent :row-root, :to-index 3}", :states ["7a572aaeec3d11c7" "4ef6a524e41aa81f"]}] + :ah + [{:transcript "one-of -> recorded-choice\n remove-child {:target :copy-sub1}", :states ["3043434871927bf0" "c5acd77993218759"]} + {:transcript "one-of -> recorded-choice\n remove-child {:target :copy-sub3}", :states ["fdddae12ff7dd7bc" "7efeb83144959be0"]} + {:transcript "one-of -> skip", :states ["4f8193bba8dbfb0d"]}] + :ak + [{:transcript "swap-shape {:target :copy-child, :to :other, :keep-touched? false}\n move-to-cell {:board :copy-root, :child :copy-child, :row 1, :column 3}\n update-main {:target :copy-root, :updated grid-copy}", :states ["a3bca1c5fd1b9b29" "246adb9d062e7222" "c4587bbdc8952e96" "400ce49b85daec77"]} + {:transcript "one-of -> skip\n move-to-cell {:board :copy-root, :child :copy-child, :row 1, :column 3}\n update-main {:target :copy-root, :updated grid-copy}", :states ["8aad596633c254fd" "7f1f0be7424c543f" "7c9214e430ebb4e8"]}] + :al + [{:transcript "change-property {:target :copy-root, :property :name, :value \"Renamed\"}\n change-property {:target :copy-instance, :property :name, :value \"Renamed child\"}\n update-main {:target :copy-root, :updated copy-root}", :states ["0166c98332ed23a7" "6c0c864aa286702f" "af3a00259b74b965" "6598d0729b91c5b3"]} + {:transcript "change-property {:target :copy-root, :property :name, :value \"Renamed\"}\n one-of -> skip\n update-main {:target :copy-root, :updated copy-root}", :states ["0166c98332ed23a7" "e2849db0c0174bfc" "c307f8e2c66e8760"]}] + :am + [{:transcript "swap-shape {:target :copy-child, :to :other, :keep-touched? false}\n update-main {:target :copy-root, :updated grouped-copy}", :states ["97535386c5e6b064" "ae99b169cd56a48c" "40447fef13f32e5a"]}] + :an + [{:transcript "change-property {:target :copy-instance, :property :margin, :value 8}\n change-property {:target :main-instance, :property :margin, :value 20}", :states ["4087468201a18ebc" "04328fe58e252ee9" "85db26a4ea6a899c"]} + {:transcript "change-property {:target :copy-instance, :property :margin, :value 8}\n reset-overrides {:target :copy-root, :reset copy-root}", :states ["4087468201a18ebc" "cb5b3ab586333d10" "054cd426071de8e3"]} + {:transcript "change-property {:target :copy-instance, :property :margin, :value 8}\n update-main {:target :copy-root, :updated copy-root}", :states ["4087468201a18ebc" "6b82a7e5bb516fc5" "8d389cd790e5cfb3"]}] + :ao + [{:transcript "nest-copy {:copy :loose, :into :main-root, :cell [1 3]}", :states ["6e7144142468b3ea" "5e11927c1505e3f6"]}] + :ap + [{:transcript "sync-from-library {:library-id library}", :states ["3550b8df58ff0c95" "3872af2b94d47dea"]}] + :aq + [{:transcript "change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["c87df8e13ef41b54" "631393b12f66fee5" "1cb324f06bacf112"]} + {:transcript "one-of -> skip\n change-property {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["6852d4f5a04f8ac3" "2d44cd9d2b7bb668"]}] + :ar + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n edit-variant-property {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n edit-variant-property {:set-name \"vset\", :edit :rename, :params {:pos 0, :name \"Color\"}}\n test\n switch-variant {:target-component sync-vset-v1-component}", :states ["1247c1fd53a5de3f" "145adc849fab1a7f" "07f7c6583abf0644" "681649d320320925" "d39450f272d671fc"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n edit-variant-property {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n edit-variant-property {:set-name \"vset\", :edit :set-value, :params {:member \"a\", :pos 0, :value \"a2\"}}\n test\n switch-variant {:target-component sync-vset-v1-component}", :states ["1247c1fd53a5de3f" "145adc849fab1a7f" "2449acda42e34e37" "2a19c0dc506f831c" "bed4b004d959f892"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n edit-variant-property {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n edit-variant-property {:set-name \"vset\", :edit :reorder, :params {:from 1, :to 0}}\n test\n switch-variant {:target-component sync-vset-v1-component}", :states ["1247c1fd53a5de3f" "145adc849fab1a7f" "fb07de11459bfd4a" "336e2d434593f2f7" "c587b6e374b11811"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n edit-variant-property {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n edit-variant-property {:set-name \"vset\", :edit :remove, :params {:pos 1}}\n test\n switch-variant {:target-component sync-vset-v1-component}", :states ["1247c1fd53a5de3f" "145adc849fab1a7f" "1247c1fd53a5de3f" "45d0fe0a073fbada" "9a8e3d09e48af9fe"]}] + :as + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n add-variant {:set-name \"vset\", :member \"a\", :component-id 7}\n test\n switch-variant {:target-component 7}", :states ["1247c1fd53a5de3f" "7e0e395e3d0660a0" "1dfa6bfdd7b29e26" "fa90e52391b5ae7f"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n add-variant {:set-name \"vset\", :member \"b\", :component-id 7}\n test\n switch-variant {:target-component 7}", :states ["1247c1fd53a5de3f" "f4146efd3687f0bf" "02f3dd834cc6a5cb" "fb72fa0de22456bd"]}] + :ay + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n add-tokens {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n apply-token {:target #fn, :token-name \"radius.s\", :value 10}\n apply-token {:target #fn, :token-name \"radius.l\", :value 30}\n test\n unapply-token {:target #fn, :token-name \"radius.l\"}", :states ["59efd69700884e48" "abf5f79fd6265aff" "39b3757cf3962625" "90094c5af982b268"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n add-tokens {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n apply-token {:target #fn, :token-name \"radius.s\", :value 10}\n apply-token {:target #fn, :token-name \"radius.l\", :value 30}\n test\n one-of -> skip", :states ["59efd69700884e48" "abf5f79fd6265aff" "35f26a160913fed7"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n add-tokens {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n apply-token {:target #fn, :token-name \"radius.l\", :value 30}\n test\n unapply-token {:target #fn, :token-name \"radius.l\"}", :states ["b59fbe5fc9ca6e6b" "6f8d6e70db24f3ee" "23156b8978646a6a"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n add-tokens {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n apply-token {:target #fn, :token-name \"radius.l\", :value 30}\n test\n one-of -> skip", :states ["b59fbe5fc9ca6e6b" "959ff508596afeae"]}] + :az + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n paste-to-root {:target #fn, :new-head 5}\n test\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}", :states ["c8c845596f55aa86" "1d1b26cfc6a035e4" "cdcb72926d45d3db" "c6ccfcd10b8e16a3"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n paste-to-root {:target #fn, :new-head 3}\n test\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}", :states ["c8c845596f55aa86" "a6a97a3d3298a63a" "a47933c7e373dfd7" "75123b44e98d2e2c"]}] + :b + [{:transcript "change-property {:target :copy-child, :property :fills, :value \"#00ff00\"}\n change-property {:target :main-child, :property :fills, :value \"#ff0000\"}", :states ["5df508d97af5247a" "b2f66a15e5ff4097" "4b24ab56135742f0"]}] + :ba + [{:transcript "edit-text {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n edit-text {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> recorded-choice\n reset-overrides {:target :copy-root, :reset copy-root}", :states ["68abaaef59a6d2ca" "c1ddfe0dc3988210" "6fdf08d7be36c783" "4070583c39b2ea8d"]} + {:transcript "edit-text {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n edit-text {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> recorded-choice\n update-main {:target :copy-root, :updated copy-root}", :states ["68abaaef59a6d2ca" "c1ddfe0dc3988210" "e6b25a45c62065cc" "523c931dc1c0532a"]} + {:transcript "edit-text {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n edit-text {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> skip", :states ["68abaaef59a6d2ca" "c1ddfe0dc3988210" "a4a8b4715dbaee4b"]} + {:transcript "edit-text {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n edit-text {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> recorded-choice\n reset-overrides {:target :copy-root, :reset copy-root}", :states ["68abaaef59a6d2ca" "44314da0d19445fd" "c352f47573457d52" "e78d1424d71e9cea"]} + {:transcript "edit-text {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n edit-text {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> recorded-choice\n update-main {:target :copy-root, :updated copy-root}", :states ["68abaaef59a6d2ca" "44314da0d19445fd" "ca2a2b2037e4e291" "8103e4a9c41bc5dc"]} + {:transcript "edit-text {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n edit-text {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> skip", :states ["68abaaef59a6d2ca" "44314da0d19445fd" "64f2927e9a353a05"]} + {:transcript "edit-text {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n edit-text {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> recorded-choice\n reset-overrides {:target :copy-root, :reset copy-root}", :states ["6ee24a0ab7d40d4e" "26063961adf48e87" "6fdf08d7be36c783" "4070583c39b2ea8d"]} + {:transcript "edit-text {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n edit-text {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> recorded-choice\n update-main {:target :copy-root, :updated copy-root}", :states ["6ee24a0ab7d40d4e" "26063961adf48e87" "7fe95a2dfd32e79b" "c1e54744d1d3f83b"]} + {:transcript "edit-text {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n edit-text {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> skip", :states ["6ee24a0ab7d40d4e" "26063961adf48e87" "4944dbbc5cba9e76"]} + {:transcript "edit-text {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n edit-text {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> recorded-choice\n reset-overrides {:target :copy-root, :reset copy-root}", :states ["6ee24a0ab7d40d4e" "91928fc2e449bd94" "c352f47573457d52" "e78d1424d71e9cea"]} + {:transcript "edit-text {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n edit-text {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> recorded-choice\n update-main {:target :copy-root, :updated copy-root}", :states ["6ee24a0ab7d40d4e" "91928fc2e449bd94" "1b53cfa51c185e11" "8957f0d3a3d4bcf6"]} + {:transcript "edit-text {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n edit-text {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> skip", :states ["6ee24a0ab7d40d4e" "91928fc2e449bd94" "18f354097caba14c"]}] + :c + [{:transcript "change-property {:target :main-child, :property :fills, :value \"#ff0000\"}", :states ["17b5ce28aeffa62e" "8f31b06c3ab1921b"]} + {:transcript "change-property {:target :main-child, :property :opacity, :value 0.5}", :states ["28904e69a7716b53" "51b5ba6124357c30"]}] + :d + [{:transcript "add-child {:parent :main-root, :new-label :main-child-2}", :states ["0268b3f1dd58ad28" "3b6ab11a6877a649"]}] + :deepest-edit-through-three-levels + [{:transcript "deepest-edit-through-three-levels", :states ["8b9f150407d643b9"]}] + :e + [{:transcript "remove-child {:target :main-child2}", :states ["d66566a75ba82ada" "7f3871ca139c0a97"]}] + :edit-through-a-chain-of-dependents + [{:transcript "edit-through-a-chain-of-dependents", :states ["9ee47520f6b1a0e9"]}] + :f + [{:transcript "move-child {:target :main-child1, :parent :main-root, :to-index 2}", :states ["4ca7ef4736e23ba7" "8082d4caea054434"]}] + :h + [{:transcript "sync-from-library {:library-id library}", :states ["ac5b8031232b4f6a" "7448e7e0603e54be"]}] + :i + [{:transcript "change-property {:target :main-child, :property :fills, :value \"#ff0000\"}\n test\n undo {:undone 2}", :states ["17b5ce28aeffa62e" "e60c9f0fd46b2310" "de1960e98c3646c7"]}] + :k + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["0072b33980dae904" "906c1b936c948e9c" "0276b437ba4eccab" "0276b437ba4eccab" "906c1b936c948e9c" "558090631bccd8ad"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["0072b33980dae904" "906c1b936c948e9c" "0276b437ba4eccab" "906c1b936c948e9c" "558090631bccd8ad"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["0072b33980dae904" "b52f7d8d0007fa57" "b52f7d8d0007fa57" "0072b33980dae904" "bd57e8070d829bdf"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> skip\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["0072b33980dae904" "b52f7d8d0007fa57" "0072b33980dae904" "bd57e8070d829bdf"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["906c1b936c948e9c" "0276b437ba4eccab" "0276b437ba4eccab" "906c1b936c948e9c" "558090631bccd8ad"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["906c1b936c948e9c" "0276b437ba4eccab" "906c1b936c948e9c" "558090631bccd8ad"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["73f915d8775a896e" "73f915d8775a896e" "ccae035ad8afa204" "d21121d9ba6ee531"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n one-of -> skip\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["73f915d8775a896e" "ccae035ad8afa204" "d21121d9ba6ee531"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["a5b1e4b00086c891" "ecb9b3d70125fdd1" "e887c3a7912b40dd" "e887c3a7912b40dd" "ecb9b3d70125fdd1" "d8f660aeaea20783"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["a5b1e4b00086c891" "ecb9b3d70125fdd1" "e887c3a7912b40dd" "ecb9b3d70125fdd1" "d8f660aeaea20783"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["a5b1e4b00086c891" "c074f5ca13faf6fb" "c074f5ca13faf6fb" "a5b1e4b00086c891" "f09bed0fa67d711c"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> skip\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["a5b1e4b00086c891" "c074f5ca13faf6fb" "a5b1e4b00086c891" "f09bed0fa67d711c"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["612744078dfe9561" "fdbbb090a4bd00fe" "fdbbb090a4bd00fe" "612744078dfe9561" "46c7e6eae04abeab"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["612744078dfe9561" "fdbbb090a4bd00fe" "612744078dfe9561" "46c7e6eae04abeab"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["d088ff7f51fed83d" "d088ff7f51fed83d" "5d56e812befee8fb" "a5b7c373319bd86d"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n one-of -> skip\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["d088ff7f51fed83d" "5d56e812befee8fb" "a5b7c373319bd86d"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["ab0a68e1af334a44" "2797b111c7f0e07b" "7dbb09769be6ddee" "7dbb09769be6ddee" "2797b111c7f0e07b" "4a99d39170cb6748"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["ab0a68e1af334a44" "2797b111c7f0e07b" "7dbb09769be6ddee" "2797b111c7f0e07b" "4a99d39170cb6748"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["ab0a68e1af334a44" "59a1778135cecc4a" "59a1778135cecc4a" "ab0a68e1af334a44" "987979e4d37001b6"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> skip\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["ab0a68e1af334a44" "59a1778135cecc4a" "ab0a68e1af334a44" "987979e4d37001b6"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["9c6887a1bdd924b4" "a90f2bc7410e7ac3" "a90f2bc7410e7ac3" "9c6887a1bdd924b4" "639ad982e1def09b"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["9c6887a1bdd924b4" "a90f2bc7410e7ac3" "9c6887a1bdd924b4" "639ad982e1def09b"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["cdb64413ea7e8db5" "cdb64413ea7e8db5" "12bbcbb8f72e4c57" "a6b198531797fe41"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n one-of -> skip\n one-of -> skip\n test\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n test\n reset-overrides {:target #fn, :reset sync-main-copyhead-0}\n test", :states ["cdb64413ea7e8db5" "12bbcbb8f72e4c57" "a6b198531797fe41"]}] + :l + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n swap-shape {:target #fn, :to \"s0\", :keep-touched? false}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n swap-shape {:target #fn, :to \"s2\", :keep-touched? false}\n test", :states ["2b81a2758337eb2f" "4bf0f46a7f6c712a" "5aed9a1b2601fea1" "fdf8c465f0c80711"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n swap-shape {:target #fn, :to \"s0\", :keep-touched? false}\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> skip\n test", :states ["2b81a2758337eb2f" "4bf0f46a7f6c712a" "06ed5e9a509fa5ad"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n swap-shape {:target #fn, :to \"s0\", :keep-touched? false}\n one-of -> skip\n swap-shape {:target #fn, :to \"s2\", :keep-touched? false}\n test", :states ["2b81a2758337eb2f" "657e66989eba8efc" "2b2ac154ceae7e81"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n swap-shape {:target #fn, :to \"s0\", :keep-touched? false}\n one-of -> skip\n one-of -> skip\n test", :states ["2b81a2758337eb2f" "65cb2bb9a1181900"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n swap-shape {:target #fn, :to \"s2\", :keep-touched? false}\n test", :states ["c97bdfba7db6afa8" "ab28e8d6b07d5718" "3f3cc98823625867"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n swap-shape {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> skip\n test", :states ["c97bdfba7db6afa8" "929d6d6f7ed36314"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n one-of -> skip\n swap-shape {:target #fn, :to \"s2\", :keep-touched? false}\n test", :states ["f8400e721c2a41b5" "0b1fa64e7320cc68"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n create-component {:component \"s0\", :id sync-s0-component}\n create-component {:component \"s1\", :id sync-s1-component}\n create-component {:component \"s2\", :id sync-s2-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n one-of -> skip\n one-of -> skip\n test", :states ["12634fd05d26a0ac"]}] + :library-update-into-copies + [{:transcript "library-update-into-copies", :states ["1ef284a1cccb6a10"]}] + :m + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n switch-variant {:target-component sync-vset-v1-component}\n switch-variant {:target-component sync-vset-v2-component}\n switch-variant {:target-component sync-vset-v3-component}\n test", :states ["bf2a191a1e54457c" "fb626a47913154f5" "1b889174be2f30a3" "5dd8437edeb3ffb8"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n switch-variant {:target-component sync-vset-v1-component}\n switch-variant {:target-component sync-vset-v2-component}\n one-of -> skip\n test", :states ["bf2a191a1e54457c" "fb626a47913154f5" "5dfee1004fe36c9b"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n switch-variant {:target-component sync-vset-v1-component}\n one-of -> skip\n switch-variant {:target-component sync-vset-v3-component}\n test", :states ["bf2a191a1e54457c" "7be9839a6d9ea13a" "7077672582583621"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n switch-variant {:target-component sync-vset-v1-component}\n one-of -> skip\n one-of -> skip\n test", :states ["bf2a191a1e54457c" "faa45526cce188af"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n switch-variant {:target-component sync-vset-v2-component}\n switch-variant {:target-component sync-vset-v3-component}\n test", :states ["43b4a591dc02b01b" "7b96294fa521f335" "4b6b1adcc2b70ad9"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n switch-variant {:target-component sync-vset-v2-component}\n one-of -> skip\n test", :states ["43b4a591dc02b01b" "d844ece54beb0bfe"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n one-of -> skip\n switch-variant {:target-component sync-vset-v3-component}\n test", :states ["4e56e67caa87f262" "85d6d4a265a35a44"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> skip\n one-of -> skip\n one-of -> skip\n test", :states ["a3344fab60ad0124"]}] + :main-edit-into-10-copies + [{:transcript "main-edit-into-10-copies", :states ["55176ea7a3052277"]}] + :main-edit-into-100-copies + [{:transcript "main-edit-into-100-copies", :states ["3fd3b227924187f4"]}] + :main-edit-into-1000-copies + [{:transcript "main-edit-into-1000-copies", :states ["b6994497085bc07f"]}] + :o + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n switch-variant {:target-component sync-vset-v1-component}", :states ["9a1a3735f1009290" "b00ea3774a618f8e" "d15895a5c5a7e993"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-variant-container {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n make-nested-component-with-variant {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n switch-variant {:target-component sync-vset-v1-component}", :states ["1247c1fd53a5de3f" "45d0fe0a073fbada" "9a8e3d09e48af9fe"]}] + :p + [{:transcript "change-property {:target :main-child, :property :fills, :value \"#ff0000\"}\n undo {:undone 2}\n redo {:redone 2}", :states ["17b5ce28aeffa62e" "e60c9f0fd46b2310" "17b5ce28aeffa62e" "8f31b06c3ab1921b"]}] + :q + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["906c1b936c948e9c" "f5a6da4ce34a94cc" "2c7dd0b9dd6b68cf" "10cdbfc7bb6e3f04"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["fc7269c02ab24174" "22be24454c63e03f" "5fe2e5c0eef7c7f1"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["ecb9b3d70125fdd1" "ce279a29ffc819b8" "2f06e4faefd1664c" "08484114a83b9854"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["535e5b636033381e" "5d0fef143bbf9b4e" "077c8cb51484ee5b"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["2797b111c7f0e07b" "2b017b5ecc0e3bbb" "47d1dc712e8b5491" "4972e6448b745e79"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n detach {:target #fn, :detached sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["2e5b5e7e7b56540d" "1e4798889445559b" "e75a8bb09850d21e"]}] + :r + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["4688ffdfcd1ba838" "53be29de2b082b74" "ebf1f4da1e3ac861" "ba68dd969fcd6b9c"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["ad3eed11bb0bfd34" "1d8defabcfe78984" "24ba49143ad5b389"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["6504acfd2dfbc012" "67b6d254e372d15e" "63c95485dee94f14" "569fecb94b584108"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["165424c8242fe851" "0c79c89b4319b252" "43c4776b4a90f22c"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["dd907ef11d9e4851" "481d62dd7e471206" "046525ebd0ffe008" "682e0ba7926cc177"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-1}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n update-main {:target #fn, :updated sync-main-copyhead-0}", :states ["af30a8074415ea47" "0292c4761cadebad" "8c3b12b00c20dd24"]}] + :s + [{:transcript "change-property {:target :copy-instance, :property :fills, :value \"#00ff00\"}\n change-property {:target :main-instance, :property :fills, :value \"#ff0000\"}\n delete-component {:target :main-root, :component-id component1}\n test\n restore-component {:component-id component1}\n change-property {:target :main-instance, :property :fills, :value \"#0000ff\"}", :states ["93c77f92c889307b" "0c2ac66ca5452745" "11bd55106f98bebc" "6a0d75c08f6b08b8" "bccb7c6434c8de28" "9da4088c9b6c2b45"]} + {:transcript "one-of -> skip\n change-property {:target :main-instance, :property :fills, :value \"#ff0000\"}\n delete-component {:target :main-root, :component-id component1}\n test\n restore-component {:component-id component1}\n change-property {:target :main-instance, :property :fills, :value \"#0000ff\"}", :states ["8c5be47002e73694" "323f1f1ed8b35e4d" "eb7c91cf5e08a6c3" "86c4d8c4352a04db" "ddbdea68968e3988"]}] + :t + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n duplicate {:target #fn, :new-head 3}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["81ed7e3425a10d37" "9d61afd70c45c20d" "32c6c16f78eafcb5" "dfe25be96378c688"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n duplicate {:target #fn, :new-head 3}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["3cd3c21dfa8a2a0b" "2a76e300a7c87062" "f4eee5c311f84114"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n duplicate {:target #fn, :new-head 5}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["b5efa1ca701be1d4" "406fb26d0306d6a9" "e4f586cc4220558a" "842ad6907c98d333"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n duplicate {:target #fn, :new-head 5}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["b728600a7c291809" "7227919d6d222019" "aae9416ab643b5ea"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n duplicate {:target #fn, :new-head 8}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["083c91e86a50fc3d" "f5f413ad5bea79a4" "0dba6a2c453b5250" "9857e951ca902581"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> skip\n duplicate {:target #fn, :new-head 8}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["ba24e834d0767879" "e97c69b1e46ffe5d" "ec75501d3a176eef"]}] + :u + [{:transcript "create-component {:component \"outer\", :id sync-outer-component}\n create-component {:component \"inner\", :id sync-inner-component}\n instantiate-copy {:component \"outer\", :copy sync-outer-copyhead-0}\n instantiate-copy {:component \"inner\", :copy sync-inner-copyhead-0}\n nest-copy {:copy #fn, :into #fn, :cell nil}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["787b17b227cfdb85" "f6490ae9fe96d3e4" "bd40aa51b1ec2fd1" "53c3ace2c3feb6d6"]} + {:transcript "create-component {:component \"outer\", :id sync-outer-component}\n create-component {:component \"inner\", :id sync-inner-component}\n instantiate-copy {:component \"outer\", :copy sync-outer-copyhead-0}\n instantiate-copy {:component \"inner\", :copy sync-inner-copyhead-0}\n nest-copy {:copy #fn, :into #fn, :cell nil}\n one-of -> skip\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["787b17b227cfdb85" "e662ae31e1675fa9" "435dd5416b94f48f"]}] + :v + [{:transcript "change-property {:target :main-instance, :property :fills, :value \"#ff0000\"}\n undo {:undone 2}\n change-property {:target :main-instance, :property :fills, :value \"#00ff00\"}\n undo {:undone 2}\n redo {:redone 2}\n redo {:redone 0}", :states ["17b5ce28aeffa62e" "e60c9f0fd46b2310" "a30b6f606aaa5f66" "e60c9f0fd46b2310" "a30b6f606aaa5f66" "a30b6f606aaa5f66" "0ba2151cc54b42fa"]}] + :variant-switch-into-copies + [{:transcript "variant-switch-into-copies", :states ["6cdf94ad6bd691c5"]}] + :w + [{:transcript "create-component {:component \"main\", :id sync-main-component}\n one-of -> skip\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#aaaaaa\"}\n undo {:undone 5}", :states ["f06eb554db2a667d" "906c1b936c948e9c" "8e29f79b473c1a0b" "0072b33980dae904" "bd57e8070d829bdf"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#aaaaaa\"}\n undo {:undone 6}", :states ["1de51816cdc0ad11" "ed2117b3a6ae1dd6" "c90876e1b44d00fb" "a5b1e4b00086c891" "f09bed0fa67d711c"]} + {:transcript "create-component {:component \"main\", :id sync-main-component}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n make-nested-component {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n instantiate-copy {:component \"main\", :copy sync-main-copyhead-0}\n change-property {:target #fn, :property :fills, :value \"#0000ff\"}\n change-property {:target #fn, :property :fills, :value \"#00ff00\"}\n change-property {:target #fn, :property :fills, :value \"#aaaaaa\"}\n undo {:undone 7}", :states ["262f632dd4a0ac41" "af99191229bac7b4" "8ba7cefbe6e101d8" "ab0a68e1af334a44" "987979e4d37001b6"]}] + :y + [{:transcript "one-of -> recorded-choice\n edit-text {:target :copy-instance, :edit :text, :value \"copy text\"}\n edit-text {:target :main-instance, :edit :text, :value \"main text\"}", :states ["8cd35014bebff5a0" "260d9897b862470e" "01f96b240a9f7786"]} + {:transcript "one-of -> recorded-choice\n edit-text {:target :copy-instance, :edit :text, :value \"copy text\"}\n edit-text {:target :main-instance, :edit :font-size, :value \"24\"}", :states ["8cd35014bebff5a0" "9a2bfd72cc5a6898" "8df2236d989a127c"]} + {:transcript "one-of -> recorded-choice\n edit-text {:target :copy-instance, :edit :font-size, :value \"32\"}\n edit-text {:target :main-instance, :edit :text, :value \"main text\"}", :states ["c0b1a5e708231296" "75e32d376c1957f9" "b1213922be7ac4cb"]} + {:transcript "one-of -> recorded-choice\n edit-text {:target :copy-instance, :edit :font-size, :value \"32\"}\n edit-text {:target :main-instance, :edit :font-size, :value \"24\"}", :states ["c0b1a5e708231296" "8eaab011168c2a4b" "14063d206179c049"]} + {:transcript "one-of -> skip\n edit-text {:target :main-instance, :edit :text, :value \"main text\"}", :states ["6c385dbccb923ae0" "f357affeab5963f4"]} + {:transcript "one-of -> skip\n edit-text {:target :main-instance, :edit :font-size, :value \"24\"}", :states ["6662689408ae889b" "69bb096083b547ee"]}]} diff --git a/common/test/common_tests/logic/golden_master_test.clj b/common/test/common_tests/logic/golden_master_test.clj new file mode 100644 index 0000000000..ebabe6db8a --- /dev/null +++ b/common/test/common_tests/logic/golden_master_test.clj @@ -0,0 +1,139 @@ +;; 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 common-tests.logic.golden-master-test + "The golden master of the component code on the JVM: the exact files that + the shared composable cases (through the pure runner) and the benchmark + worlds produce (see `app.common.test-helpers.golden-master`). A refactor + must keep them; a change that alters them is a behavior change, made on + purpose and recorded again. + + A case variant records the state after each user, undo and redo step, + then its files at the end with the signatures of its undo/redo round trip + failures; a world records its file after its timed work. + + `golden_master.edn` next to this file keeps the digests; the full lines + go to `tmp/golden-master/` at the repository root. Record from `common/` + with + `PENPOT_GOLDEN_MASTER=record clojure -M:dev:test --focus common-tests.logic.golden-master-test`, + only on purpose and saying why in the commit." + (:require + [app.common.test-helpers.composable.comp.cases :as cases] + [app.common.test-helpers.composable.comp.runner :as r] + [app.common.test-helpers.composable.comp.undo-check :as uc] + [app.common.test-helpers.composable.core :as tm] + [app.common.test-helpers.golden-master :as thgm] + [app.common.test-helpers.ids-map :as thi] + [bench.component-sync :as bench] + [clojure.test :as t])) + +(def ^:private digests-path "test/common_tests/logic/golden_master.edn") + +(def ^:private lines-dir "../tmp/golden-master") + +(defn- recording? + [] + (= "record" (System/getenv "PENPOT_GOLDEN_MASTER"))) + +(def ^:private case-fns + "The shared cases the pure runner runs (see + `common-tests.logic.composable-sync-test`), by key." + (array-map + :b cases/copy-override-survives-later-main-change + :c cases/attribute-sweep-propagates-to-clean-copy + :d cases/add-shape-to-main-propagates-to-clean-copy + :e cases/remove-shape-from-main-propagates-to-clean-copy + :f cases/move-shape-in-main-propagates-order-to-clean-copy + :h cases/library-change-propagates-across-file-boundary-on-sync + :i cases/undo-reverts-edit-and-its-propagation + :p cases/redo-reapplies-edit-and-its-propagation + :k cases/synchronisation-scenarios + :l cases/swap-scenarios + :m cases/variant-switch-scenarios + :o cases/variant-switch-keeps-override-only-where-mains-agree + :q cases/detach-keeps-nested-copies-linked + :r cases/update-main-reaches-other-copies + :s cases/deleted-component-copies-sync-again-after-restore + :t cases/duplicated-copy-keeps-overrides-and-link + :u cases/nested-copy-reaches-copies-of-the-receiving-main + :v cases/new-edit-after-undo-clears-redo + :w cases/undo-several-steps-over-nested-cascades + :y cases/text-override-merges-with-main-text-change + :ba cases/text-style-override-against-main-style-change + :aa cases/copy-swap-survives-main-changes + :ab cases/reset-of-nested-swap-keeps-top-copy-overrides + :ac cases/second-variant-switch-keeps-root-overrides + :ad cases/update-main-pushes-a-swapped-child + :ae cases/detached-or-duplicated-swapped-copy-follows-its-component + :af cases/grid-cell-move-reaches-a-swapped-copy-child + :ag cases/main-reorder-keeps-copy-sub-heads-aligned + :ah cases/copy-sub-head-delete-keeps-others-aligned + :ak cases/update-main-pushes-grid-cells + :al cases/update-main-renames-the-component + :am cases/update-main-pushes-a-swap-inside-a-group + :an cases/flex-child-override-follows-sync-reset-and-update-main + :ao cases/copy-dropped-into-a-grid-cell-reaches-copies + :ap cases/library-main-child-removal-reaches-copy + :aq cases/main-change-reaches-a-copy-nested-in-a-sub-board + :ar cases/variant-property-edits-keep-copies + :as cases/added-variant-is-a-switch-target + :ay cases/token-on-a-main-reaches-copies + :az cases/copy-moved-out-of-its-main-keeps-inherited-overrides)) + +(defn- situation-files + [situation] + (cons (tm/file situation) (vals (tm/aux-files situation)))) + +(defn- run-case + "The states of each variant of `case-map`: one per user, undo and redo + step, then the final one, with the round trip's failures." + [case-map] + (let [steps (atom []) + variants (atom []) + observe (fn [situation] + (swap! steps conj (thgm/state-lines (situation-files situation) nil)))] + (r/run-each case-map {:observe observe} + (fn [situation] + (let [files (situation-files situation) + failures (into #{} (map (juxt :phase :signature)) (uc/failures situation)) + final (thgm/state-lines files {:undo-failures failures})] + (swap! variants conj {:transcript (thgm/transcript situation (thgm/id-names files)) + :states (conj @steps final)}) + (reset! steps [])))) + @variants)) + +(defn- run-world + "The state of benchmark world `build` after its timed work." + [build] + (thi/reset-idmap!) + (let [{:keys [key run libraries]} (build) + [file passes] (run)] + [key [{:transcript (name key) + :states [(thgm/state-lines (cons file libraries) {:passes passes})]}]])) + +(defn- groups + "Every case and world as `[key variants]`, run one at a time." + [] + (concat + (for [[key case-fn] case-fns] + (do (thi/reset-idmap!) + [key (run-case (case-fn))])) + (map run-world (bench/world-builders)))) + +(t/deftest golden-master + (if (recording?) + (do + (thgm/write-digests! digests-path + (into {} (map (fn [[group variants]] + [group (thgm/record-group! lines-dir group variants)])) + (groups))) + (t/is true)) + (let [recorded (thgm/read-digests digests-path) + groups (vec (groups))] + (t/is (= (set (keys recorded)) (set (map first groups))) + "the cases and worlds differ from the recorded ones") + (doseq [[group variants] groups] + (thgm/compare-group! lines-dir group variants (get recorded group)))))) diff --git a/frontend/test/frontend_tests/composable_tests/golden_master.edn b/frontend/test/frontend_tests/composable_tests/golden_master.edn new file mode 100644 index 0000000000..b124037386 --- /dev/null +++ b/frontend/test/frontend_tests/composable_tests/golden_master.edn @@ -0,0 +1,221 @@ +;; Golden master digests, written by the golden master test. +{:case-aa-copy-swap-survives-main-changes + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn, :to \"s2\", :keep-touched? false}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["a1eb6e86bd5c7824" "4b505537f060c27e" "a8c5332cc7b15424" "253ba3894650baa4"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn, :to \"s2\", :keep-touched? false}\n one-of -> ", :states ["a1eb6e86bd5c7824" "4b505537f060c27e" "94d3e3d3f14e0e58"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["a1eb6e86bd5c7824" "16622fffacac0c8d" "964a553e029b1e19"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> \n one-of -> ", :states ["a1eb6e86bd5c7824" "4ce98879b40b53aa"]}] + :case-ab-reset-of-nested-swap-keeps-top-copy-overrides + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :opacity, :value 0.5}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn}", :states ["18092b58aa495ad2" "783143fdc428e89e" "8398b5c6929d2064" "c13a6df26c01deb1"]}] + :case-ac-second-variant-switch-keeps-root-overrides + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 3}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :opacity, :value 0.5}\n {:target #fn, :value \"b\", :pos 0}\n \n {:target #fn, :value \"c\", :pos 0}", :states ["45b82e3d3433e503" "6aa8b050f6e60b75" "2464ce46aa6d70f8" "83ae3b7689a44277"]}] + :case-ad-update-main-pushes-a-swapped-child + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn}", :states ["70154c2f90c4d94f" "8276a39e105869aa" "60ae4e382dab157a"]}] + :case-ae-detached-or-duplicated-swapped-copy-follows-its-component + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["d74e87bca3fa2eb9" "04d085bb07bb3857" "b886602f9de07d6e" "b57c324aaa781800"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn, :new-head 5}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["d74e87bca3fa2eb9" "e2162174653b4d7b" "0bd8763796243e1f" "f612d9fde86170a6"]}] + :case-af-grid-cell-move-reaches-a-swapped-copy-child + [{:transcript " {:target :copy-child, :to :other, :keep-touched? false}\n {:board :main-root, :child :main-child, :row 1, :column 3}", :states ["5a6af6c0b8f86ac3" "ec2294c072f52ae5" "8cd63b096547fb1b"]} + {:transcript "one-of -> \n {:board :main-root, :child :main-child, :row 1, :column 3}", :states ["ab911a9c4ef389ba" "56df09285036aa60"]}] + :case-ag-main-reorder-keeps-copy-sub-heads-aligned + [{:transcript " {:target :sub1, :parent :row-root, :to-index 3}", :states ["8118be0e3d318e30" "bd3db9738a8851c0"]}] + :case-ah-copy-sub-head-delete-keeps-others-aligned + [{:transcript "one-of -> \n {:target :copy-sub1}", :states ["fff37cf722a40e61" "6fd3a8bad999968b"]} + {:transcript "one-of -> \n {:target :copy-sub3}", :states ["efada86db353920f" "3364b0fbfb76067a"]} + {:transcript "one-of -> ", :states ["94318a628db305b6"]}] + :case-ai-copy-sub-head-delete-and-reflow-keeps-others-aligned + [{:transcript "one-of -> \n {:target :copy-sub1}\n {:target :copy-root, :value 500}", :states ["fff37cf722a40e61" "738377a4c5ef9f3c" "f23a64d143d27dba"]} + {:transcript "one-of -> \n {:target :copy-sub1}\n one-of -> ", :states ["fff37cf722a40e61" "6fd3a8bad999968b"]} + {:transcript "one-of -> \n {:target :copy-sub3}\n {:target :copy-root, :value 500}", :states ["efada86db353920f" "701edc575ad9c0c6" "91db7f5306659911"]} + {:transcript "one-of -> \n {:target :copy-sub3}\n one-of -> ", :states ["efada86db353920f" "3364b0fbfb76067a"]} + {:transcript "one-of -> \n {:target :copy-root, :value 500}", :states ["df9a66ef7c8ee469" "c4f0c92f92575cda"]} + {:transcript "one-of -> \n one-of -> ", :states ["94318a628db305b6"]}] + :case-aj-reflow-after-nested-sync-is-its-own-undo-step + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:times 1}", :states ["43ca8b2de80a51fc" "43ca8b2de80a51fc" "9c3022331b3fe9ae"]}] + :case-ak-update-main-pushes-grid-cells + [{:transcript " {:target :copy-child, :to :other, :keep-touched? false}\n {:board :copy-root, :child :copy-child, :row 1, :column 3}\n {:target :copy-root}", :states ["5a6af6c0b8f86ac3" "278e4ff6bf0df746" "f611ebe15fb41317" "ead3c5e066d93cc4"]} + {:transcript "one-of -> \n {:board :copy-root, :child :copy-child, :row 1, :column 3}\n {:target :copy-root}", :states ["9900a7f71dc0cb5f" "de66ab1c3d4cc157" "6b5ff9fd86e2aa87"]}] + :case-al-update-main-renames-the-component + [{:transcript " {:target :copy-root, :property :name, :value \"Renamed\"}\n {:target :copy-instance, :property :name, :value \"Renamed child\"}\n {:target :copy-root}", :states ["d4e11348047fc1e1" "0021aeab497d25e6" "c0aa5a2b915a7542" "ca23729038aec91f"]} + {:transcript " {:target :copy-root, :property :name, :value \"Renamed\"}\n one-of -> \n {:target :copy-root}", :states ["d4e11348047fc1e1" "409795fc3e2bb3a7" "6a882f51aaf16306"]}] + :case-am-update-main-pushes-a-swap-inside-a-group + [{:transcript " {:target :copy-child, :to :other, :keep-touched? false}\n {:target :copy-root}", :states ["aba215c5bc93ff0d" "f2232d12b1707e79" "a9496203eed2406e"]}] + :case-an-flex-child-override-follows-sync-reset-and-update-main + [{:transcript " {:target :copy-instance, :property :margin, :value 8}\n {:target :main-instance, :property :margin, :value 20}", :states ["234a21e54bf21bd5" "03664b1e6eb74856" "9c3b12abbc6089ce"]} + {:transcript " {:target :copy-instance, :property :margin, :value 8}\n {:target :copy-root}", :states ["234a21e54bf21bd5" "1f92f9b4d2e50598" "a09954797e57930c"]} + {:transcript " {:target :copy-instance, :property :margin, :value 8}\n {:target :copy-root}", :states ["234a21e54bf21bd5" "ace1e76c1da2c443" "8f3452e82544f1ad"]}] + :case-ao-copy-dropped-into-a-grid-cell-reaches-copies + [{:transcript " {:copy :loose, :into :main-root, :cell [1 3]}", :states ["abc6e41a291516a2" "88ef39349d35f0b6"]}] + :case-ap-library-main-child-removal-reaches-copy + [{:transcript "", :states ["f53d220c42298128" "7c2dfde6478d399c"]}] + :case-aq-main-change-reaches-a-copy-nested-in-a-sub-board + [{:transcript " {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["d458024081bee6ec" "df29aaf3b63bece6" "0aef0de70c1e2e98"]} + {:transcript "one-of -> \n {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["c9ecea6283cef90c" "be12b667808778f3"]}] + :case-ar-variant-property-edits-keep-copies + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n {:set-name \"vset\", :edit :rename, :params {:pos 0, :name \"Color\"}}\n \n {:target #fn, :value \"b\", :pos #fn}", :states ["df9a042b9d59d699" "c4f5353ee8eb5822" "63ea87cd0b4d141b" "769b5be744bb40fd" "bf639b8e0da39e6e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n {:set-name \"vset\", :edit :set-value, :params {:member \"a\", :pos 0, :value \"a2\"}}\n \n {:target #fn, :value \"b\", :pos #fn}", :states ["df9a042b9d59d699" "c4f5353ee8eb5822" "767cb025f6ccf371" "5c9f674c0eeebbc0" "20a320e9ab14039f"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n {:set-name \"vset\", :edit :reorder, :params {:from 1, :to 0}}\n \n {:target #fn, :value \"b\", :pos #fn}", :states ["df9a042b9d59d699" "c4f5353ee8eb5822" "20e7c6031f77998f" "4b387428cd241ed1" "a79933f2d6da95da"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:set-name \"vset\", :edit :add, :params {:property-name \"Size\", :property-value \"S\"}}\n {:set-name \"vset\", :edit :remove, :params {:pos 1}}\n \n {:target #fn, :value \"b\", :pos #fn}", :states ["df9a042b9d59d699" "c4f5353ee8eb5822" "df9a042b9d59d699" "ef6a99bd8579dc7f" "3b1bfc8427b3963d"]}] + :case-as-added-variant-is-a-switch-target + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:set-name \"vset\", :member \"a\", :component-id 7}\n \n {:target #fn, :value \"Value 3\", :pos 0}", :states ["df9a042b9d59d699" "00b4a79bae39f703" "0b85fa1611096bb7" "542884fb9e0b082e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:set-name \"vset\", :member \"b\", :component-id 7}\n \n {:target #fn, :value \"Value 3\", :pos 0}", :states ["df9a042b9d59d699" "73a3942a18403d5e" "3234ee274caa5b9e" "0fd372565af6eae2"]}] + :case-at-transformed-component-keeps-its-copies + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :name, :value \"Button/Primary\"}\n {:action :transform, :params {:target #fn}}\n \n {:target #fn, :value \"Value 2\", :pos 0}", :states ["19168567c3f4c8b1" "865741f5dae8819e" "7f7bd28b4563fabd" "bca3e99455b8e931" "06c3f510cacd8a58"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :name, :value \"Button/Primary\"}\n {:action :shortcut, :params {:kind :create-component, :targets [#fn]}}\n \n {:target #fn, :value \"Value 2\", :pos 0}", :states ["19168567c3f4c8b1" "865741f5dae8819e" "7f7bd28b4563fabd" "bca3e99455b8e931" "06c3f510cacd8a58"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n {:action :transform, :params {:target #fn}}\n \n {:target #fn, :value \"Value 2\", :pos 0}", :states ["19168567c3f4c8b1" "cfce0b246967964a" "2c3ef0411b35a158" "0d456e1108bb1756"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n {:action :shortcut, :params {:kind :create-component, :targets [#fn]}}\n \n {:target #fn, :value \"Value 2\", :pos 0}", :states ["19168567c3f4c8b1" "cfce0b246967964a" "2c3ef0411b35a158" "0d456e1108bb1756"]}] + :case-au-combined-components-keep-their-copies + [{:transcript " {:component \"first\", :id sync-first-component}\n {:component \"second\", :id sync-second-component}\n {:component \"first\", :copy sync-first-copyhead-0}\n {:component \"second\", :copy sync-second-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :combine, :params {:targets [#fn #fn], :selected? nil}}\n \n {:target #fn, :value #fn, :pos 0}", :states ["61c776d9e973c9dd" "0f68af4cace0f325" "97651ebcd2334fe5" "47fc4c7f440fdc13"]} + {:transcript " {:component \"first\", :id sync-first-component}\n {:component \"second\", :id sync-second-component}\n {:component \"first\", :copy sync-first-copyhead-0}\n {:component \"second\", :copy sync-second-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :combine, :params {:targets [#fn #fn], :selected? true}}\n \n {:target #fn, :value #fn, :pos 0}", :states ["61c776d9e973c9dd" "0f68af4cace0f325" "97651ebcd2334fe5" "47fc4c7f440fdc13"]}] + :case-av-variant-rename-reaches-copy-names + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :name, :value \"Mine\"}\n {:action :rename, :params {:target #fn, :name \"Renamed\"}}", :states ["c6e889ca261596ce" "940f36855f4f991d" "d7a54338ab53a791"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:action :rename, :params {:target #fn, :name \"Renamed\"}}", :states ["5eb544d7e28709d7" "5e6794a9b313112e"]}] + :case-aw-variant-layer-rename-and-cleanup + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :rename-in-layers, :params {:set-name \"vset\", :member \"a\", :properties [[\"Property 1\" \"a2\"] [\"Size\" \"S\"]]}}\n \n {:set-name \"vset\", :edit :add, :params {:property-name \"Empty\"}}\n {:action :remove-empty, :params {:set-name \"vset\"}}\n \n {:action :rename-in-layers, :params {:set-name \"vset\", :member \"a\", :properties [[\"Property 1\" \"a2\"]]}}\n \n {:action :remove-empty, :params {:set-name \"vset\"}}\n \n {:action :error, :params {:set-name \"vset\", :member \"b\", :value \"Duplicated\"}}\n \n {:action :error, :params {:set-name \"vset\", :member \"b\", :value nil}}\n \n {:target #fn, :value \"b\", :pos 0}", :states ["df9a042b9d59d699" "4b53486972986d97" "8553f89a9ebbcf54" "4b53486972986d97" "3af1829d8b4ab932" "d65ad905aa97d661" "6daf5f692c6595f1" "d65ad905aa97d661" "cc7d2dfd618fc8cb" "6390b4d83995b629"]}] + :case-ax-variant-shortcuts-add-members + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :shortcut, :params {:kind :create-component, :targets [#fn]}}", :states ["df9a042b9d59d699" "00b4a79bae39f703" "3c821d5f87436799"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :shortcut, :params {:kind :duplicate, :targets [#fn]}}", :states ["df9a042b9d59d699" "00b4a79bae39f703" "3c821d5f87436799"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :shortcut, :params {:kind :create-component, :targets [#fn #fn]}}", :states ["df9a042b9d59d699" "07e820c7c676a7b0" "d3972300b9f78ab6"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:action :shortcut, :params {:kind :duplicate, :targets [#fn #fn]}}", :states ["df9a042b9d59d699" "07e820c7c676a7b0" "d3972300b9f78ab6"]}] + :case-ay-token-on-a-main-reaches-copies + [{:transcript " {:component \"main\", :id sync-main-component}\n {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :token-name \"radius.s\", :value 10}\n {:target #fn, :token-name \"radius.l\", :value 30}\n \n {:target #fn, :token-name \"radius.l\"}", :states ["04cddffca776d7fb" "24756b13d210f3a5" "8e8c0c21d4a0638b" "f656f9c8188793cf"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :token-name \"radius.s\", :value 10}\n {:target #fn, :token-name \"radius.l\", :value 30}\n \n one-of -> ", :states ["04cddffca776d7fb" "24756b13d210f3a5" "8fb17ce46cb883c8"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :token-name \"radius.l\", :value 30}\n \n {:target #fn, :token-name \"radius.l\"}", :states ["d943d9831136267d" "ae544068bc050c2a" "eb8434e3f9dd763e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:tokens [[\"radius.s\" 10] [\"radius.l\" 30]]}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :token-name \"radius.l\", :value 30}\n \n one-of -> ", :states ["d943d9831136267d" "62fe93164996f7fe"]}] + :case-az-copy-moved-out-of-its-main-keeps-inherited-overrides + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:target #fn, :new-head 5}\n \n {:target #fn, :property :fills, :value \"#ff0000\"}", :states ["d6802c2361c4f48a" "09526a373b2bf78d" "f6588d21ee3f82ea" "89696ef8abcbb71d"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n {:target #fn, :new-head 3}\n \n {:target #fn, :property :fills, :value \"#ff0000\"}", :states ["d6802c2361c4f48a" "7443c8f4406f3704" "78edc4e41925495c" "62c32614a4d51244"]}] + :case-b-copy-override-survives-later-main-change + [{:transcript " {:target :copy-child, :property :fills, :value \"#00ff00\"}\n {:target :main-child, :property :fills, :value \"#ff0000\"}", :states ["83d0e402abf3aafe" "89465e6b1fc243c5" "009c37e0db2f75d7"]}] + :case-ba-text-style-override-against-main-style-change + [{:transcript " {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> \n {:target :copy-root}", :states ["f1cef32655dc15d3" "aedb3d1edeec9ee8" "a3b039c1df563ee6" "6b5ce93d0ac4d982"]} + {:transcript " {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> \n {:target :copy-root}", :states ["f1cef32655dc15d3" "aedb3d1edeec9ee8" "9fa24035c7ef30ab" "8dcfa14b662c9dce"]} + {:transcript " {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> ", :states ["f1cef32655dc15d3" "aedb3d1edeec9ee8" "4d60d06154db73bf"]} + {:transcript " {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> \n {:target :copy-root}", :states ["f1cef32655dc15d3" "1b3c02b90b597b97" "80d237d6176697ad" "e78e170e91d99cb4"]} + {:transcript " {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> \n {:target :copy-root}", :states ["f1cef32655dc15d3" "1b3c02b90b597b97" "3f3e545b6451d3d8" "76357709c6222dc6"]} + {:transcript " {:target :copy-instance, :edit :fills, :value [{:fill-color \"#FF0000\", :fill-opacity 1}]}\n {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> ", :states ["f1cef32655dc15d3" "1b3c02b90b597b97" "e99bcf8ab3895d17"]} + {:transcript " {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> \n {:target :copy-root}", :states ["c2c41d13f1023206" "9a89f95d514d8a3f" "a3b039c1df563ee6" "6b5ce93d0ac4d982"]} + {:transcript " {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> \n {:target :copy-root}", :states ["c2c41d13f1023206" "9a89f95d514d8a3f" "80544041ddd4c555" "1b0ac1fc4205eafb"]} + {:transcript " {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n {:target :main-instance, :edit :fills, :value [{:fill-color \"#0000FF\", :fill-opacity 1}]}\n one-of -> ", :states ["c2c41d13f1023206" "9a89f95d514d8a3f" "9af0564566bdfa27"]} + {:transcript " {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> \n {:target :copy-root}", :states ["c2c41d13f1023206" "29c5721627efc0f2" "80d237d6176697ad" "e78e170e91d99cb4"]} + {:transcript " {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> \n {:target :copy-root}", :states ["c2c41d13f1023206" "29c5721627efc0f2" "fb174d28a700d7aa" "e50d3548740f22df"]} + {:transcript " {:target :copy-instance, :edit :font-family, :value \"Roboto\"}\n {:target :main-instance, :edit :font-family, :value \"Inter\"}\n one-of -> ", :states ["c2c41d13f1023206" "29c5721627efc0f2" "df6a804b273d17e4"]}] + :case-c-attribute-sweep-auto-propagates-to-clean-copy + [{:transcript " {:target :main-child, :property :fills, :value \"#ff0000\"}", :states ["386e940ac63af4b1" "8f48f693ee787fec"]} + {:transcript " {:target :main-child, :property :opacity, :value 0.5}", :states ["75960051ace0a903" "cd93cbbc9654a03f"]}] + :case-d-add-shape-to-main-auto-propagates-to-clean-copy + [{:transcript " {:parent :main-root, :new-label :main-child-2, :shape-params nil}", :states ["04160b1fd954a526" "c15468a32f6a6eee"]}] + :case-e-remove-shape-from-main-auto-propagates-to-clean-copy + [{:transcript " {:target :main-child2}", :states ["43c6f0fafdb79914" "d084fa213a85ee68"]}] + :case-f-move-shape-in-main-auto-propagates-order-to-clean-copy + [{:transcript " {:target :main-child1, :parent :main-root, :to-index 2}", :states ["1994876f6bbe7d2e" "0ac4d4f98925b8d9"]}] + :case-h-library-change-propagates-across-file-boundary-on-sync + [{:transcript "", :states ["d8c5e8bda3728127" "6ee281995d7d8f65"]}] + :case-i-undo-reverts-edit-and-its-auto-propagation + [{:transcript " {:target :main-child, :property :fills, :value \"#ff0000\"}\n \n {:times 1}", :states ["386e940ac63af4b1" "734ec524d88eb6bb" "ff1fa863b88027e5"]}] + :case-k-synchronisation-scenarios + [{:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["4df63fbd39f111b4" "e3ad22551ca81acf" "7e5eb4ef4c5906c9" "7e5eb4ef4c5906c9" "e3ad22551ca81acf" "d3c9dea3b93d0e03"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["4df63fbd39f111b4" "e3ad22551ca81acf" "7e5eb4ef4c5906c9" "e3ad22551ca81acf" "d3c9dea3b93d0e03"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["4df63fbd39f111b4" "4ce6186d4ece003f" "4ce6186d4ece003f" "4df63fbd39f111b4" "a8f6e49033b99e9e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> \n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["4df63fbd39f111b4" "4ce6186d4ece003f" "4df63fbd39f111b4" "a8f6e49033b99e9e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["e3ad22551ca81acf" "7e5eb4ef4c5906c9" "7e5eb4ef4c5906c9" "e3ad22551ca81acf" "d3c9dea3b93d0e03"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["e3ad22551ca81acf" "7e5eb4ef4c5906c9" "e3ad22551ca81acf" "d3c9dea3b93d0e03"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["4fd719f4ba29bcf4" "4fd719f4ba29bcf4" "fed5cad23679bb6b" "90e72f0f691777c1"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n one-of -> \n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["4fd719f4ba29bcf4" "fed5cad23679bb6b" "90e72f0f691777c1"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["cd9d65b6e9e44dd4" "8b02b2c2f738633c" "c060d7212278ad3f" "c060d7212278ad3f" "8b02b2c2f738633c" "396bcc2a635b9ae9"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["cd9d65b6e9e44dd4" "8b02b2c2f738633c" "c060d7212278ad3f" "8b02b2c2f738633c" "396bcc2a635b9ae9"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["cd9d65b6e9e44dd4" "3fb818ca5c73bde6" "3fb818ca5c73bde6" "cd9d65b6e9e44dd4" "ddea124a9ab145f1"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> \n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["cd9d65b6e9e44dd4" "3fb818ca5c73bde6" "cd9d65b6e9e44dd4" "ddea124a9ab145f1"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["e7fd52bfd7469a3e" "ed64a4f1c0559892" "ed64a4f1c0559892" "e7fd52bfd7469a3e" "c03e1b72c66b350b"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["e7fd52bfd7469a3e" "ed64a4f1c0559892" "e7fd52bfd7469a3e" "c03e1b72c66b350b"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["79a17aea4be35a77" "79a17aea4be35a77" "856a1a85640e346b" "c3614af678a02e24"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n one-of -> \n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["79a17aea4be35a77" "856a1a85640e346b" "c3614af678a02e24"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["3f2266fbef201c71" "1ad84c27e54fc157" "6bab293b0f4e46f6" "6bab293b0f4e46f6" "1ad84c27e54fc157" "7b70e8e778fba787"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["3f2266fbef201c71" "1ad84c27e54fc157" "6bab293b0f4e46f6" "1ad84c27e54fc157" "7b70e8e778fba787"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["3f2266fbef201c71" "283666e530b7f0a7" "283666e530b7f0a7" "3f2266fbef201c71" "32c65c945efec2cd"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#ff0000\"}\n one-of -> \n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["3f2266fbef201c71" "283666e530b7f0a7" "3f2266fbef201c71" "32c65c945efec2cd"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["c715b942fef256f0" "cb212f3029cadc98" "cb212f3029cadc98" "c715b942fef256f0" "3dcd5e13aec8eb22"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["c715b942fef256f0" "cb212f3029cadc98" "c715b942fef256f0" "3dcd5e13aec8eb22"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["56f86e11add59364" "56f86e11add59364" "0f43477fe0aa8039" "ef7ccf843df65aa4"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n one-of -> \n one-of -> \n \n {:target #fn, :property :fills, :value \"#0000ff\"}\n \n {:target #fn}\n ", :states ["56f86e11add59364" "0f43477fe0aa8039" "ef7ccf843df65aa4"]}] + :case-l-swap-scenarios + [{:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :to \"s0\", :keep-touched? false}\n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn, :to \"s2\", :keep-touched? false}\n ", :states ["61c6023206dd13c0" "2d322b0234c845a4" "99e7baab4f4d08d3" "dc513dbabfd12fb8"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :to \"s0\", :keep-touched? false}\n {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> \n ", :states ["61c6023206dd13c0" "2d322b0234c845a4" "6d0014296bd7221f"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :to \"s0\", :keep-touched? false}\n one-of -> \n {:target #fn, :to \"s2\", :keep-touched? false}\n ", :states ["61c6023206dd13c0" "465bfffa21ed521b" "61d3b1ed23ecd621"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :to \"s0\", :keep-touched? false}\n one-of -> \n one-of -> \n ", :states ["61c6023206dd13c0" "5f626567484d7be9"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n {:target #fn, :to \"s1\", :keep-touched? false}\n {:target #fn, :to \"s2\", :keep-touched? false}\n ", :states ["bec529e88e98bff1" "dbebf6fa9f151043" "d6324cffd150de8e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n {:target #fn, :to \"s1\", :keep-touched? false}\n one-of -> \n ", :states ["bec529e88e98bff1" "bb13151761de3616"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n one-of -> \n {:target #fn, :to \"s2\", :keep-touched? false}\n ", :states ["a2a35ce5f947003d" "4c3920a4ce49e2ae"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"s0\", :id sync-s0-component}\n {:component \"s1\", :id sync-s1-component}\n {:component \"s2\", :id sync-s2-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n one-of -> \n one-of -> \n ", :states ["5d4c7d9094bfeaa7"]}] + :case-m-variant-switch-scenarios + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :value \"v1\", :pos 0}\n {:target #fn, :value \"v2\", :pos 0}\n {:target #fn, :value \"v3\", :pos 0}\n ", :states ["b9a9cbdb19f95782" "fa9fadee59f9ef60" "341671c93d89e22d" "506e63f5083d881c"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :value \"v1\", :pos 0}\n {:target #fn, :value \"v2\", :pos 0}\n one-of -> \n ", :states ["b9a9cbdb19f95782" "fa9fadee59f9ef60" "22485d54edbee38c"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :value \"v1\", :pos 0}\n one-of -> \n {:target #fn, :value \"v3\", :pos 0}\n ", :states ["b9a9cbdb19f95782" "859ade3c30f287ec" "d00f217efe63f42d"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n {:target #fn, :value \"v1\", :pos 0}\n one-of -> \n one-of -> \n ", :states ["b9a9cbdb19f95782" "74134373cb5d6a7b"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n {:target #fn, :value \"v2\", :pos 0}\n {:target #fn, :value \"v3\", :pos 0}\n ", :states ["5a79e103f49ac2c4" "e0f85e7e36c95860" "1724beab33728572"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n {:target #fn, :value \"v2\", :pos 0}\n one-of -> \n ", :states ["5a79e103f49ac2c4" "acfb6959f79a0321"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n one-of -> \n {:target #fn, :value \"v3\", :pos 0}\n ", :states ["5465856887185ca0" "72519cdcd7188cc4"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 4}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 2, :outer sync-main-outercomp-2}\n one-of -> \n one-of -> \n one-of -> \n ", :states ["0873995f173d4a79"]}] + :case-n-geometry-sync-with-rotated-instances + [{:transcript " {:target :copy-root, :angle 45}\n {:target :main-root, :angle 30}\n {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["ba9a6dac13f812ea" "53df1008cfc253d9" "5209d5674c0f3d7d" "25decd78552afde5"]} + {:transcript " {:target :copy-root, :angle 45}\n {:target :main-root, :angle 30}\n {:target :main-instance, :value 80}", :states ["ba9a6dac13f812ea" "53df1008cfc253d9" "3770b3227c55f2e3" "3e932096c59afd2a"]} + {:transcript " {:target :copy-root, :angle 45}\n one-of -> \n {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["ba9a6dac13f812ea" "65ca84670680dd3f" "a920758fa5650950"]} + {:transcript " {:target :copy-root, :angle 45}\n one-of -> \n {:target :main-instance, :value 80}", :states ["ba9a6dac13f812ea" "3f78d8893ed44646" "ca1b4068acd4cf89"]} + {:transcript "one-of -> \n {:target :main-root, :angle 30}\n {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["9209eb7b4ee877fa" "594405b1ecce4064" "9db6f380604b2fea"]} + {:transcript "one-of -> \n {:target :main-root, :angle 30}\n {:target :main-instance, :value 80}", :states ["9209eb7b4ee877fa" "1834062b7878fd2f" "85d3c98c7713553c"]} + {:transcript "one-of -> \n one-of -> \n {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["386e940ac63af4b1" "8f48f693ee787fec"]} + {:transcript "one-of -> \n one-of -> \n {:target :main-instance, :value 80}", :states ["a41078de929e10aa" "76237d559c31a37e"]}] + :case-o-variant-switch-keeps-override-only-where-mains-agree + [{:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :value \"b\", :pos 0}", :states ["06a5bc4ddb335b50" "a92238b23bfa5be5" "e1b0877c8e113f7d"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:variant-set \"vset\", :variant-id sync-vset-vcontainer, :count 2}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :value \"b\", :pos 0}", :states ["df9a042b9d59d699" "ef6a99bd8579dc7f" "3b1bfc8427b3963d"]}] + :case-p-redo-reapplies-edit-and-its-auto-propagation + [{:transcript " {:target :main-child, :property :fills, :value \"#ff0000\"}\n {:times 1}\n ", :states ["386e940ac63af4b1" "734ec524d88eb6bb" "386e940ac63af4b1" "8f48f693ee787fec"]}] + :case-q-detach-keeps-nested-copies-linked + [{:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["e3ad22551ca81acf" "ad94b5a8dac9a164" "d2173bc3074189df" "21b1476db99a4723"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["65f94fc95d67df78" "c43a5ccce7f8c37b" "c0d7f02d05a5e1fe"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["8b02b2c2f738633c" "a83e568f070f21a1" "53b58825ade561b6" "5985a050bd19bd23"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["48310c9847008019" "10406eeca34b9a81" "274ab7cc01bb8a4b"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["1ad84c27e54fc157" "379b8cf2adbb886b" "188a1fe421f3b46a" "897a967998b8f062"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["753b1e93ed2bcc8a" "57bc377d7bc8c268" "a9c2621352ac65b3"]}] + :case-r-update-main-reaches-other-copies + [{:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}", :states ["d1a05cf4f4adb3b2" "c3d9e1ce9620f108" "5e0773669a8f6af4" "07740b98577a6762"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}", :states ["fbb943407e1c504b" "c0f6fa5a36037ed6" "1b9ad3536aff61ab"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}", :states ["93ad055cbed493df" "13cc690952ae96bf" "614e08073846a3c5" "ed0511cd4dd61780"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}", :states ["9aab8ec6661d0fd5" "134433ada0e82669" "f8dee5e5d019d23c"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}", :states ["c663ec06e11f94b1" "383fa055dabddb40" "5a41eedd801a30bf" "da206c43563a1c85"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:component \"main\", :copy sync-main-copyhead-1}\n one-of -> \n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn}", :states ["f875c295a1942d95" "302808fd6c8a190d" "81777115be94939a"]}] + :case-s-deleted-component-copies-sync-again-after-restore + [{:transcript " {:target :copy-instance, :property :fills, :value \"#00ff00\"}\n {:target :main-instance, :property :fills, :value \"#ff0000\"}\n {:target :main-root}\n \n {:deletion #app.common.test-helpers.composable.comp.nodes.DeleteComponent{:target :main-root, :app.common.test-helpers.composable.core/id unreached}}\n {:target :main-instance, :property :fills, :value \"#0000ff\"}", :states ["4d643133f3da818c" "77b0f2567d55ba5a" "32ac1ebe1fabaa4e" "09d2d189311fe9f0" "4f2f18ae50e1edf5" "49abbb8937c58047"]} + {:transcript "one-of -> \n {:target :main-instance, :property :fills, :value \"#ff0000\"}\n {:target :main-root}\n \n {:deletion #app.common.test-helpers.composable.comp.nodes.DeleteComponent{:target :main-root, :app.common.test-helpers.composable.core/id unreached}}\n {:target :main-instance, :property :fills, :value \"#0000ff\"}", :states ["10d64018219b2998" "e487d9c92db38780" "68b8032743fd61c0" "b2a2d39e34f4a47e" "496bc5ace99aa51c"]}] + :case-t-duplicated-copy-keeps-overrides-and-link + [{:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :new-head 3}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["64eac9877e567358" "26604597e9cad9c3" "8e859271d6864c82" "4f7382fc3c2194a6"]} + {:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :new-head 3}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["2835846fce453978" "610360f000e2fe8d" "3a642606146de24e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :new-head 5}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["2207bf7373340695" "1f462381756fda84" "f49a9a5a2ccac2a0" "f6cc8ddba328c94d"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :new-head 5}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["8454aa1f2ccc4ac3" "4f0aed11d69dce8c" "13e27c38620b99ba"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :new-head 8}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["170f05fe60d794fb" "6f95a0e52dbc58f3" "1682e155232c79ff" "7e41824902c17537"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n one-of -> \n {:target #fn, :new-head 8}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["e09ce2b9958878d1" "59617d71e336c70c" "4f37d9c4a6c72163"]}] + :case-touched-copy-child-survives-main-rotation + [{:transcript " {:target :copy-root, :angle 30}\n {:target :copy-instance, :value 60}\n \n {:target :main-root, :angle 40}", :states ["6b63805de28b6fa4" "cfb4d7484a4abd78" "f4cf8a16c5457089" "fa0aab3b284e3448"]}] + :case-u-nested-copy-reaches-copies-of-the-receiving-main + [{:transcript " {:component \"outer\", :id sync-outer-component}\n {:component \"inner\", :id sync-inner-component}\n {:component \"outer\", :copy sync-outer-copyhead-0}\n {:component \"inner\", :copy sync-inner-copyhead-0}\n {:copy #fn, :into #fn, :cell nil}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["3e741919b165a9b1" "3b36d2a788757ccf" "13cc7bde13f6db61" "d2df2363c6fd87ee"]} + {:transcript " {:component \"outer\", :id sync-outer-component}\n {:component \"inner\", :id sync-inner-component}\n {:component \"outer\", :copy sync-outer-copyhead-0}\n {:component \"inner\", :copy sync-inner-copyhead-0}\n {:copy #fn, :into #fn, :cell nil}\n one-of -> \n {:target #fn, :property :fills, :value \"#0000ff\"}", :states ["3e741919b165a9b1" "20ac8b615e23f0ea" "3b80647668a43256"]}] + :case-v-new-edit-after-undo-clears-redo + [{:transcript " {:target :main-instance, :property :fills, :value \"#ff0000\"}\n {:times 1}\n {:target :main-instance, :property :fills, :value \"#00ff00\"}\n {:times 1}\n \n ", :states ["386e940ac63af4b1" "734ec524d88eb6bb" "2249ff7b4eb6cdaa" "734ec524d88eb6bb" "2249ff7b4eb6cdaa" "2249ff7b4eb6cdaa" "fb1a35e87f575e72"]}] + :case-w-undo-several-steps-over-nested-cascades + [{:transcript " {:component \"main\", :id sync-main-component}\n one-of -> \n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#aaaaaa\"}\n {:times 3}", :states ["2f6bfa0d0c065d5c" "e3ad22551ca81acf" "080a5e1b3a52e353" "4df63fbd39f111b4" "a8f6e49033b99e9e"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 0, :outer sync-main-outercomp-0}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#aaaaaa\"}\n {:times 3}", :states ["08a251a3907c6037" "3dff1bfab5a5b77d" "b5df4ace7209f759" "cd9d65b6e9e44dd4" "ddea124a9ab145f1"]} + {:transcript " {:component \"main\", :id sync-main-component}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :level 1, :outer sync-main-outercomp-1}\n {:component \"main\", :copy sync-main-copyhead-0}\n {:target #fn, :property :fills, :value \"#0000ff\"}\n {:target #fn, :property :fills, :value \"#00ff00\"}\n {:target #fn, :property :fills, :value \"#aaaaaa\"}\n {:times 3}", :states ["4220f3cd46b6b642" "180cc6a41d003bb5" "9fa58862bf863db6" "3f2266fbef201c71" "32c65c945efec2cd"]}] + :case-x-undo-before-sync-leaves-copies-unchanged + [{:transcript " {:target :main-instance, :property :fills, :value \"#ff0000\"}", :states ["734ec524d88eb6bb" "ff1fa863b88027e5"]}] + :case-y-text-override-merges-with-main-text-change + [{:transcript "one-of -> \n {:target :copy-instance, :edit :text, :value \"copy text\"}\n {:target :main-instance, :edit :text, :value \"main text\"}", :states ["1fdda10ff2de93bb" "9caff776f882850b" "cc39679f8f901c8e"]} + {:transcript "one-of -> \n {:target :copy-instance, :edit :text, :value \"copy text\"}\n {:target :main-instance, :edit :font-size, :value \"24\"}", :states ["1fdda10ff2de93bb" "b44573ca4817a1c2" "805af3e9523db814"]} + {:transcript "one-of -> \n {:target :copy-instance, :edit :font-size, :value \"32\"}\n {:target :main-instance, :edit :text, :value \"main text\"}", :states ["c5ad2b1e98811951" "ed2ffe7c84c65ffa" "50166a4e5025f6cb"]} + {:transcript "one-of -> \n {:target :copy-instance, :edit :font-size, :value \"32\"}\n {:target :main-instance, :edit :font-size, :value \"24\"}", :states ["c5ad2b1e98811951" "c75ab24b318795d7" "8896671645bb0a65"]} + {:transcript "one-of -> \n {:target :main-instance, :edit :text, :value \"main text\"}", :states ["dd9f23b4112dddae" "3bd3720125090159"]} + {:transcript "one-of -> \n {:target :main-instance, :edit :font-size, :value \"24\"}", :states ["e9f4a95ed0bdc435" "c25899d9e4b5f184"]}] + :case-z-main-child-move-reaches-copies + [{:transcript " {:target :copy-instance, :dx 7, :dy 3}\n {:target :main-instance, :dx 10, :dy 5}", :states ["8c67857e6499ceaa" "01ea149d9a397a0d" "343dd81f583f6b09"]} + {:transcript "one-of -> \n {:target :main-instance, :dx 10, :dy 5}", :states ["782a6f20c4115dca" "7f13ec2672ca35fe"]}] + :skipped-optional-keeps-the-undo-baseline + [{:transcript " {:target :main-instance, :property :fills, :value \"#ff0000\"}\n {:target :copy-instance, :property :fills, :value \"#ff0000\"}", :states ["386e940ac63af4b1" "386e940ac63af4b1" "8f48f693ee787fec"]} + {:transcript " {:target :main-instance, :property :fills, :value \"#ff0000\"}\n one-of -> ", :states ["386e940ac63af4b1" "8f48f693ee787fec"]}]} diff --git a/frontend/test/frontend_tests/composable_tests/interpreter.cljs b/frontend/test/frontend_tests/composable_tests/interpreter.cljs index 9a1fcdba87..d33f9f95c2 100644 --- a/frontend/test/frontend_tests/composable_tests/interpreter.cljs +++ b/frontend/test/frontend_tests/composable_tests/interpreter.cljs @@ -22,8 +22,10 @@ [app.common.test-helpers.composable.comp.undo-check :as uc] [app.common.test-helpers.composable.core :as tm] [app.common.test-helpers.files :as cthf] + [app.common.test-helpers.golden-master :as thgm] [app.common.test-helpers.ids-map :as cthi] [app.common.test-helpers.shapes :as cths] + [app.common.types.shape :as cts] [app.common.uuid :as uuid] [app.main.data.changes :as dch] [app.main.data.workspace :as dw] @@ -79,17 +81,27 @@ (declare uninstall!) +;; Whether shapes were WASM shape proxies before the running test. A test that +;; starts the WASM renderer leaves `cts/wasm-enabled?` on for the tests after +;; it, and a proxy leaves out the attributes that are nil or false, so the +;; cases run on shape records whatever ran before them. +(defonce ^:private wasm-shapes-before (atom nil)) + (def fixture "An `:each` fixture for tests that run the component watcher: a fresh label - map and no thumbnail rendering, and the watchers `install!` starts stopped - at the end. Its `:after` runs after an async test's `done`, so it covers - the whole test." + map, no thumbnail rendering and shapes as records (see + `wasm-shapes-before`), and the watchers `install!` starts stopped at the + end. Its `:after` runs after an async test's `done`, so it covers the + whole test." {:before (fn [] (cthi/reset-idmap!) - (install-thumbnail-noop!)) + (install-thumbnail-noop!) + (reset! wasm-shapes-before cts/wasm-enabled?) + (set! cts/wasm-enabled? false)) :after (fn [] (uninstall!) - (restore-thumbnail!))}) + (restore-thumbnail!) + (set! cts/wasm-enabled? @wasm-shapes-before))}) ;; -------------------------------------------------------------------------- ;; Operations as workspace events @@ -606,6 +618,65 @@ [op] (pr-str (dissoc (into {} op) ::tm/id))) +;; -------------------------------------------------------------------------- +;; Golden master: the store's files after each user, undo and redo step and +;; at the end of each variant (see `app.common.test-helpers.golden-master`). +;; `golden_master.edn` next to this file keeps the digests, the full lines go +;; to `tmp/golden-master-frontend/` at the repository root. Record from +;; `frontend/` with `PENPOT_GOLDEN_MASTER=record node target/tests/test.js +;; --focus frontend-tests.composable-tests.comp.sync-test`, only on purpose. +;; -------------------------------------------------------------------------- + +(def ^:private golden-digests-path "test/frontend_tests/composable_tests/golden_master.edn") + +(def ^:private golden-lines-dir "../tmp/golden-master-frontend") + +(def ^:private golden-kinds #{:user :frontend-only :undo :redo}) + +;; The states of the running variant. +(defonce ^:private golden-steps (atom [])) + +(defn- golden-recording? + [] + (= "record" (.. js/process -env -PENPOT_GOLDEN_MASTER))) + +(defn- store-files + "The current file, then the other files of the store." + [] + (let [st @st/state] + (cons (current-file) + (->> (vals (:files st)) + (remove #(= (:id %) (:current-file-id st))))))) + +(defn- golden-state + [extra] + (thgm/state-lines (store-files) extra + {:position-data? (not (features/active-feature? @st/state "render-wasm/v1"))})) + +(defn- observe-golden-step! + [] + (swap! golden-steps conj (golden-state nil))) + +(defn- golden-variant + "The golden master entry of a variant that ended with `situation` (nil when + a step failed)." + [situation] + (if situation + (let [failures (into #{} (map (juxt :phase :signature)) (uc/failures situation))] + {:transcript (thgm/transcript situation (thgm/id-names (store-files))) + :states (conj @golden-steps (golden-state {:undo-failures failures}))}) + {:transcript "the variant failed" :states []})) + +(defn- check-golden-master! + "Record or compare the golden master `variants` of the case `group`." + [group variants] + (if (golden-recording?) + (thgm/write-digests! golden-digests-path + (assoc (or (thgm/read-digests golden-digests-path) {}) + group (thgm/record-group! golden-lines-dir group variants))) + (thgm/compare-group! golden-lines-dir group variants + (get (thgm/read-digests golden-digests-path) group)))) + (defn- run-ops "Run the op units `ops` in order, each `sync-op?` one on the live file and the others as events awaited with `await-step`. Resolves with the final @@ -623,7 +694,10 @@ before (when check-step? (snapshot)) index-before (undo-index)] (if (sync-op? op) - (run-ops (run-sync-op situation op) (rest ops)) + (let [situation (run-sync-op situation op)] + (when (contains? golden-kinds kind) + (observe-golden-step!)) + (run-ops situation (rest ops))) (do (reset! step-errors []) (.then (await-step (op-events op situation) step-timeout-ms (op-ready op situation)) @@ -645,6 +719,8 @@ :else (let [situation (record-op situation op)] + (when (contains? golden-kinds kind) + (observe-golden-step!)) (cond check-step? ;; go on from the redone file, as the pure runner does @@ -729,6 +805,7 @@ [setup ops undo-check?] ;; a fresh label map per variant, as `tm/run-each` does (cthi/reset-idmap!) + (reset! golden-steps []) (let [situation (-> (setup) (assoc ::undo-check? undo-check?) (uc/with-runner :frontend) @@ -771,11 +848,14 @@ (let [variants (tm/enumerate operation) on-error @st/on-error applied (atom #{}) + group (-> (t/get-current-env) :testing-vars first meta :name keyword) + golden (atom []) judge (fn [variant] (let [made (assertions-made)] (-> (js/Promise.resolve) (.then #(run-variant setup (tm/sequence-ops variant) (uc/enabled? case-map))) (.then (fn [situation] + (swap! golden conj (golden-variant situation)) (when situation (t/testing (str "operations:\n " (tm/describe-applied situation)) (when asserter @@ -790,6 +870,7 @@ (reset! st/on-error (fn [e] (swap! step-errors conj e) (on-error e))) (-> (reduce (fn [p variant] (.then p #(judge variant))) (js/Promise.resolve) variants) (.then #(uc/check-marks-applied! case-map :frontend @applied)) + (.then #(check-golden-master! group @golden)) (.catch (fn [e] (t/report {:type :error :message "the case raised an error" :expected nil :actual e}))) (.finally (fn []