Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for an application-owned readiness signal, not merely for the Konva container to appear. Konva shapes are painted into canvas pixels, so Playwright can confirm that a DOM wrapper is visible without proving that the requested scene has been drawn. Set a marker such as data-render-state="ready" only after React state, required images or fonts, and any application-controlled drawing work are complete; then wait for that marker and capture the locator.

The reliable synchronization pattern

A robust test has four phases: navigate, trigger the scene change, wait for the app’s readiness contract, and take the screenshot.

await page.goto('/editor');
await page.getByRole('button', { name: 'Render preview' }).click();
await page.waitForFunction(() =>
  document.querySelector('[data-testid="preview"]')?.getAttribute('data-render-state') === 'ready'
);
await page.locator('[data-testid="preview"]').screenshot({ path: 'preview.png' });

The marker is illustrative. Your application must set it only after the requested Konva scene is applied and its dependencies are ready. data-testid belongs to an application-owned DOM wrapper; it is not a selector for a Konva shape.

Playwright’s page.waitForFunction() polls a predicate in the page and uses requestAnimationFrame polling by default. See the Page API. A locator assertion can express the same contract:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await expect(page.locator('[data-testid="preview"]'))
  .toHaveAttribute('data-render-state', 'ready');

Use a real browser for appearance checks. Konva’s testing guidance explains that questions such as whether a shape has the right color require real pixels, not just DOM assertions: Konva’s React testing guide.

Why a visible Stage is not enough

React-Konva renders a canvas-backed Stage. Individual rectangles, text nodes, and images are not ordinary DOM elements that Playwright can query. A Stage wrapper may be present while React is still committing state, an image is still loading, or a custom drawing source has not updated.

locator.screenshot() performs actionability checks and scrolls the target into view before capturing its visible bounds (Locator API). Those checks answer “can I capture this DOM target?” They do not answer “does this canvas contain the intended frame?”

Likewise, a screenshot that is merely stable can be wrong. Playwright’s toHaveScreenshot() waits for two consecutive screenshots to match before comparing with the expectation (LocatorAssertions API), but a blank or stale canvas can also be stable. Pair pixel stability with a semantic readiness signal.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Design an application-owned readiness contract

Expose state on a wrapper

Put a marker on a normal DOM element surrounding the Stage. Typical states are idle, loading, ready, and error. Include a generation or scene identifier when several renders can be requested quickly.

function Preview({ scene }) {
  const [renderState, setRenderState] = useState('loading');
  const [generation, setGeneration] = useState(0);

  useEffect(() => {
    let cancelled = false;
    setRenderState('loading');
    const nextGeneration = generation + 1;
    setGeneration(nextGeneration);

    (async () => {
      try {
        await scene.assetsReady;       // images, fonts, or other app data
        if (cancelled) return;
        // Update Konva/React scene here. If drawing is custom, finish it here.
        setRenderState('ready');
      } catch {
        if (!cancelled) setRenderState('error');
      }
    })();

    return () => { cancelled = true; };
  }, [scene]);

  return (
    <div
      data-testid="preview"
      data-render-state={renderState}
      data-render-generation={generation}
    >
      <Stage width={800} height={600}>{/* layers and shapes */}</Stage>
    </div>
  );
}

In production code, keep the generation in a ref or derive it from the scene request so that overlapping effects cannot mark an older request ready after a newer one. The important property is ownership: the application, not a guessed delay, declares when the requested scene is complete.

Wait for assets that affect pixels

Images introduce an asynchronous boundary. The official React-Konva image example loads an image with use-image before passing it to an Image node (Konva image example). Include image completion—and any font, data, or texture work your scene needs—in the readiness contract. Do not mark ready merely because an Image component has mounted.

Account for custom drawing sources

Konva’s automatic redraw behavior applies to normal Konva attribute changes. Since Konva 8, attribute changes mark a layer dirty and schedule a redraw on the next animation frame in the standard auto-draw configuration (Konva automatic redraws). Calling draw() or batchDraw() after every ordinary state change is therefore usually redundant.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Manual work is still relevant when pixels come from a mutable source canvas or video frame, when drawing occurs outside Konva’s awareness, or when Konva.autoDrawEnabled is disabled. Check the installed Konva version and your configuration. If you make such changes, complete that work before setting the readiness marker.

Playwright test examples

Wait with a page predicate and capture

import { test, expect } from '@playwright/test';

test('captures the rendered preview', async ({ page }) => {
  await page.goto('/editor');
  await page.getByRole('button', { name: 'Render preview' }).click();

  await page.waitForFunction(() => {
    const el = document.querySelector('[data-testid="preview"]');
    return el?.getAttribute('data-render-state') === 'ready';
  });

  const preview = page.locator('[data-testid="preview"]');
  await preview.screenshot({ path: 'test-results/preview.png' });
});

Give the wait a timeout appropriate to your app and surface a useful error rather than silently capturing a failed render:

await page.waitForFunction(
  () => document.querySelector('[data-testid="preview"]')?.getAttribute('data-render-state') === 'ready',
  { timeout: 15_000 }
);

Use screenshot assertions for visual regression

await expect(page.locator('[data-testid="preview"]'))
  .toHaveScreenshot('preview.png', { animations: 'disabled' });

