playwright-roll

bởi microsoft

Cập nhật Playwright Java lên phiên bản mới

npx skills add https://github.com/microsoft/playwright-java --skill playwright-roll

Help the user roll to a new version of Playwright. ROLLING.md contains general instructions and scripts.

Start with running ./scripts/roll_driver.sh to update the version and generate the API to see the state of things. Afterwards, walk through the upstream changes that affect the Java client and port the relevant ones.

Determining what to port

List the upstream commits that touched a client-relevant path since the last release. The paths cover everything that can change the public Java surface or the wire protocol:

  • docs/src/api/ — the source of truth for api.json. Method/option additions, removals, and langs: filter changes flow from here.
  • packages/playwright-core/src/client/ — the JS client implementation that the Java client mirrors.
  • packages/isomorphic/ — selector engines, locator generation/parsing, and aria-snapshot logic shared between client and server. Changes here can affect client-side helpers like getByRoleSelector.
  • packages/playwright/src/matchers/matchers.ts — assertion-method definitions. Changes here usually correspond to new options on LocatorAssertions / PageAssertions.
  • packages/protocol/src/protocol.yml — the wire protocol schema. Method/event additions, parameter renames, and result-shape changes affect what the Java *Impl classes need to send/receive.
cd ~/playwright
PREV_TAG=$(git tag | grep -E '^v1\.[0-9]+\.[0-9]+$' | sort -V | tail -1)  # e.g. v1.59.1
git log "$PREV_TAG"..HEAD --oneline -- \
  'docs/src/api/' \
  'packages/playwright-core/src/client/' \
  'packages/isomorphic/' \
  'packages/playwright/src/matchers/matchers.ts' \
  'packages/protocol/src/protocol.yml'

Walk that list top-to-bottom (oldest-first is easier — newest is at top, so reverse). For each commit:

  1. Read the commit (git show <sha>) to see what client/protocol/docs changed.
  2. If it's JS-internal (bundling, dispatcher conventions, electron, mcp, dashboard, trace-viewer, test-runner) — skip.
  3. If it touches docs/src/api/ or types, check langs: annotations — features marked langs: js/langs: js, python don't apply to Java.
  4. If it adds/changes a public API method or option that applies to Java, port it. The api.json regenerated by roll_driver.sh already contains the new types/options, so the generated Java interfaces usually pick them up automatically — what's typically missing is the *Impl wiring.
  5. Watch for follow-up reverts — a "feat: X" commit might be undone by a later "Revert X". Check whether the change still exists in HEAD before porting.
  6. Maintain a running notes file (e.g. /tmp/roll-notes.md) listing each upstream PR as ported / skipped / verified-already-supported, with a one-line reason. This file becomes the body of the eventual PR.

What to include in the rolling PR

  • Driver version bump
  • Generated interface diffs from roll_driver.sh
  • *Impl wiring for each ported feature
  • Generator updates (import lists, special-cases) if new types appeared
  • A small test per new public API surface — listener for new events, basic call for new methods, regression for changed return types
  • PR description: list each upstream PR ported, each skipped (with reason), and each verified-already-supported

Rolling includes:

  • updating client implementation to match changes in the upstream JS implementation (see ../playwright/packages/playwright-core/src/client)
  • adding a couple of new tests to verify new/changed functionality

Mimicking the JavaScript implementation

The Java client is a port of the JS client in ../playwright/packages/playwright-core/src/client/. When implementing a new or changed method, always read the corresponding JS file first and mirror its logic:

../playwright/packages/playwright-core/src/client/browserContext.ts
../playwright/packages/playwright-core/src/client/page.ts
../playwright/packages/playwright-core/src/client/tracing.ts
../playwright/packages/playwright-core/src/client/video.ts
../playwright/packages/playwright-core/src/client/locator.ts
../playwright/packages/playwright-core/src/client/network.ts
...

Key translation rules:

