Files
houseplan-card/demo/smoke_mode_transition.mjs
T

65 lines
2.6 KiB
JavaScript

// #101: View/editor navigation has one controller for toolbar height, stage
// geometry and camera. This smoke deliberately observes real animation frames;
// it never asserts an exact wall-clock millisecond.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 820, height: 760 });
const result = await page.evaluate(async () => {
const card = window.__card;
const root = () => card.shadowRoot || card.renderRoot;
const sleepFrame = () => new Promise((resolve) => requestAnimationFrame(resolve));
const sampleUntilSettled = async () => {
const samples = [];
const started = performance.now();
do {
await sleepFrame();
const stage = root().querySelector('.stage');
const svg = stage?.querySelector(':scope .zoomwrap > svg');
if (stage && svg) {
const vb = svg.viewBox.baseVal;
samples.push({
busy: card._modeTransitionBusy,
inert: stage.inert,
height: stage.getBoundingClientRect().height,
aspect: vb.width / vb.height,
stageAspect: stage.clientWidth / stage.clientHeight,
});
}
} while (card._modeTransitionBusy && performance.now() - started < 1000);
return samples;
};
await card.updateComplete;
card._setMode('view');
await card.updateComplete;
const viewHeight = root().querySelector('.stage').clientHeight;
card._setMode('plan');
const enter = await sampleUntilSettled();
const planHeight = root().querySelector('.stage').clientHeight;
const distinctEnterHeights = new Set(enter.map((sample) => Math.round(sample.height))).size;
card._setMode('devices');
const swap = await sampleUntilSettled();
const chromeInner = root().querySelector('.editorchrome-inner');
card._setMode('view');
const leave = await sampleUntilSettled();
const restoredHeight = root().querySelector('.stage').clientHeight;
const allFrames = [...enter, ...swap, ...leave];
return {
enterHadIntermediateGeometry: distinctEnterHeights >= 3,
editorConsumesViewportHeight: planHeight < viewHeight,
stageInertDuringMotion: allFrames.filter((sample) => sample.busy).every((sample) => sample.inert),
cameraMatchesEveryStageAspect: allFrames.every((sample) =>
Number.isFinite(sample.aspect) && Math.abs(sample.aspect - sample.stageAspect) < 0.02),
editorSwapUsesSharedTimeline: swap.some((sample) => sample.busy) && !!chromeInner,
viewHeightRestored: Math.abs(restoredHeight - viewHeight) <= 2,
controllerSettled: card._modeTransitionBusy === false
&& !root().querySelector('.stage').classList.contains('mode-transition'),
};
});
checkAll(result);
await finish(browser, result);