mirror of
https://github.com/penpot/penpot.git
synced 2026-07-23 14:38:12 +00:00
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4ea56e0b89
|
🐛 Fix propagation of geometric changes to rotated component copies (#10574)
* 🐛 Fix geometry sync between mains and rotated component copies Rotating a copy instance as a whole marked every shape inside it as touched for geometry, so later geometric changes in the main (e.g. a resize) were no longer propagated to that copy, while non-geometric ones (e.g. fills) still were. And on paths where geometry did get written to a rotated copy (e.g. resetting overrides), the sync engine compensated only the roots' position delta, so the written values wiped the copy's rotation back to 0. Model the instance root's transformation as inherited, overridable content, asymmetric to position (which remains free per-instance placement): - An untouched copy follows the main's transformation verbatim, including rotation and flips (preserving the BUG #13267 semantics that rotating a main propagates to its copies). - Transforming a copy as a whole overrides only its ROOT: check-delta compares the root's rotation/flips absolutely, but the descendants relative to their root, so they merely follow and stay untouched. - When a copy root's geometry is overridden, update-attrs expresses the main's geometry in the copy's own frame: reposition-shape applies the roots' relative transformation (rotation/flips) around the dest root center in addition to the position delta. Geometric changes from the main then keep propagating to the rotated copy, landing correctly in its rotated frame instead of destroying its placement. Covered by the new composable test case case-n-geometry-sync-with-rotated-instances: an 8-variant sweep over optional copy rotation, optional main rotation, and one of a fills or height edit on the main child, asserting the whole model through the real workspace events (the new rotate operation dispatches dwt/increase-rotation, whose apply-modifiers step runs the check-delta classification under test; change-height dispatches dwt/update-dimensions and implements IPropertyCheck so one-of sweeps can mix property and geometry edits). Verified by temporarily reverting the fix: the case then fails with 6 assertion failures and passes again with the fix restored. Fixes #10109 AI-assisted-by: claude-fable-5 * 🐛 Fix synchronization problems --------- Co-authored-by: alonso.torres <alonso.torres@kaleidos.net> |
||
|
|
2c15dcdb84
|
✨ Add systematic component tests via a composable test model (#10529)
* ✨ Add systematic component tests via a composable test model Introduce a framework for systematically testing Penpot component behaviour (synchronisation/propagation, swaps, variant switches, nesting), plus a first suite of cases built on it. A test is expressed as a COMPOSITION OF OPERATIONS over a "situation" (an in-memory file value plus named role bindings). Operations are reified as data and composed by two combinators — `in-sequence` (threads the situation) and `one-of`/`optional` (alternatives, enumerated into concrete variants). So one written case stands for a whole matrix of variants, and coverage grows by composition rather than by copying tests. Operations drive the REAL production change pipeline, and event-operations dispatch the REAL workspace events and await settlement, so the production watcher's automatic propagation is what is exercised — the tests reflect genuine app behaviour, not a reimplementation. Structure (frontend/test/frontend_tests/composable_tests/): - core — the domain-agnostic engine: situation, the operation and enumeration protocols, the combinators, and the runners. - comp/nodes — the component operations (create/instantiate/reset, nesting, swap, the variant ops, child add/remove/move, change, undo, library sync). - comp/setups — component-shaped starting configurations. - interpreter — runs a case against the real frontend store: sync-ops apply directly, event-ops dispatch real events and await settlement (absorbing sync-file's delayed status RPC, which would otherwise leak an error into subsequent tests). - comp/sync-test — the cases (B-F, H, I, K, L, M). This is test-only code with a single consumer — the frontend test suite (the layer that runs the real app) — so it lives entirely under the frontend test tree as .cljs, not under app/common. The framework and its cases are documented in the project memory frontend/composable-component-tests, added alongside. Co-authored-by: Claude <noreply@anthropic.com> * 🐛 Guard WASM mock teardown against an empty snapshot `teardown-wasm-mocks!` unconditionally restored from the `originals` atom. When run without a matching setup (double teardown, or `with-wasm-mocks*` misused around an async test body), the snapshot is empty and every WASM API function was `set!` to nil — permanently, for the remainder of the test run. Any later code calling one of them (e.g. a leaked debounced resize-wasm-text event firing during a subsequent test namespace) then crashed with "initialized? is not a function". Make the restore a no-op when there is nothing to restore. Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |