mirror of
https://github.com/n8n-io/n8n.git
synced 2026-08-30 18:01:23 +08:00
test: Stabilize canvas zoom assertion after route changes (#36694)
Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -79,40 +79,24 @@ export class CanvasComposer {
|
||||
async zoomInAndCheckNodes(): Promise<void> {
|
||||
await this.n8n.canvas.getCanvasNodes().first().waitFor();
|
||||
|
||||
const measureFirstNodeWidth = async () =>
|
||||
await this.n8n.page.evaluate(() => {
|
||||
const firstNode = document.querySelector('[data-test-id="canvas-node"]');
|
||||
if (!firstNode) {
|
||||
throw new Error('Canvas node not found during measurement');
|
||||
}
|
||||
return firstNode.getBoundingClientRect().width;
|
||||
});
|
||||
|
||||
// Wait for the animated fit-to-view to settle before capturing the baseline.
|
||||
let previousWidth = Number.NaN;
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const width = await measureFirstNodeWidth();
|
||||
const settled = width === previousWidth;
|
||||
previousWidth = width;
|
||||
return settled;
|
||||
})
|
||||
.toBe(true);
|
||||
|
||||
const initialNodeSize = await measureFirstNodeWidth();
|
||||
// After a route change the editor runs an animated fit-to-view. Wait for the
|
||||
// viewport transform to stop moving before capturing the baseline zoom, so we
|
||||
// don't measure against a pre-animation value.
|
||||
await this.n8n.canvas.waitForCanvasZoomSettled();
|
||||
const initialZoom = await this.n8n.canvas.getCanvasZoomLevel();
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
await this.n8n.canvas.clickZoomInButton();
|
||||
}
|
||||
|
||||
// Poll the width until the animated zoom transition settles.
|
||||
// Poll the zoom scale until the animated zoom-in transition settles.
|
||||
await expect
|
||||
.poll(measureFirstNodeWidth, {
|
||||
.poll(async () => await this.n8n.canvas.getCanvasZoomLevel(), {
|
||||
message:
|
||||
"Zoom functionality not working: nodes didn't scale properly. " +
|
||||
`Initial: ${initialNodeSize.toFixed(1)}px`,
|
||||
"Zoom functionality not working: canvas didn't scale in. " +
|
||||
`Initial zoom: ${initialZoom.toFixed(3)}`,
|
||||
})
|
||||
.toBeGreaterThan(initialNodeSize * 1.5);
|
||||
.toBeGreaterThan(initialZoom * 1.5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -929,6 +929,38 @@ export class CanvasPage extends BasePage {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the canvas viewport transform (zoom/pan) to stop changing.
|
||||
* After a route change the editor runs an animated fit-to-view. Sparse
|
||||
* expect.poll sampling can catch two equal values in the pre-animation window
|
||||
* and report "settled" before the animation starts; this checks every frame
|
||||
* inside the page so it can't miss the in-flight transition.
|
||||
*/
|
||||
async waitForCanvasZoomSettled(stableFrames = 5): Promise<void> {
|
||||
await this.page.waitForFunction(
|
||||
(needed) => {
|
||||
const el = document.querySelector('.vue-flow__transformationpane.vue-flow__container');
|
||||
if (!el) return false;
|
||||
const transform = getComputedStyle(el).transform;
|
||||
const w = window as unknown as { n8nZoomSettle?: { last: string; count: number } };
|
||||
const state = (w.n8nZoomSettle ??= { last: '', count: 0 });
|
||||
if (transform === state.last) {
|
||||
state.count += 1;
|
||||
} else {
|
||||
state.last = transform;
|
||||
state.count = 0;
|
||||
}
|
||||
if (state.count >= needed) {
|
||||
delete w.n8nZoomSettle;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
stableFrames,
|
||||
{ polling: 'raf', timeout: 10_000 },
|
||||
);
|
||||
}
|
||||
|
||||
waitingForTriggerEvent() {
|
||||
return this.getExecuteWorkflowButton().getByText('Waiting for trigger event');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user