Protocol callsawait this._channel.methodName(params)sendMessage("methodName", params, NO_TIMEOUT)

Extracting a returned channel object from a result — JS uses SomeClass.from(result.foo) which resolves the JS-side object for a channel reference. In Java, the object was already created when the server sent __create__, so extract it from the connection: connection.getExistingObject(result.getAsJsonObject("foo").get("guid").getAsString())

Async/await — all await calls become synchronous sendMessage(...) calls since the Java client is synchronous.

undefined / optional params — JS options?.foo checks translate to if (options != null && options.foo != null) null checks before adding to the params JsonObject.

_channel fields — the JS this._channel.foo maps to calling sendMessage("foo", ...) on this in the Impl class.

Channel object references in params — when a JS call passes a channel object as a param (e.g. { frame: frame._channel }), in Java pass the guid: params.addProperty("frame", ((FrameImpl) frame).guid).

Fixing generator and compilation errors

After running ./scripts/roll_driver.sh, the build often fails because the generated Java interfaces reference new types or methods that the generator doesn't know how to handle yet, and the *Impl classes don't implement new interface methods.

ApiGenerator.java fixes (tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java)

The generator has hardcoded lists that control which imports are added to each generated file. When new classes appear in the API, add them to the relevant lists in Interface.writeTo:

  • options.* import list — add new classes that use types from the options package
  • java.util.* import list — add new classes that use List, Map, etc.
  • java.util.function.Consumer list — add new classes with Consumer-typed event handlers

Type mapping: when JS-only types (like Disposable) are used as return types in Java-compatible methods, add a mapping in convertBuiltinType. For example, DisposableAutoCloseable.

Event handler generation: events with void type generate invalid Consumer<void>. Handle this case in Event.writeListenerMethods by emitting Runnable instead.

After editing the generator, recompile and re-run it:

mvn -f tools/api-generator/pom.xml compile -q
mvn -f tools/api-generator/pom.xml exec:java -Dexec.mainClass=com.microsoft.playwright.tools.ApiGenerator

Impl class fixes (playwright/src/main/java/com/microsoft/playwright/impl/)

After regenerating, compile playwright/ to find what's missing:

mvn -f playwright/pom.xml compile 2>&1 | grep "ERROR"

Common patterns:

Return type changed (e.g. voidAutoCloseable): Update the method signature in the Impl class and return an appropriate AutoCloseable. Check the JS client to see what kind of disposable is used:

  • If JS returns DisposableObject.from(result.disposable) — the server created a disposable channel object. Extract its guid from the protocol result and return connection.getExistingObject(guid) (a DisposableObject).
  • If JS returns new DisposableStub(() => this.someCleanup()) — it's a local callback. Return new DisposableStub(this::someCleanup) in Java.
  • Examples: addInitScript/exposeBinding/exposeFunctionDisposableObject; route(...)DisposableStub(() -> unroute(...)); Tracing.groupDisposableStub(this::groupEnd); Video.startDisposableStub(this::stop).

New method missing: Add a stub implementation. Common patterns:

  • Simple protocol message: sendMessage("methodName", params, NO_TIMEOUT)
  • New property accessor (e.g. from initializer): return initializer.get("fieldName").getAsString()
  • Delegation to mainFrame (for Page methods): return mainFrame.locator(":root").method(...)

New interface entirely (e.g. Debugger): Create a new *Impl class extending ChannelOwner, implement the interface, and register the type in Connection.java's switch statement. Initialize the field from the parent's initializer in the parent's constructor (e.g. connection.getExistingObject(initializer.getAsJsonObject("debugger").get("guid").getAsString())).

Field visibility: If a field needs to be accessed from a sibling Impl class (e.g. setting existingResponse on RequestImpl from BrowserContextImpl), change it from private to package-private.

ListenerCollection only supports Consumer<T>, not Runnable. For void events that use Runnable handlers, maintain a plain List<Runnable> instead.