The animations: 'disabled' option controls CSS animations, CSS transitions, and Web Animations. It does not stop a Konva animation loop. If Konva nodes animate, pause the animation or set a deterministic frame in application code before exposing ready.

Read pixels when the test needs a direct signal

For a pixel-level diagnostic, use the real browser and the layer context. Konva’s guide demonstrates pixel readback while accounting for the layer’s pixel ratio (testing react-konva components). This can verify a known coordinate or color, but it should complement—not replace—the app readiness contract.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What each waiting approach actually proves

Approach What it proves What it cannot prove
DOM visibility or locator actionability The wrapper is attached, visible, and capturable. That Konva pixels show the requested scene.
Fixed waitForTimeout() Only that an arbitrary interval elapsed. Readiness on slow runs, and it wastes time on fast runs.
Application readiness marker Your app’s declared state, including assets and scene generation. Correctness if the marker is set too early or the scene logic is wrong.
toHaveScreenshot() stabilization Two successive captures are visually identical before comparison. Semantic correctness; blank and stale canvases can be stable.
Pixel readback The browser produced expected pixels at selected coordinates. Unexamined regions or the meaning of those pixels without app context.

Why fixed delays and frame waits fail

A fixed waitForTimeout(1000) can be too short when a network image or data request is slow and unnecessarily long when the scene is ready immediately. A one-frame delay is valid only when the application’s contract is specifically “the next browser frame”; it cannot stand in for asynchronous assets, effects, or a server response. Wait for the event that makes this scene ready.

Animated scenes and deterministic captures

Decide whether the screenshot represents a static state or a particular animation frame. For a static baseline, stop the Konva animation loop, set a known timestamp or frame index, then mark the generation ready. For an intentionally animated capture, define the frame in the test and wait for that application signal. Playwright’s CSS animation controls do not govern Konva’s JavaScript animation loop.

Troubleshooting timeouts and mismatches

The readiness wait times out

  • Inspect the wrapper’s data-render-state and any error message in a trace or debug log.
  • Verify that the scene’s image, font, and data promises resolve and that rejected promises set error instead of leaving loading forever.
  • Check that a newer scene request has not cancelled the effect for the request under test.
  • Use a longer timeout only after fixing the contract; do not convert timeout into an unconditional screenshot.

The screenshot is blank or stale

  • Ensure the marker is set after the state update that creates the Konva nodes and after required assets load.
  • Look for mutable canvases, video frames, disabled auto-draw, or custom drawing outside Konva’s normal change tracking.
  • Confirm the test waits for the correct generation when users can trigger multiple renders.

Pixels differ between runs

  • Freeze Konva animation and control time-dependent data.
  • Use stable viewport, device scale, fonts, timezone, and locale settings.
  • Use toHaveScreenshot() for repeatability, but retain the semantic readiness check.

The target is clipped

locator.screenshot() captures the target’s visible bounds after scrolling it into view. Make the wrapper dimensions explicit and choose a full-page or element capture intentionally; clipping is a geometry issue, not proof of render completion.

Performance, reliability, and cost considerations

Event-based readiness avoids sleeping through every test and reduces false failures caused by variable load times. Keep the marker local to the scene under test so unrelated page work does not delay capture. A generation value makes retries diagnosable and prevents stale asynchronous work from winning a race.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use screenshot assertions only where visual evidence is needed; they require image comparison and can be slower than a focused state assertion. When debugging, record the readiness state, generation, asset status, and browser configuration alongside the screenshot. There is no universal Konva await renderComplete() API; the correct signal depends on your React effects, assets, custom drawing sources, and animation policy.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. For a URL that can render independently, one GET request returns PNG, JPEG, WebP, or PDF. Its capture pipeline accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and whether the request was billed.

See the ScreenshotNeo API documentation for parameters such as full-page capture, element selectors, device and viewport settings, retina scale, custom CSS or JavaScript, waits for selectors, delays or network idle, request blocking, headers, cookies, user agents, timezone and geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture, usage data, and PDF options.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is on every plan. These captures do not replace an in-app readiness contract for a live Konva editor, but they can remove browser orchestration when the page itself is the only target.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a free ScreenshotNeo account to use the 1,000 monthly screenshots without a card.

FAQ

Can I wait for a Konva shape with a CSS or DOM selector?

No. Shapes are canvas output rather than individual DOM nodes. Select an application-owned wrapper or expose a readiness marker and verify appearance with browser pixels.

Should I call layer.draw() before every screenshot?

Usually not with Konva 8 or newer and normal automatic redraw enabled. It can matter for drawing changes outside Konva’s tracking or when auto-draw is disabled.

Is one successful screenshot enough to prove rendering?

No. A screenshot can be stable while blank or stale. Combine a meaningful application signal with the visual assertion or pixel check required by the test.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

What should the readiness marker contain?

Use an application-owned state such as data-render-state="ready", and include a scene generation when renders can overlap.

Does Playwright’s default screenshot wait detect image loading inside Konva?

No. Actionability and visibility checks target the DOM wrapper. Your readiness contract must include all images and other assets that affect canvas pixels.

The Bottom Line

Make the app declare when the requested Konva scene is ready, wait for that state in Playwright, then capture or compare real browser pixels. Delays and screenshot stability alone cannot establish semantic render completion.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.