This commit is contained in:
Olive Vaughn 2026-10-04 18:14:05 -04:00
parent 208dddee07
commit 78fb120edd
9 changed files with 102 additions and 48 deletions

View file

@ -216,10 +216,19 @@
(deftest no-symbol-is-special
(let [c (nested)]
(testing "a document opens on the longest symbol nothing places"
(testing "a document opens on its root, however long its unplaced symbols are"
(is (= [:loose :main :outer] (clip/unplaced c)))
(is (= :outer (clip/opens-on c)))
(is (= :main (clip/opens-on (clip/blank)))))
(is (= :main (clip/opens-on c)))
(is (= :main (clip/opens-on (clip/blank))))
(is (= :loose (clip/opens-on (assoc c :root :loose))))
(is (= c (leaf/clip "u" (leaf/leaves "u" c))))
(is (seq (clip/problems (assoc c :root :gone)))))
(testing "without a root, the longest symbol nothing places"
(is (= :outer (clip/opens-on (dissoc c :root)))))
(testing "a document saved before roots opens on :main, not a longer take"
(is (= :main (:root (clip/pin-root (dissoc c :root)))))
(is (= :outer (:root (clip/pin-root (-> c (dissoc :root) (update :symbols dissoc :main))))))
(is (= :loose (:root (clip/pin-root (assoc c :root :loose))))))
(testing "an instance can go into any symbol, and spans that symbol's frames"
(let [[n] (vals (get-in c [:symbols :outer :nodes]))]
(is (= #{:inner} (node/sources n)))

View file

@ -523,32 +523,32 @@ async function main() {
// same synchronous block arrives while the tool is still unset and is dropped.
// A person cannot click twice inside one microtask; a test should not either.
const armed = await page.eval(`(() => {
const button = [...document.querySelectorAll('.palette-bar button')]
.find(b => b.textContent === 'pen');
const button = document.querySelector('.toolbox button.tool[title^="Pen"]');
if (!button) return false;
button.click();
return true;
})()`);
await sleep(100);
const painted = armed && await page.eval(`(() => {
const svg = document.querySelector('.paint-overlay');
const box = svg.getBoundingClientRect();
for (const [x, y] of [[10, 10], [40, 10], [25, 40]]) {
svg.dispatchEvent(new PointerEvent('pointerdown', {
bubbles: true, clientX: box.left + x * box.width / 320,
clientY: box.top + y * box.height / 200,
}));
}
// The overlay reaches past the stage on every side, so a stage pixel is
// found through the SVG's own transform, as the stage finds it coming back.
// Each point is its own eval: a click is a re-frame event, and the next one
// reads the draft it added to.
const PEN_AT = (x, y) => `(() => {
const svg = document.querySelector('.paint-overlay.tool-pen');
if (!svg) return false;
const p = new DOMPoint(${x}, ${y}).matrixTransform(svg.getScreenCTM());
svg.dispatchEvent(new PointerEvent('pointerdown', {
bubbles: true, clientX: p.x, clientY: p.y,
}));
return true;
})()`);
await sleep(100);
const finished = await page.eval(`(() => {
const button = [...document.querySelectorAll('.palette-bar button')]
.find(b => b.textContent === 'finish');
if (!button || button.disabled) return false;
button.click();
return true;
})()`);
})()`;
let painted = armed;
for (const [x, y] of [[10, 10], [40, 10], [25, 40]]) {
painted = painted && await page.eval(PEN_AT(x, y));
await sleep(60);
}
// Closed as a person closes it: on the first point.
const finished = painted && await page.eval(PEN_AT(10, 10));
await sleep(250);
const afterPaint = await page.eval(`(() => {
const c = document.querySelector('canvas.stage');
@ -556,7 +556,8 @@ async function main() {
return [...d];
})()`);
check(painted && finished && beforePaint.join(',') !== afterPaint.join(','),
'a polygon drawn with the paint controls appears on the canvas');
'a polygon drawn with the paint controls appears on the canvas',
`${beforePaint} -> ${afterPaint}`);
for (const f of [8, 16]) {
await page.eval(SEEK(f));
await sleep(100);
@ -597,7 +598,18 @@ async function main() {
return [...c.getContext('2d').getImageData(25, 20, 1, 1).data];
})()`);
check(afterPaint.join(',') === reopenedPaint.join(','),
'the painted polygon survives the project round trip');
'the painted polygon survives the project round trip', `${afterPaint} vs ${reopenedPaint}`);
// A reopened document has nothing selected, so the shape's keys are not in
// the inspector until it is selected again, as anybody would.
await page.eval(`(() => {
const c = cljs.core, k = c.keyword;
const db = c.deref(re_frame.db.app_db);
const nodes = c.get_in(c.get(arthur.footage.store.entry(c.get(db, k('clip/current'))), k('clip')),
c.vector(k('symbols'), k('main'), k('nodes')));
const id = c.first(c.filter((id) => c.name(id).startsWith('paint-'), c.keys(nodes)));
re_frame.core.dispatch_sync(c.vector(k('arthur.events.ui/select'),
c.vector(k('node'), k('main'), id, c.vector(id))));
})()`);
await page.eval(SEEK(8));
await sleep(100);
check(await page.eval(`(() => {