Protocol changes that remove events — when a method's response now returns an object directly instead of via a subsequent event, update the Impl to capture it from the sendMessage result and remove the old event handler. Example: videoStart used to fire a "video" page event to deliver the artifact; it now returns the artifact directly in the response. Check git history of the upstream JS client when tests hang unexpectedly.

Protocol parameter renames — protocol parameter names can change between versions (e.g. wsEndpointendpoint in BrowserType.connect). When a test fails with expected string, got undefined or similar validation errors from the driver, check packages/protocol/src/protocol.yml for the current parameter names and update the corresponding params.addProperty(...) call in the Impl class. Also check the JS client (src/client/) to see how it builds the params object.

Rebuilding the driver-bundle after a roll

./scripts/roll_driver.sh does the whole roll pipeline end-to-end: bumps DRIVER_VERSION, downloads new driver files into driver-bundle/src/main/resources/driver/<platform>/, regenerates api.json and the Java interfaces, and updates the README. When all of that succeeds, the next mvn invocation that touches driver-bundle will pick up the new files and you don't need to think about it.

But if any step in the pipeline fails (the very common case is the API generator throwing on a new type — see Fixing generator and compilation errors), the run aborts before driver-bundle/target/classes/ has been refreshed. From that point on, until you manually rebuild driver-bundle, the test JVM will load the old driver from the cached target/classes/installed jar even though the source resources have already been swapped to the new version.

Fix — rebuild driver-bundle once before re-running tests:

mvn -f driver-bundle/pom.xml install -DskipTests

Porting and verifying tests

Before porting an upstream test file, check the API exists in Java. The upstream repo may have test files for brand-new APIs that haven't been added to the Java interface yet (e.g., screencast.spec.ts tests page.screencast which may not be in the generated Page.java). Check git diff main --name-only to see what interfaces were added this roll, and verify the method exists in the generated Java interface before porting.

Java test file names don't always match upstream spec names. TestScreencast.java tests recordVideo video-file recording (which corresponds to video.spec.ts), not the newer page.screencast streaming API (screencast.spec.ts). When comparing coverage, check test content, not just file names.

Remove tests for behavior that was removed upstream. When the JS client drops a client-side error check (e.g., "Page is not yet closed before saveAs", "Page did not produce any video frames"), delete the corresponding Java tests rather than trying to keep them passing. Check the upstream tests/library/ spec to confirm the behavior is gone.

