Conversation
The bridge gains an expectScreenshot command for pages and locators. It calls page._expectScreenshot(), the private method behind @playwright/test's toHaveScreenshot(): screenshots until two consecutive ones match, masks, then pixelmatch or ssim-cie94. The bridge applies the defaults the JS runner adds on its side (animations disabled, caret hidden, CSS scale). Images travel base64 encoded, masks as selectors rebuilt into locators, frames included. Page::expectScreenshot() and Locator::expectScreenshot() expose it as @internal methods returning a ScreenshotComparison. PageInterface and LocatorInterface are left untouched: downstream test doubles implement them.
toHaveScreenshot() on page and locator assertions, and on expect() in test cases, compares a stable screenshot with a baseline image, as in @playwright/test: - Baselines live next to the test file, <Test>.php-snapshots/, named after the browser of the page under test and the platform: card-chromium-linux.png. PNG by default, lossless WebP with .webp. - PLAYWRIGHT_UPDATE_SNAPSHOTS takes the --update-snapshots values: none, missing (default), changed, all. "all" records without comparing. - A failure writes card-expected, card-actual and card-diff to test-failures/<TestClass>-<testMethod>-<browser>/, removed once the baseline matches or is recorded again. - ToHaveScreenshotOptions carries the @playwright/test defaults and rejects invalid values on construction.
A guide on why and where to compare screenshots (a defensive test on the design system and precious pages), how baselines are named, updated and reviewed, failure images, PNG and WebP, options, headless mode and limits.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Empty baselines can pass incorrectly, stale artifacts can persist, and several path, locator, and portability cases remain broken.
Review effort: Balanced
Findings: 1
Open (5)
What changed in this PR
Adds visual regression assertions for pages and locators, backed by Playwright’s screenshot comparator.
Changes:
- Adds PNG/WebP screenshot comparison, update modes, masks, tolerances, and failure artifacts.
- Integrates assertions with PHPUnit tracing, snapshot paths, and browser/platform variants.
- Adds documentation and unit/functional coverage.
| File | Description |
|---|---|
bin/lib/handlers.js |
Bridges screenshot comparisons to Playwright. |
src/Assertions/Internal/AbstractAssertions.php |
Supports non-polled assertions. |
src/Assertions/Internal/ScreenshotExpectation.php |
Manages baselines and artifacts. |
src/Assertions/LocatorAssertions.php |
Adds locator screenshot assertions. |
src/Assertions/LocatorAssertionsInterface.php |
Exposes the locator API. |
src/Assertions/Options/ToHaveScreenshotOptions.php |
Defines and validates options. |
src/Assertions/PageAssertions.php |
Adds page screenshot assertions. |
src/Assertions/PageAssertionsInterface.php |
Exposes the page API. |
src/Locator/Locator.php |
Sends locator comparison commands. |
src/Page/Page.php |
Sends page comparison commands. |
src/Screenshot/ScreenshotComparison.php |
Models comparison results. |
src/Testing/Expect.php |
Resolves snapshot paths and variants. |
src/Testing/ExpectDecorator.php |
Counts screenshot assertions. |
src/Testing/ExpectInterface.php |
Exposes the testing API. |
src/Testing/PlaywrightTestCaseTrait.php |
Configures baseline and output directories. |
tests/Functional/Screenshot/ToHaveScreenshotTest.php |
Exercises browser-level behavior. |
tests/Unit/Assertions/Internal/ScreenshotExpectationTest.php |
Tests baseline lifecycle. |
tests/Unit/Assertions/LocatorAssertionsTest.php |
Tests locator integration. |
tests/Unit/Assertions/Options/ToHaveScreenshotOptionsTest.php |
Tests option validation. |
tests/Unit/Assertions/PageAssertionsTest.php |
Tests page integration. |
tests/Unit/Locator/LocatorTest.php |
Tests locator transport behavior. |
tests/Unit/Page/PageTest.php |
Tests page transport behavior. |
tests/Unit/Screenshot/ScreenshotComparisonTest.php |
Tests response decoding. |
tests/Unit/Testing/ExpectFactoryTest.php |
Tests paths and PHPUnit integration. |
docs/guide/assertions-reference.md |
Lists the new assertions. |
docs/guide/visual-regression.md |
Documents visual regression workflows. |
CHANGELOG.md |
Announces the feature. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+208
to
+213
| try { | ||
| $page = $subject instanceof LocatorInterface ? $subject->page() : $subject; | ||
|
|
||
| return $page->context()->browser()?->browserType()->value ?? ''; | ||
| } catch (RuntimeException) { | ||
| return ''; |
| */ | ||
| private function writeArtifacts(string $path, string $expected, ScreenshotComparison $result): array | ||
| { | ||
| $stem = $this->artifactStem($path); |
Comment on lines
+191
to
+193
| if (str_starts_with($name, '/') || 1 === preg_match('~^[a-zA-Z]:[\\\\/]~', $name)) { | ||
| return $name; | ||
| } |
Comment on lines
+417
to
+419
| if (0 === posix_geteuid()) { | ||
| $this->markTestSkipped('Root reads files whatever their permissions.'); | ||
| } |
| * Rebinds $this->locator to the '.items' selector used by the filter and | ||
| * combinator tests, which need a different base selector than setUp(). | ||
| */ | ||
| public function testExpectScreenshotSendsTheBaselineAndOptions(): void |
- An empty baseline reached Playwright as "no baseline" and matched any screenshot. It now fails with a clear message, and is recorded again in the changed and all modes. The bridge sends any string it receives. - A failure removes the images of the previous one, so a diff from an earlier mismatch never sits next to a later timeout. - Locator::normalize() keeps the page of the locator, so a normalized locator names its baselines after the browser too. - UNC paths (\\server\share\card.png) are absolute snapshot paths. - The unreadable baseline test skips without POSIX permissions. - The useItemsLocator() docblock is back on its helper.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.



Add
toHaveScreenshot()for pages and locators, using Playwright's comparator and screenshot stabilization.Notes:
_expectScreenshot()API.