GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — [profiler] Wait for cytoscape to draw before the pixel tests read the canvas by Karakatiza666 · Pull Request #7840 · feldera/feldera

Conversation

@Karakatiza666

@Karakatiza666 Karakatiza666 commented Nov 4, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Fixes #7767.

Cause

settle() in mountDiagram.ts waited a fixed 150 ms. Cytoscape draws on animation frames, so on a busy CI runner a frame can come later and the pixel probes read the previous frame.

Fix

settle() waits 150 ms, then waits on animation frames until one frame passes without a cytoscape render event (public API). Cytoscape requests its frame callback during the previous frame, so its callback runs first in each frame. mountDiagram records the new instance before its first settle(). Only the test harness changed.

Testing

A temporary test/setup.ts change delayed whole animation frames by a random 0-400 ms and kept the callback order:

Harness Late frames Normal
old 2 and 5 of 150 failed (2 runs)
new 150/150 pass (3 runs) 150/150 pass (3 runs)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@Karakatiza666 @claude
[profiler] Wait for cytoscape to draw before the pixel tests read the…
a721263
… canvas

`settle()` waited a fixed 150 ms, but cytoscape draws on animation frames.
On a busy CI runner a frame can come later, and the pixel probes in
diagramShadows and diagramText read the previous frame. `settle()` now
also waits until a frame passes without a cytoscape `render` event.

Fixes #7767

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@Karakatiza666
Karakatiza666 requested a review from mihaibudiu November 4, 2026 21:13
mythical-fred-oss[bot]
mythical-fred-oss Bot reviewed Nov 4, 2026
View reviewed changes
Comment thread js-packages/profiler-layout/src/lib/test-support/mountDiagram.ts
Comment on lines +164 to +176
// Cytoscape requests its frame callback during the previous frame, so its callback runs before
// this one. Cytoscape emits `render` after each draw, so a frame without `render` had no draw
// pending.
let hasDrawn = false
const onRender = () => {
hasDrawn = true
}
mountedCy.on('render', onRender)
do {
hasDrawn = false
await nextFrame()
} while (hasDrawn)
mountedCy.off('render', onRender)

@mythical-fred-oss mythical-fred-oss Bot Nov 4, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug (medium): a frame with no render does not mean no draw is pending. Cytoscape's texture caches dequeue in beforeRenderCallbacks on frames that do not draw. They then request the redraw through a lodash debounce set to deqRedrawThreshold, which is 50–100 ms (setupDequeueing in cytoscape 3.33.1). The LayeredTextureCache works the same way.

I tested this. A probe stayed inside settle() for 400 ms after the loop exited and counted render events. I also delayed animation frames by a random 0–400 ms, the same way your PR testing did.

  • Idle machine: no late draws in the pixel tests.
  • Late frames: in ~20 of ~70 settles per run, cytoscape drew again after the "quiet" frame. This included node text > draws the text itself… and the selection glow > paints nothing…. Wrapping renderer().redraw showed the callers were trailingEdge (debounce) → LayeredTextureCache, plus some BRp.notify.

The tests still passed, so these redraws seem to be mostly texture refinement. Still, the comment states something that is not true, and the probes can still read a frame that is about to change. One fix is to also require a quiet stretch longer than the debounce:

let last = performance.now()
const onRender = () => { last = performance.now() }
mountedCy.on('render', onRender)
// A frame with no draw is not enough: the texture caches ask for their redraw
// from a 50-100 ms debounce, so also wait out that delay.
let frames = 0
do {
  frames++
  await nextFrame()
} while (frames < 2 || performance.now() - last < 150)
mountedCy.off('render', onRender)

Also consider try/finally around the off, and resetting mountedCy in cleanup, so a later settle() does not wait on a removed instance.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@Karakatiza666 Karakatiza666 Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed in 0f12d9c. I traced the late draws to the same chain: element texture refinement, then scheduleElementRefinement (50 ms), then the LayeredTextureCache dequeue and its redraw debounce (50 ms).

I did not use the suggested condition (150 ms since the last render). With late frames it can still exit too early: if the last draw was 400 ms ago and the next frame starts a refinement, the loop exits and the debounced redraw comes after. A refinement step only advances in a frame, so the condition counts frames:

  • settle() returns after 3 frames without a draw, each at least 120 ms after the one before (longer than the longest debounce).
  • off is in finally, and cleanup() resets mountedCy.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mythical-fred-oss

mythical-fred-oss Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Review of the test-harness-only fix for #7767

What I ran Result
bun run test-unit in profiler-layout (Chromium) 23 files, 249/249 pass
pre-commit and biome check on the changed file clean
components/ tests, idle machine, with a probe that stays in settle() 400 ms after it returns 142 of 143 settles quiet. The one late draw follows a drag in a non-pixel click test
Text, shadows, view and minimap tests with animation frames delayed 0–400 ms (same method as the PR) all pass, 3 runs. But ~20 of ~70 settles per run drew again after the quiet frame
  • Flaky-test gate, medium: this is better than the fixed 150 ms, but the end condition is still timing-dependent. Debounced texture-cache redraws arrive after the quiet frame (details inline). I'd tighten it before merge so Flaky pixel-comparison tests in profiler-layout (diagramShadows/diagramText) #7767 doesn't come back on a slower runner.
  • Not covered, low risk: there is no self-test for settle(). One option is a browser test that calls cy.zoom(), awaits settle(), then asserts no render event fires in the next 200 ms. Run it under the late-frame shim from your PR testing.

The other gates (docs, deps, breaking changes, unsafe, CI) don't apply to a test-only change.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

mihaibudiu
mihaibudiu approved these changes Nov 4, 2026
View reviewed changes
@Karakatiza666

Karakatiza666 commented Nov 5, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Addressed the review in 0f12d9c:

  • settle() waits out cytoscape's texture refinement chain (details in the inline thread).
  • New self-test src/lib/test-support/settle.test.ts: it delays animation frames by a random 0-400 ms (in browser order), zooms 3 times, and asserts that no render follows settle() within 1 s.
Harness Self-test Full browser suite
a721263 (one frame without a draw) failed 11 of 11 runs
0f12d9c passed 15 of 15 runs 151/151 pass (4 runs)

Cost: the browser suite takes about 28 s instead of 20 s locally, because each settle() now takes at least about 240 ms instead of 150 ms.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Karakatiza666
Karakatiza666 force-pushed the fix-flaky-diagram-pixel-tests branch from 0f12d9c to a721263 Compare November 5, 2026 11:54
@Karakatiza666
Karakatiza666 added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit b2af617 Nov 5, 2026
4 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@Karakatiza666
Karakatiza666 deleted the fix-flaky-diagram-pixel-tests branch November 5, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@mythical-fred-oss mythical-fred-oss[bot] mythical-fred-oss[bot] left review comments
@mihaibudiu mihaibudiu mihaibudiu approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Flaky pixel-comparison tests in profiler-layout (diagramShadows/diagramText)

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@Karakatiza666 @mihaibudiu
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.