playwright-roll

작성자: microsoft

Playwright Java를 새 버전으로 업데이트

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.

microsoft의 다른 스킬

oss-growth
microsoft
OSS 성장 해커 페르소나
agent-framework-azure-ai-py
microsoft
Microsoft Agent Framework Python SDK(agent-framework-azure-ai)를 사용하여 Azure AI Foundry 에이전트를 구축합니다. AzureAIAgentsProvider로 지속적 에이전트를 만들 때, 호스팅 도구(코드 인터프리터, 파일 검색, 웹 검색)를 사용할 때, MCP 서버를 통합할 때, 대화 스레드를 관리할 때, 또는 스트리밍 응답을 구현할 때 사용합니다. 함수 도구, 구조화된 출력, 다중 도구 에이전트를 다룹니다.
development
airunway-aks-setup
microsoft
Set up AI Runway on AKS — from bare cluster to running model. Covers cluster verification, controller install, GPU assessment, provider setup, and first deployment. WHEN: "setup AI Runway", "onboard AKS cluster", "install AI Runway", "airunway setup", "deploy model to AKS", "GPU inference on AKS", "KAITO setup on AKS", "run LLM on AKS", "vLLM on AKS", "set up model serving on AKS", "AI Runway controller".
devops
appinsights-instrumentation
microsoft
Azure Application Insights로 웹앱을 계측하기 위한 지침입니다. 원격 분석 패턴, SDK 설정, 구성 참조를 제공합니다. WHEN: 앱 계측 방법, App Insights SDK, 원격 분석 패턴, App Insights란 무엇인가, Application Insights 지침, 계측 예시, APM 모범 사례.
devops
applicationinsights-web-ts
microsoft
브라우저/웹 앱을 Application Insights JavaScript SDK(@microsoft/applicationinsights-web)로 계측합니다. Real User Monitoring(RUM) — 페이지 뷰, 클릭, AJAX/fetch 종속성, 예외, 사용자 지정 이벤트, 백엔드 OpenTelemetry 트레이스와 상관관계가 있는 브라우저 측 GenAI 에이전트 트레이스에 사용합니다. SDK Loader Script 및 npm 설정, 프레임워크 확장(React, React Native, Angular), Click Analytics, 텔레메트리 이니셜라이저, 브라우저에서 생성된 에이전트/도구/모델 스팬에 대한 OTel GenAI 의미론적 규칙을 다룹니다.
devops
azure-ai-anomalydetector-java
microsoft
Azure AI Anomaly Detector SDK for Java로 이상 탐지 애플리케이션을 구축하세요. 단변량/다변량 이상 탐지, 시계열 분석 또는 AI 기반 모니터링을 구현할 때 사용하세요.
development
azure-ai-language-conversations-py
microsoft
azure-ai-language-conversations Python SDK를 사용하여 대화형 언어 이해(CLU)를 구현합니다. ConversationAnalysisClient로 대화 의도와 엔터티를 분석하거나, NLP 기능을 구축하거나, 애플리케이션에 언어 이해를 통합할 때 사용합니다.
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 for Python. ML 작업 영역, 작업, 모델, 데이터 세트, 컴퓨팅 및 파이프라인에 사용합니다. 트리거: "azure-ai-ml", "MLClient", "workspace", "model registry", "training jobs", "datasets".
development