Skip to content

test: port the upstream page and library tests - #2024

Merged
Yury Semikhatsky (yury-s) merged 93 commits into
microsoft:mainfrom
yury-s:upstream-tests
Oct 28, 2026
Merged

Yury Semikhatsky (yury-s) merged 93 commits into
microsoft:mainfrom
yury-s:upstream-tests

Conversation

@yury-s

@yury-s Yury Semikhatsky (yury-s) commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Port the upstream tests of tests/page and tests/library to playwright/src/test/java/com/microsoft/playwright/tests, one class per spec file. Each test has the title and the identifier of the upstream test.
  • upstream_registry.md is the upstream test registry at the commit in upstream_base.txt. scripts/check_test_registry.py checks that each test is ported or is in upstream_not_ported.txt with a reason.
  • Add the harness that the ports need: test servers, proxy and SOCKS servers, the remote server and child process utilities, the image comparator and @Fixme.
  • Fix client bugs that the ports found: the driver of each Playwright instance gets the env of that instance, close errors after a route are ignored, and the navigation waits fail at once on a closed page, like the Node.js client. The traces collect the sources of the ported test classes. The other fixes landed in fix(browser): list contexts in creation order from browser.contexts() #2018 to fix(tracing): title the waits in the trace like the Node.js client #2023.

Tests not yet ported

3342 of the 4936 upstream tests are ported. The other 1594 are in upstream_not_ported.txt.

Keep listed as not ported

Category Tests Why it stays
Node.js client and driver internals 541 Unit tests, parsers, locator generators, EventEmitter, heap, private methods
Driver tools 368 The trace viewer, codegen, the Inspector and the debug controller run in the driver
API that Java does not have by design 152 The docs give it to other languages only: service workers, coverage, devices, launchServer, the behavior option of unrouteAll
Concurrent calls 120 A call while another call is pending, which the synchronous Java client can not do
Test runner features 113 Generic matchers and snapshots of @playwright/test
JavaScript-only values and options 71 Function arguments, exposeFunctions, AbortSignal, arrays that mix strings and RegExp
Server internals through toImpl 52 The slow-motion tests patch the server, and the rest read server objects
Typed API and other language limits 40 Invalid enum values, numbers where Java takes a String, error.stack, Node.js error fields
Server test hooks 33 Hook functions that only an in-process server can receive
HTTP/2 server and WebP decoding 8 Each one needs a new, large test dependency
Node.js packaging 4 Package import checks

To port next

Group Tests What it needs
Multi-client and signals 26 Nothing new: the remote server fixtures support a shared browser and SIGINT
Test server and screenshot comparison 12 Nothing new: the test server has status messages, headers with several values, chunked bodies and the close event of a connection, and the image comparator has comparePNGs
locator.within 1 Nothing new: the Java API has it now
Page crash 8 Chromium only, with a navigation to chrome://crash; Firefox and WebKit stay listed
Multipart uploads 9 A small multipart parser in the test server
Driver environment 3 A second Playwright instance whose driver gets the environment variable
Video frames 19 Run the ffmpeg from the browser cache and read the PNG frames, as the upstream helper does
Trace titles and stacks 12 The title format of the trace model, added to the existing trace parser
Paused request body 1 req.pause() on the test server, which now reads the whole body before the route runs
pageErrors filter 1 The filter option in the Java API: the docs give it to Java, the Java client does not have it

Reasons to correct

  • The blocking-call entries, PA-034, PO-005 and WO-003 say "TODO harness", but they describe concurrent calls. They should say java: concurrent.
  • The toImpl entries say "TODO harness", but a Java test can never reach the in-process server. They should get a permanent reason, and so should CR-043 and CR-044, which call a private method.
  • The reasons of the multi-client, signal, test server, screenshot comparison and locator.within tests are out of date.
  • FF-004 waits for a driver bug fix. Check it again on the next driver roll.

…rary tests

A test server with the Node.js request and response shapes, WebSocket support
and the upstream certificate; the testInfo, contextFactory, launchPersistent,
createUserDataDir and pageWithHar fixtures; the utils of tests/config; the
upstream assets, golden screenshots and test registry; a checker that every
registry entry is ported or listed as not ported; @fixme for strict expected
failures; Surefire reports named after the upstream test titles. Three spec
files are ported as examples, under the rules of src/test/AGENTS.md.
…stry

The registry shows the describe path and markdown escapes around the title.
…p, page-dispatchevent, page-dialog, page-expose-function, elementhandle-bounding-box, elementhandle-click
…st, network-post-data, page-set-extra-http-headers, page-basic, page-set-content, page-transition, page-event-popup, queryselector, retarget
…electors-register, page-strict, page-select-option, page-screenshot, page-localstorage, page-cache-storage, page-wait-for-function
…filechooser, firefox-network-response, page-fill, page-focus, frame-evaluate, frame-frame-element
…se the client

