✨ 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
This commit is contained in:
alonso.torres 2026-10-14 00:47:28 +02:00
parent 1dcae42878
commit 90a64592c1
10 changed files with 1009 additions and 37 deletions

View File

@ -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/<n>` in tree order, grid cells `:cell/<shape>.<row>.<col>`,
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 <ns>`; 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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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/<n>`, numbered in tree order (pages in order,
each from its root; components by label, each from its main), and each
grid cell by `:cell/<shape>.<row>.<column>`. 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 <dir>/recorded <dir>/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/<shape>.<row>.<column>`."
[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/<n>` 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 `<dir>/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 `<dir>/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))))))))

View File

@ -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]

View File

@ -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"]}]}

View File

@ -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))))))

View File

@ -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"]}]}

View File

@ -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 []