Run the full suite to catch regressions, re-run flaky failures in isolation. Some tests (e.g., TestClientCertificates#shouldKeepSupportingHttp) time out only under heavy parallel load. Run the failing test alone to confirm it's flaky before investigating further.

Diagnosing hanging tests

When mvn test hangs and surefire eventually times the JVM out, it writes thread dumps to playwright/target/surefire-reports/<timestamp>-jvmRun*.dump. To find the stuck test:

grep "com.microsoft.playwright.Test" playwright/target/surefire-reports/*-jvmRun1.dump | sort -u

Each line is a stack frame inside a test method — typically you'll see one or two test methods blocked on a Future.get(), waitForCondition, or similar. That's the hanging test.

When you've identified a hanging test:

  1. Run it in isolation: mvn -f playwright/pom.xml test -Dtest='TestClass#testMethod'. If it passes alone, it's a parallel-load flake — note it but move on.
  2. If it still hangs in isolation, look for a recent fix in the upstream repo for the same test name. Use git log --oneline tests/library/<spec>.spec.ts in ~/playwright. Upstream fixes for client-side hangs are often small and portable (e.g. about:blankserver.EMPTY_PAGE from microsoft/playwright#39840 fixed route-web-socket.spec.ts arraybuffer hangs — apparently some browser changed the WebSocket origin policy on about:blank).
  3. When porting an upstream fix, mirror the helper signature change rather than hard-coding workarounds. E.g. if upstream added a server parameter to setupWS, do the same in Java by injecting Server server via the JUnit fixture (@FixtureTest already wires up ServerLifecycle, so adding Server server to the test method signature is enough — no class-level boilerplate). Watch for local-variable shadowing when you add a Server server parameter to a method that already has a WebSocketRoute server local; rename the local.

Thêm skills từ microsoft

oss-growth
microsoft
Cá tính tăng trưởng OSS
agent-framework-azure-ai-py
microsoft
Xây dựng các tác nhân Azure AI Foundry bằng SDK Python của Microsoft Agent Framework (agent-framework-azure-ai). Sử dụng khi tạo các tác nhân bền vững với AzureAIAgentsProvider, sử dụng các công cụ được lưu trữ (trình thông dịch mã, tìm kiếm tệp, tìm kiếm web), tích hợp máy chủ MCP, quản lý chuỗi hội thoại hoặc triển khai phản hồi phát trực tuyến. Bao gồm các công cụ hàm, đầu ra có cấu trúc và các tác nhân đa công cụ.
development
airunway-aks-setup
microsoft
Thiết lập AI Runway trên AKS — từ cụm trống đến mô hình đang chạy. Bao gồm xác minh cụm, cài đặt controller, đánh giá GPU, thiết lập nhà cung cấp và triển khai đầu tiên. KHI NÀO: "thiết lập AI Runway", "onboard cụm AKS", "cài đặt AI Runway", "thiết lập airunway", "triển khai mô hình lên AKS", "suy luận GPU trên AKS", "thiết lập KAITO trên AKS", "chạy LLM trên AKS", "vLLM trên AKS", "thiết lập phục vụ mô hình trên AKS", "AI Runway controller".
devops
appinsights-instrumentation
microsoft
Hướng dẫn để instrument các ứng dụng web với Azure Application Insights. Cung cấp các mẫu telemetry, thiết lập SDK, và tài liệu tham khảo cấu hình. KHI NÀO: cách instrument ứng dụng, App Insights SDK, các mẫu telemetry, App Insights là gì, hướng dẫn Application Insights, ví dụ instrumentation, các phương pháp tốt nhất APM.
devops
applicationinsights-web-ts
microsoft
Instrument các ứng dụng trình duyệt/web bằng SDK JavaScript Application Insights (@microsoft/applicationinsights-web). Dùng cho Real User Monitoring (RUM) — lượt xem trang, nhấp chuột, phụ thuộc AJAX/fetch, ngoại lệ, sự kiện tùy chỉnh và dấu vết tác nhân GenAI phía trình duyệt tương quan với dấu vết OpenTelemetry phía backend. Bao gồm thiết lập SDK Loader Script và npm, tiện ích mở rộng framework (React, React Native, Angular), Click Analytics, trình khởi tạo telemetry và quy ước ngữ nghĩa OTel GenAI cho các span tác nhân/công cụ/mô hình phát ra từ trình duyệt.
devops
azure-ai-anomalydetector-java
microsoft
Xây dựng ứng dụng phát hiện bất thường với Azure AI Anomaly Detector SDK cho Java. Sử dụng khi triển khai phát hiện bất thường đơn biến/đa biến, phân tích chuỗi thời gian hoặc giám sát hỗ trợ AI.
development
azure-ai-language-conversations-py
microsoft
Triển khai Conversational Language Understanding (CLU) bằng SDK Python azure-ai-language-conversations. Sử dụng khi làm việc với ConversationAnalysisClient để phân tích ý định và thực thể trong hội thoại, xây dựng tính năng NLP, hoặc tích hợp hiểu ngôn ngữ vào ứng dụng.
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 cho Python. Dùng cho không gian làm việc ML, công việc, mô hình, tập dữ liệu, tính toán và quy trình. Kích hoạt: "azure-ai-ml", "MLClient", "không gian làm việc", "đăng ký mô hình", "công việc đào tạo", "tập dữ liệu".
development