Threads blocked in Playwright calls polled and dispatched messages concurrently,
so a response could be dispatched before the __create__ of the object it
names, failing with "Object doesn't exist". A fair lock around poll+dispatch
and around sending keeps the order; the object and callback maps are concurrent.
…, locator-list, locator-misc-*, locator-query, locator-wait-for-function, page-mouse, wheel, page-goto, page-navigation, page-history, page-event-load
…-script*, jshandle-*, page-keyboard, page-add-locator-handler, locator-any-frame, locator-click, locator-convenience, locator-element-handle, locator-evaluate
…page-wait-for-navigation, page-wait-for-url, page-wait-for-response, workers
…,pages,page-event}, browser, browser-server, browsertype-basic, browsertype-launch, launcher, beforeunload, capabilities, modernizr, client-certificates
…ne-id,user-agent,viewport,service-worker-policy}, video, webmcp*, shared-worker, web-socket, route-web-socket
The wait info sent for waitForConsoleMessage() and the other event waits had
no event name and no title, so the trace viewer showed them as __waitInfo__.
The before message of a wait now carries the event and the title of the
Node.js client, "Wait for event "console"" or "Wait for navigation", set for
that message only so that the calls made from the callback of the wait stay
visible. The wait of BrowserContext.waitForPage() was reported under the
name of BrowserContext.close(). TR-041 passes and loses its fixme.
upstream_base.txt names the microsoft/playwright commit whose tests/registry.md
is upstream_registry.md and whose spec files the ports follow, with the
commands that list the upstream changes still to port.
The upstream test checks that page.reload() ignores a pushState that
happens while the reload is pending. A port without concurrent calls can
only arrange that with timers, so it checks the fix only while the
timing holds. The fix is in the driver, and the Node.js test covers it
for all the ports.

Record the upstream rewrite of the other tests in
microsoft/playwright#43656.
The ported tests use @ParameterizedClass, which JUnit added in 5.13.
The headed tests need an X server, as upstream runs its Linux tests under
xvfb-run. With the ported tests a run takes about four times longer, and
the macOS and Windows jobs did not finish in 30 minutes.
Playwright Test sets testIdAttribute before every test. Without it, SE-075
failed when SE-072 or SE-073 ran before it in the same worker.
On Windows the temporary directory and the checkout are on different
drives, where Path.relativize throws and path.relative returns the
absolute path.
…y occur

Fixme gets an os attribute and can be repeated, like DisabledOnBrowser.
CA-030, PR-007 and FI-013 pass in the WebKit of some platforms, DD-008
fails in the WebKit of macOS and Windows, and EH-077 matches the goldens
in CI.
The stack trace collector skipped the frames of the tests in
com.microsoft.playwright.tests, so TR-014 and TR-016 found no source files.
TestTracing now sets PLAYWRIGHT_JAVA_SRC, as the Node.js client always
sends the stack frames.
…rocess

The driver is installed once per JVM, and it kept the env of the first
Playwright.create() call. The env of later instances did not get to their
driver process.
Like the Node.js client: when the page or the context closes while a route
handler runs, the update of the interception patterns no longer throws
from the call that dispatched the route event, such as context.close().
…l its pid

taskkill got pid -1 and killed nothing, so the teardown of the child
processes waited forever and TestBrowsertypeConnect never finished.
…nutes

The method timeout does not cover the fixtures, and a hang there stopped
the whole job with no trace of the cause.
After the Fixme timeout, the paused call kept reading the connection of
the worker while the teardown used it, and the test class could hang.
TZ-006 waits for the log message of the worker, because Chrome on Windows
can log the 404 error of /favicon.ico first. NE-024 is an expected
failure in the WebKit of driver 1.64.1 on Windows.
Like the Node.js client, waitForNavigation, waitForURL and waitForLoadState
throw the target closed error when the page is already closed, instead of
the close reason of the connection, which differs between platforms.
The test classes run in parallel in one JVM, so the fixed port 9339 of
upstream collides with the old TestChromium.
Java does not escape the quotes in an argument on Windows, so the remote
server got its JSON options without the quotes.
On JDK 8 the fork-join pool of JUnit adds a thread when a pool thread
blocks, and the new thread starts another test. On the 3-core macOS
runners about 30 tests ran at once and the jobs hit the time limit.
Chromium 156 of driver 1.64 sometimes never answers a Page.captureScreenshot
that is sent right after a document of the redirect loop commits, and the
screenshot times out after 30 seconds.
The teardown uses the connection of the test, which is not thread-safe; a
timed-out connect() kept reading it while the worker closed the browser.
Concurrent extractions shared the zip file system of the jar, and the
first one to finish closed it under the others: ClosedFileSystemException
when several Playwright instances were created at once.
A class ran its methods one at a time, so a few long classes such as
TestBrowsertypeConnect kept a run going long after the others had
finished. The classes whose tests share state or a display opt out.
With the methods in parallel, 32 Firefox tests at once on the Windows
runner timed out by the hundreds. The limit of TestScope follows the
configured parallelism, since JDK 8 can add threads to the JUnit pool.
A port that was free when it was picked can be taken before the server
binds it, now that many tests run at once: Address already in use. The
tests of a class also create their server only once.
@yury-s
Yury Semikhatsky (yury-s) merged commit 441d9f0 into microsoft:main Oct 28, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants