Skip to content

Releases: webdriverio/visual-testing

@wdio/visual-service@9.3.0

Choose a tag to compare

@github-actions github-actions released this 28 Jun 06:48
87903a8

Minor Changes

  • 10d34d6: chore: refresh @wdio/* deps for the v9 maintenance line

    Committers: 1

Patch Changes

  • Updated dependencies [10d34d6]
    • @wdio/image-comparison-core@1.3.0

@wdio/visual-service@10.0.0

Choose a tag to compare

@github-actions github-actions released this 28 Jun 07:00
ab672ae

Major Changes

  • d2758ce: ### 💥 Breaking change: new image comparison engine

    We replaced the engine that powers every visual comparison. This is a breaking change, so please read the migration note below before upgrading.

    The problem

    Visual tests were flaky. Tests failed on differences that are impossible to see by eye, like sub-pixel font rendering, 1px anti-aliasing on edges and small shadow shifts between runs. The old engine (resemble.js) compared raw RGB values, which does not match how human vision works, and on larger screenshots it quietly skipped about a third of the pixels. So you got failures that were not real, and in some cases real changes that could slip through.

    On top of that, all the image handling (decode, crop, composite, rotate, resize) ran through jimp, a large dependency that we only used a small slice of and that is no longer actively maintained.

    The solution

    Two things changed under the hood:

    1. The comparison engine is now pixelmatch. It compares images the way the eye perceives them (in the YIQ colour space) and detects anti-aliasing by checking both images at once. Invisible rendering noise now passes, and real regressions still fail.
    2. jimp has been removed completely. PNG decode and encode now go through the small fast-png library, and the handful of image operations we still need (crop, composite, canvas, opacity, rotate, resize) live in a tiny internal helper. The bundled resemble file is gone too. The net effect is a much lighter dependency footprint with no loss in functionality.

    What you need to do

    • Your public API does not change. checkScreen, checkElement, checkFullPageScreen and the matchers all work exactly as before, and the same ignore options are supported.
    • Because the new engine measures differences differently, mismatch percentages will not match the old numbers exactly. You should re-run your suite once and re-accept your baselines so they are generated with the new engine. After that your tests should be noticeably more stable.

    Also fixed in this release

    • Top-row artifact on full page screenshots: Jimp's contain() centred the image, shifting content by 1px and creating a false diff across the top row. Replaced with buffer-level padding that anchors content at (0,0).
    • Ignored region 1px under-coverage: The device-pixel size of an ignored region used Math.floor, which could drop a pixel when cssSize * DPR had a fractional part. Width and height now use Math.ceil so the full element is always covered. Position still uses Math.floor.
    • Comparison sensitivity matches what you were used to: Switching engines meant retuning how strict a comparison is. The pixelmatch threshold is now aligned with the old resemble tolerances, so a difference that used to fail still fails and one that used to pass still passes. The diff highlight also uses a single consistent colour instead of varying per run.
    • Different image sizes no longer crash the comparison: When a baseline and the actual screenshot had slightly different dimensions, the old flow threw an error and you lost the result. Both images are now normalised to the same size before they are compared, so a size change is reported as a visual difference you can review instead of a hard failure.
    • More reliable ignore regions with WebDriver BiDi: With BiDi the calculated element bounds can be off by a pixel or two, which sometimes left part of an ignored element just outside the ignored area and caused a false diff. The BiDi emulated flow now uses a larger ignoreRegionPadding so the whole element stays covered.

    Committers: 1

Patch Changes

  • 6cd5742: ### Dependency updates

    Updated dependencies across all packages to their latest compatible versions. This includes the WebdriverIO toolchain (webdriverio, @wdio/*) to 9.29.1, the TypeScript ESLint plugins to 8.62.0, Vitest to 3.2.6, and various other packages such as sharp, @remix-run/*, fuse.js and expect-webdriverio. There are no functional or API changes.

    Committers: 1

  • Updated dependencies [d2758ce]

  • Updated dependencies [6cd5742]

    • @wdio/image-comparison-core@2.0.0

@wdio/visual-reporter@0.4.14

Choose a tag to compare

@github-actions github-actions released this 28 Jun 07:00
ab672ae

Patch Changes

  • 6cd5742: ### Dependency updates

    Updated dependencies across all packages to their latest compatible versions. This includes the WebdriverIO toolchain (webdriverio, @wdio/*) to 9.29.1, the TypeScript ESLint plugins to 8.62.0, Vitest to 3.2.6, and various other packages such as sharp, @remix-run/*, fuse.js and expect-webdriverio. There are no functional or API changes.

    Committers: 1

@wdio/ocr-service@2.2.10

Choose a tag to compare

@github-actions github-actions released this 28 Jun 07:01
ab672ae

Patch Changes

  • 6cd5742: ### Dependency updates

    Updated dependencies across all packages to their latest compatible versions. This includes the WebdriverIO toolchain (webdriverio, @wdio/*) to 9.29.1, the TypeScript ESLint plugins to 8.62.0, Vitest to 3.2.6, and various other packages such as sharp, @remix-run/*, fuse.js and expect-webdriverio. There are no functional or API changes.

    Committers: 1

@wdio/image-comparison-core@2.0.0

Choose a tag to compare

@github-actions github-actions released this 28 Jun 07:00
ab672ae

Major Changes

  • d2758ce: ### 💥 Breaking change: new image comparison engine

    We replaced the engine that powers every visual comparison. This is a breaking change, so please read the migration note below before upgrading.

    The problem

    Visual tests were flaky. Tests failed on differences that are impossible to see by eye, like sub-pixel font rendering, 1px anti-aliasing on edges and small shadow shifts between runs. The old engine (resemble.js) compared raw RGB values, which does not match how human vision works, and on larger screenshots it quietly skipped about a third of the pixels. So you got failures that were not real, and in some cases real changes that could slip through.

    On top of that, all the image handling (decode, crop, composite, rotate, resize) ran through jimp, a large dependency that we only used a small slice of and that is no longer actively maintained.

    The solution

    Two things changed under the hood:

    1. The comparison engine is now pixelmatch. It compares images the way the eye perceives them (in the YIQ colour space) and detects anti-aliasing by checking both images at once. Invisible rendering noise now passes, and real regressions still fail.
    2. jimp has been removed completely. PNG decode and encode now go through the small fast-png library, and the handful of image operations we still need (crop, composite, canvas, opacity, rotate, resize) live in a tiny internal helper. The bundled resemble file is gone too. The net effect is a much lighter dependency footprint with no loss in functionality.

    What you need to do

    • Your public API does not change. checkScreen, checkElement, checkFullPageScreen and the matchers all work exactly as before, and the same ignore options are supported.
    • Because the new engine measures differences differently, mismatch percentages will not match the old numbers exactly. You should re-run your suite once and re-accept your baselines so they are generated with the new engine. After that your tests should be noticeably more stable.

    Also fixed in this release

    • Top-row artifact on full page screenshots: Jimp's contain() centred the image, shifting content by 1px and creating a false diff across the top row. Replaced with buffer-level padding that anchors content at (0,0).
    • Ignored region 1px under-coverage: The device-pixel size of an ignored region used Math.floor, which could drop a pixel when cssSize * DPR had a fractional part. Width and height now use Math.ceil so the full element is always covered. Position still uses Math.floor.
    • Comparison sensitivity matches what you were used to: Switching engines meant retuning how strict a comparison is. The pixelmatch threshold is now aligned with the old resemble tolerances, so a difference that used to fail still fails and one that used to pass still passes. The diff highlight also uses a single consistent colour instead of varying per run.
    • Different image sizes no longer crash the comparison: When a baseline and the actual screenshot had slightly different dimensions, the old flow threw an error and you lost the result. Both images are now normalised to the same size before they are compared, so a size change is reported as a visual difference you can review instead of a hard failure.
    • More reliable ignore regions with WebDriver BiDi: With BiDi the calculated element bounds can be off by a pixel or two, which sometimes left part of an ignored element just outside the ignored area and caused a false diff. The BiDi emulated flow now uses a larger ignoreRegionPadding so the whole element stays covered.

    Committers: 1

Patch Changes

  • 6cd5742: ### Dependency updates

    Updated dependencies across all packages to their latest compatible versions. This includes the WebdriverIO toolchain (webdriverio, @wdio/*) to 9.29.1, the TypeScript ESLint plugins to 8.62.0, Vitest to 3.2.6, and various other packages such as sharp, @remix-run/*, fuse.js and expect-webdriverio. There are no functional or API changes.

    Committers: 1

@wdio/image-comparison-core@1.3.0

Choose a tag to compare

@github-actions github-actions released this 28 Jun 06:48
87903a8

Minor Changes

  • 10d34d6: chore: refresh @wdio/* deps for the v9 maintenance line

    Committers: 1

@wdio/visual-service@9.2.4

Choose a tag to compare

@github-actions github-actions released this 23 Jun 04:24
d74fdd5

Patch Changes

  • 60997df: fix: prevent false emulation detection when checkElement is called inside an iframe after switchFrame

    Committers: 1

  • Updated dependencies [60997df]

    • @wdio/image-comparison-core@1.2.4

@wdio/image-comparison-core@1.2.4

Choose a tag to compare

@github-actions github-actions released this 23 Jun 04:24
d74fdd5

Patch Changes

  • 60997df: fix: prevent false emulation detection when checkElement is called inside an iframe after switchFrame

    Committers: 1

@wdio/visual-service@9.2.3

Choose a tag to compare

@github-actions github-actions released this 31 May 16:45
33951d5

Patch Changes

  • c56e1ae: ## #1146 Fix BiDi element screenshots missing composited layers (scrollbars, fixed/sticky overlays)

    Root cause

    When checkElement / saveElement is used with the WebDriver BiDi protocol, the screenshot was taken with browsingContext.captureScreenshot using origin: 'document'. This renders the document layout independently of the browser's compositor, which means composited layers are never included — element-level scrollbars, position: fixed / position: sticky overlays, and elements with a will-change CSS property all render as invisible or without their correct visual state.

    The switch to origin: 'document' was introduced in an earlier fix (commit 227f10a) to avoid a zero dimensions error that occurred when origin: 'viewport' was used for elements that were outside the visible viewport. That fix was correct for out-of-viewport elements, but it also silently broke composited-layer capture for all elements.

    Fix: new biDiOrigin method option

    A new method-level option biDiOrigin has been added to saveElement / checkElement. It is BiDi-only and ignored for the legacy WebDriver screenshot path.

    Value Behaviour
    'document' (default) Previous behaviour — works for any element position but composited layers (scrollbars, overlays, will-change) are not captured
    'viewport' Captures the composited frame as the browser painted it — scrollbars, fixed/sticky overlays and will-change layers are included. The element must be visible in the viewport; descriptive errors are thrown when it is not

    Usage

    // Capture an element with its scrollbar / overlay visible:
    await browser.checkElement(element, "myTag", { biDiOrigin: "viewport" });
    await browser.saveElement(element, "myTag", { biDiOrigin: "viewport" });

    Error messages when biDiOrigin: 'viewport' cannot produce a valid screenshot

    Element larger than the viewport — must fall back to 'document':

    [BiDi viewport screenshot] The element dimensions (1400x800px) exceed the viewport (1280x720px).
    You must use the default `biDiOrigin: 'document'` for this element.
    Note: with `'document'` origin, composited layers such as scrollbars, fixed/sticky overlays,
    and elements using `will-change` may not appear in the screenshot.
    

    Element not in the viewport at all — needs scrolling:

    [BiDi viewport screenshot] The element is not in the viewport
    (element: x=0, y=900, 300x200px; viewport: 1280x720px).
    Call `element.scrollIntoView()` before taking the screenshot, or set `autoElementScroll: true`.
    

    Element partially outside the viewport but fits — needs to be scrolled fully into view:

    [BiDi viewport screenshot] The element is not fully visible in the viewport
    (element: x=-20, y=100, 300x200px; viewport: 1280x720px).
    The element fits within the viewport — scroll it fully into view by calling
    `element.scrollIntoView()` or setting `autoElementScroll: true`.
    

    Committers: 1

  • Updated dependencies [c56e1ae]

    • @wdio/image-comparison-core@1.2.3

@wdio/image-comparison-core@1.2.3

Choose a tag to compare

@github-actions github-actions released this 31 May 16:45
33951d5

Patch Changes

  • c56e1ae: ## #1146 Fix BiDi element screenshots missing composited layers (scrollbars, fixed/sticky overlays)

    Root cause

    When checkElement / saveElement is used with the WebDriver BiDi protocol, the screenshot was taken with browsingContext.captureScreenshot using origin: 'document'. This renders the document layout independently of the browser's compositor, which means composited layers are never included — element-level scrollbars, position: fixed / position: sticky overlays, and elements with a will-change CSS property all render as invisible or without their correct visual state.

    The switch to origin: 'document' was introduced in an earlier fix (commit 227f10a) to avoid a zero dimensions error that occurred when origin: 'viewport' was used for elements that were outside the visible viewport. That fix was correct for out-of-viewport elements, but it also silently broke composited-layer capture for all elements.

    Fix: new biDiOrigin method option

    A new method-level option biDiOrigin has been added to saveElement / checkElement. It is BiDi-only and ignored for the legacy WebDriver screenshot path.

    Value Behaviour
    'document' (default) Previous behaviour — works for any element position but composited layers (scrollbars, overlays, will-change) are not captured
    'viewport' Captures the composited frame as the browser painted it — scrollbars, fixed/sticky overlays and will-change layers are included. The element must be visible in the viewport; descriptive errors are thrown when it is not

    Usage

    // Capture an element with its scrollbar / overlay visible:
    await browser.checkElement(element, "myTag", { biDiOrigin: "viewport" });
    await browser.saveElement(element, "myTag", { biDiOrigin: "viewport" });

    Error messages when biDiOrigin: 'viewport' cannot produce a valid screenshot

    Element larger than the viewport — must fall back to 'document':

    [BiDi viewport screenshot] The element dimensions (1400x800px) exceed the viewport (1280x720px).
    You must use the default `biDiOrigin: 'document'` for this element.
    Note: with `'document'` origin, composited layers such as scrollbars, fixed/sticky overlays,
    and elements using `will-change` may not appear in the screenshot.
    

    Element not in the viewport at all — needs scrolling:

    [BiDi viewport screenshot] The element is not in the viewport
    (element: x=0, y=900, 300x200px; viewport: 1280x720px).
    Call `element.scrollIntoView()` before taking the screenshot, or set `autoElementScroll: true`.
    

    Element partially outside the viewport but fits — needs to be scrolled fully into view:

    [BiDi viewport screenshot] The element is not fully visible in the viewport
    (element: x=-20, y=100, 300x200px; viewport: 1280x720px).
    The element fits within the viewport — scroll it fully into view by calling
    `element.scrollIntoView()` or setting `autoElementScroll: true`.
    

    Committers: 1