mirror of
https://github.com/microsoft/playwright-java.git
synced 2026-03-30 19:32:50 +00:00
chore: roll to 1.59.0-alpha-1774622285000 (#1901)
This commit is contained in:
parent
afd80add27
commit
5ccdd3e4b9
@ -10,7 +10,7 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->146.0.7680.31<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->147.0.7727.15<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->26.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->148.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
|
||||
@ -35,11 +35,11 @@ public interface Debugger {
|
||||
void offPausedStateChanged(Runnable handler);
|
||||
|
||||
/**
|
||||
* Returns details about the currently paused calls. Returns an empty array if the debugger is not paused.
|
||||
* Returns details about the currently paused call. Returns {@code null} if the debugger is not paused.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
List<PausedDetails> pausedDetails();
|
||||
PausedDetails pausedDetails();
|
||||
/**
|
||||
* Configures the debugger to pause before the next action is executed.
|
||||
*
|
||||
@ -47,13 +47,13 @@ public interface Debugger {
|
||||
* com.microsoft.playwright.Debugger#runTo Debugger.runTo()} to step while paused.
|
||||
*
|
||||
* <p> Note that {@link com.microsoft.playwright.Page#pause Page.pause()} is equivalent to a "debugger" statement — it pauses
|
||||
* execution at the call site immediately. On the contrary, {@link com.microsoft.playwright.Debugger#pause
|
||||
* Debugger.pause()} is equivalent to "pause on next statement" — it configures the debugger to pause before the next
|
||||
* action is executed.
|
||||
* execution at the call site immediately. On the contrary, {@link com.microsoft.playwright.Debugger#requestPause
|
||||
* Debugger.requestPause()} is equivalent to "pause on next statement" — it configures the debugger to pause before the
|
||||
* next action is executed.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void pause();
|
||||
void requestPause();
|
||||
/**
|
||||
* Resumes script execution. Throws if the debugger is not paused.
|
||||
*
|
||||
|
||||
@ -35,8 +35,8 @@ public interface Locator {
|
||||
*/
|
||||
public Integer depth;
|
||||
/**
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption with element references. Defaults to {@code
|
||||
* "default"}.
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption. Defaults to {@code "default"}. See details
|
||||
* for more information.
|
||||
*/
|
||||
public AriaSnapshotMode mode;
|
||||
/**
|
||||
@ -55,8 +55,8 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption with element references. Defaults to {@code
|
||||
* "default"}.
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption. Defaults to {@code "default"}. See details
|
||||
* for more information.
|
||||
*/
|
||||
public AriaSnapshotOptions setMode(AriaSnapshotMode mode) {
|
||||
this.mode = mode;
|
||||
@ -2322,6 +2322,12 @@ public interface Locator {
|
||||
*
|
||||
* <p> Below is the HTML markup and the respective ARIA snapshot:
|
||||
*
|
||||
* <p> An AI-optimized snapshot, controlled by {@code mode}, is different from a default snapshot:
|
||||
* <ol>
|
||||
* <li> Includes element references {@code [ref=e2]}. 2. Does not wait for an element matching the locator, and throws when no
|
||||
* elements match. 3. Includes snapshots of {@code <iframe>}s inside the target.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
default String ariaSnapshot() {
|
||||
@ -2353,6 +2359,12 @@ public interface Locator {
|
||||
*
|
||||
* <p> Below is the HTML markup and the respective ARIA snapshot:
|
||||
*
|
||||
* <p> An AI-optimized snapshot, controlled by {@code mode}, is different from a default snapshot:
|
||||
* <ol>
|
||||
* <li> Includes element references {@code [ref=e2]}. 2. Does not wait for an element matching the locator, and throws when no
|
||||
* elements match. 3. Includes snapshots of {@code <iframe>}s inside the target.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
String ariaSnapshot(AriaSnapshotOptions options);
|
||||
|
||||
109
playwright/src/main/java/com/microsoft/playwright/Overlay.java
Normal file
109
playwright/src/main/java/com/microsoft/playwright/Overlay.java
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for managing page overlays that display persistent visual indicators on top of the page.
|
||||
*/
|
||||
public interface Overlay {
|
||||
class ShowOptions {
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Overlay stays until dismissed if not
|
||||
* provided.
|
||||
*/
|
||||
public Double duration;
|
||||
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Overlay stays until dismissed if not
|
||||
* provided.
|
||||
*/
|
||||
public ShowOptions setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ChapterOptions {
|
||||
/**
|
||||
* Optional description text displayed below the title.
|
||||
*/
|
||||
public String description;
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Defaults to {@code 2000}.
|
||||
*/
|
||||
public Double duration;
|
||||
|
||||
/**
|
||||
* Optional description text displayed below the title.
|
||||
*/
|
||||
public ChapterOptions setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Defaults to {@code 2000}.
|
||||
*/
|
||||
public ChapterOptions setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Adds an overlay with the given HTML content. The overlay is displayed on top of the page until removed. Returns a
|
||||
* disposable that removes the overlay when disposed.
|
||||
*
|
||||
* @param html HTML content for the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
default AutoCloseable show(String html) {
|
||||
return show(html, null);
|
||||
}
|
||||
/**
|
||||
* Adds an overlay with the given HTML content. The overlay is displayed on top of the page until removed. Returns a
|
||||
* disposable that removes the overlay when disposed.
|
||||
*
|
||||
* @param html HTML content for the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
AutoCloseable show(String html, ShowOptions options);
|
||||
/**
|
||||
* Shows a chapter overlay with a title and optional description, centered on the page with a blurred backdrop. Useful for
|
||||
* narrating video recordings. The overlay is removed after the specified duration, or 2000ms.
|
||||
*
|
||||
* @param title Title text displayed prominently in the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
default void chapter(String title) {
|
||||
chapter(title, null);
|
||||
}
|
||||
/**
|
||||
* Shows a chapter overlay with a title and optional description, centered on the page with a blurred backdrop. Useful for
|
||||
* narrating video recordings. The overlay is removed after the specified duration, or 2000ms.
|
||||
*
|
||||
* @param title Title text displayed prominently in the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
void chapter(String title, ChapterOptions options);
|
||||
/**
|
||||
* Sets visibility of all overlays without removing them.
|
||||
*
|
||||
* @param visible Whether overlays should be visible.
|
||||
* @since v1.59
|
||||
*/
|
||||
void setVisible(boolean visible);
|
||||
}
|
||||
|
||||
@ -2986,8 +2986,8 @@ public interface Page extends AutoCloseable {
|
||||
*/
|
||||
public Integer depth;
|
||||
/**
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption with element references. Defaults to {@code
|
||||
* "default"}.
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption: including element references like {@code
|
||||
* [ref=e2]} and snapshots of {@code <iframe>}s. Defaults to {@code "default"}.
|
||||
*/
|
||||
public AriaSnapshotMode mode;
|
||||
/**
|
||||
@ -3006,8 +3006,8 @@ public interface Page extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption with element references. Defaults to {@code
|
||||
* "default"}.
|
||||
* When set to {@code "ai"}, returns a snapshot optimized for AI consumption: including element references like {@code
|
||||
* [ref=e2]} and snapshots of {@code <iframe>}s. Defaults to {@code "default"}.
|
||||
*/
|
||||
public AriaSnapshotOptions setMode(AriaSnapshotMode mode) {
|
||||
this.mode = mode;
|
||||
@ -5880,6 +5880,12 @@ public interface Page extends AutoCloseable {
|
||||
* @since v1.8
|
||||
*/
|
||||
Mouse mouse();
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
Overlay overlay();
|
||||
/**
|
||||
* Adds one-off {@code Dialog} handler. The handler will be removed immediately after next {@code Dialog} is created.
|
||||
* <pre>{@code
|
||||
|
||||
@ -805,7 +805,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
} else if ("response".equals(event)) {
|
||||
String guid = params.getAsJsonObject("response").get("guid").getAsString();
|
||||
ResponseImpl response = connection.getExistingObject(guid);
|
||||
response.request.existingResponse = response;
|
||||
listeners.notify(EventType.RESPONSE, response);
|
||||
if (params.has("page")) {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
|
||||
@ -16,21 +16,19 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Debugger;
|
||||
import com.microsoft.playwright.options.Location;
|
||||
import com.microsoft.playwright.options.PausedDetails;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class DebuggerImpl extends ChannelOwner implements Debugger {
|
||||
private final List<Runnable> pausedStateChangedHandlers = new ArrayList<>();
|
||||
private List<PausedDetails> pausedDetails = new ArrayList<>();
|
||||
private PausedDetails pausedDetails;
|
||||
|
||||
DebuggerImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
@ -39,8 +37,11 @@ class DebuggerImpl extends ChannelOwner implements Debugger {
|
||||
@Override
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("pausedStateChanged".equals(event)) {
|
||||
JsonArray details = params.getAsJsonArray("pausedDetails");
|
||||
pausedDetails = Arrays.asList(gson().fromJson(details, PausedDetails[].class));
|
||||
if (params.has("pausedDetails") && !params.get("pausedDetails").isJsonNull()) {
|
||||
pausedDetails = gson().fromJson(params.get("pausedDetails"), PausedDetails.class);
|
||||
} else {
|
||||
pausedDetails = null;
|
||||
}
|
||||
for (Runnable handler : new ArrayList<>(pausedStateChangedHandlers)) {
|
||||
handler.run();
|
||||
}
|
||||
@ -58,13 +59,13 @@ class DebuggerImpl extends ChannelOwner implements Debugger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PausedDetails> pausedDetails() {
|
||||
public PausedDetails pausedDetails() {
|
||||
return pausedDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
sendMessage("pause", new JsonObject(), NO_TIMEOUT);
|
||||
public void requestPause() {
|
||||
sendMessage("requestPause", new JsonObject(), NO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -43,7 +43,11 @@ class DialogImpl extends ChannelOwner implements Dialog {
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
sendMessage("dismiss");
|
||||
try {
|
||||
sendMessage("dismiss");
|
||||
} catch (TargetClosedError e) {
|
||||
// Swallow TargetClosedErrors for beforeunload dialogs.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Request;
|
||||
@ -82,7 +84,7 @@ public class HARRouter {
|
||||
if (status == -1) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> headers = fromNameValues(response.getAsJsonArray("headers"));
|
||||
Map<String, String> headers = mergeSetCookieHeaders(response.getAsJsonArray("headers"));
|
||||
byte[] buffer = Base64.getDecoder().decode(response.get("body").getAsString());
|
||||
route.fulfill(new Route.FulfillOptions()
|
||||
.setStatus(status)
|
||||
@ -105,6 +107,25 @@ public class HARRouter {
|
||||
route.abort();
|
||||
}
|
||||
|
||||
private static Map<String, String> mergeSetCookieHeaders(JsonArray headersArray) {
|
||||
Map<String, String> result = new java.util.LinkedHashMap<>();
|
||||
for (JsonElement element : headersArray) {
|
||||
JsonObject pair = element.getAsJsonObject();
|
||||
String name = pair.get("name").getAsString();
|
||||
String value = pair.get("value").getAsString();
|
||||
if ("set-cookie".equalsIgnoreCase(name)) {
|
||||
if (!result.containsKey("set-cookie")) {
|
||||
result.put("set-cookie", value);
|
||||
} else {
|
||||
result.put("set-cookie", result.get("set-cookie") + "\n" + value);
|
||||
}
|
||||
} else {
|
||||
result.put(name, value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("harId", harId);
|
||||
|
||||
@ -34,13 +34,20 @@ public class LocalUtils extends ChannelOwner {
|
||||
return initializer.getAsJsonArray("deviceDescriptors");
|
||||
}
|
||||
|
||||
void zip(Path zipFile, JsonArray entries, String stacksId, boolean appendMode, boolean includeSources) {
|
||||
void zip(Path zipFile, JsonArray entries, String stacksId, boolean appendMode, boolean includeSources, List<String> additionalSources) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("zipFile", zipFile.toString());
|
||||
params.add("entries", entries);
|
||||
params.addProperty("mode", appendMode ? "append" : "write");
|
||||
params.addProperty("stacksId", stacksId);
|
||||
params.addProperty("includeSources", includeSources);
|
||||
if (!additionalSources.isEmpty()) {
|
||||
JsonArray sourcesArray = new JsonArray();
|
||||
for (String source : additionalSources) {
|
||||
sourcesArray.add(source);
|
||||
}
|
||||
params.add("additionalSources", sourcesArray);
|
||||
}
|
||||
sendMessage("zip", params, NO_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
@ -112,8 +112,8 @@ class LocatorImpl implements Locator {
|
||||
public Locator normalize() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject result = frame.sendMessage("normalizeLocator", params, ChannelOwner.NO_TIMEOUT).getAsJsonObject();
|
||||
return new LocatorImpl(frame, result.get("selector").getAsString(), null);
|
||||
JsonObject result = frame.sendMessage("resolveSelector", params, ChannelOwner.NO_TIMEOUT).getAsJsonObject();
|
||||
return new LocatorImpl(frame, result.get("resolvedSelector").getAsString(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Overlay;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
|
||||
class OverlayImpl implements Overlay {
|
||||
private final ChannelOwner page;
|
||||
|
||||
OverlayImpl(ChannelOwner page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoCloseable show(String html, ShowOptions options) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("html", html);
|
||||
if (options != null && options.duration != null) {
|
||||
params.addProperty("duration", options.duration);
|
||||
}
|
||||
JsonObject result = (JsonObject) page.sendMessage("overlayShow", params, NO_TIMEOUT);
|
||||
String id = result.get("id").getAsString();
|
||||
return () -> {
|
||||
JsonObject removeParams = new JsonObject();
|
||||
removeParams.addProperty("id", id);
|
||||
page.sendMessage("overlayRemove", removeParams, NO_TIMEOUT);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chapter(String title, ChapterOptions options) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("title", title);
|
||||
if (options != null) {
|
||||
if (options.description != null) {
|
||||
params.addProperty("description", options.description);
|
||||
}
|
||||
if (options.duration != null) {
|
||||
params.addProperty("duration", options.duration);
|
||||
}
|
||||
}
|
||||
page.sendMessage("overlayChapter", params, NO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("visible", visible);
|
||||
page.sendMessage("overlaySetVisible", params, NO_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@ -46,6 +46,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private final KeyboardImpl keyboard;
|
||||
private final MouseImpl mouse;
|
||||
private final TouchscreenImpl touchscreen;
|
||||
private final OverlayImpl overlay;
|
||||
final Waitable<?> waitableClosedOrCrashed;
|
||||
private ViewportSize viewport;
|
||||
private final Router routes = new Router();
|
||||
@ -135,6 +136,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
keyboard = new KeyboardImpl(this);
|
||||
mouse = new MouseImpl(this);
|
||||
touchscreen = new TouchscreenImpl(this);
|
||||
overlay = new OverlayImpl(this);
|
||||
frames.add(mainFrame);
|
||||
timeoutSettings = new TimeoutSettings(browserContext.timeoutSettings);
|
||||
waitableClosedOrCrashed = createWaitForCloseHelper();
|
||||
@ -1347,6 +1349,11 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
return touchscreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Overlay overlay() {
|
||||
return overlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void type(String selector, String text, TypeOptions options) {
|
||||
mainFrame.type(selector, text, convertType(options, Frame.TypeOptions.class));
|
||||
|
||||
@ -42,6 +42,7 @@ public class ResponseImpl extends ChannelOwner implements Response {
|
||||
super(parent, type, guid, initializer);
|
||||
headers = new RawHeaders(asList(gson().fromJson(initializer.getAsJsonArray("headers"), HttpHeader[].class)));
|
||||
request = connection.getExistingObject(initializer.getAsJsonObject("request").get("guid").getAsString());
|
||||
request.existingResponse = this;
|
||||
request.timing = gson().fromJson(initializer.get("timing"), Timing.class);
|
||||
}
|
||||
|
||||
@ -88,10 +89,8 @@ public class ResponseImpl extends ChannelOwner implements Response {
|
||||
|
||||
@Override
|
||||
public String httpVersion() {
|
||||
if (initializer.has("httpVersion")) {
|
||||
return initializer.get("httpVersion").getAsString();
|
||||
}
|
||||
return null;
|
||||
JsonObject result = sendMessage("httpVersion").getAsJsonObject();
|
||||
return result.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -489,7 +489,7 @@ class Serialization {
|
||||
public JsonElement serialize(ConsoleMessagesFilter src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
switch (src) {
|
||||
case ALL: return new JsonPrimitive("all");
|
||||
case SINCE_NAVIGATION: return new JsonPrimitive("sinceNavigation");
|
||||
case SINCE_NAVIGATION: return new JsonPrimitive("since-navigation");
|
||||
default: throw new PlaywrightException("Unknown ConsoleMessagesFilter: " + src);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,10 @@ import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Tracing;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
@ -29,6 +33,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
private Path tracesDir;
|
||||
private boolean isTracing;
|
||||
private String stacksId;
|
||||
private final Set<String> additionalSources = new HashSet<>();
|
||||
|
||||
|
||||
TracingImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
@ -42,6 +47,9 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
}
|
||||
JsonObject params = new JsonObject();
|
||||
|
||||
List<String> capturedAdditionalSources = new ArrayList<>(additionalSources);
|
||||
additionalSources.clear();
|
||||
|
||||
// Not interested in artifacts.
|
||||
if (path == null) {
|
||||
params.addProperty("mode", "discard");
|
||||
@ -57,7 +65,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
params.addProperty("mode", "entries");
|
||||
JsonObject json = sendMessage("tracingStopChunk", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonArray entries = json.getAsJsonArray("entries");
|
||||
connection.localUtils.zip(path, entries, stacksId, false, includeSources);
|
||||
connection.localUtils.zip(path, entries, stacksId, false, includeSources, capturedAdditionalSources);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -74,7 +82,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
artifact.saveAs(path);
|
||||
artifact.delete();
|
||||
|
||||
connection.localUtils.zip(path, new JsonArray(), stacksId, true, includeSources);
|
||||
connection.localUtils.zip(path, new JsonArray(), stacksId, true, includeSources, capturedAdditionalSources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -95,6 +103,9 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
if (options == null) {
|
||||
options = new GroupOptions();
|
||||
}
|
||||
if (options.location != null) {
|
||||
additionalSources.add(options.location.file);
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("name", name);
|
||||
sendMessage("tracingGroup", params, NO_TIMEOUT);
|
||||
|
||||
@ -28,6 +28,7 @@ import java.nio.file.Paths;
|
||||
class VideoImpl implements Video {
|
||||
private final PageImpl page;
|
||||
private ArtifactImpl artifact;
|
||||
private Path savePath;
|
||||
|
||||
VideoImpl(PageImpl page) {
|
||||
this.page = page;
|
||||
@ -58,7 +59,13 @@ class VideoImpl implements Video {
|
||||
public AutoCloseable start(StartOptions options) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (options != null) {
|
||||
params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (options.size != null) {
|
||||
params.add("size", gson().toJsonTree(options.size));
|
||||
}
|
||||
if (options.annotate != null) {
|
||||
params.add("annotate", gson().toJsonTree(options.annotate));
|
||||
}
|
||||
savePath = options.path;
|
||||
}
|
||||
JsonObject result = page.sendMessage("videoStart", params, ChannelOwner.NO_TIMEOUT).getAsJsonObject();
|
||||
String artifactGuid = result.getAsJsonObject("artifact").get("guid").getAsString();
|
||||
@ -69,6 +76,10 @@ class VideoImpl implements Video {
|
||||
@Override
|
||||
public void stop() {
|
||||
page.sendMessage("videoStop", new JsonObject(), ChannelOwner.NO_TIMEOUT);
|
||||
if (savePath != null) {
|
||||
saveAs(savePath);
|
||||
savePath = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -20,13 +20,35 @@ public class Annotate {
|
||||
/**
|
||||
* How long each annotation is displayed in milliseconds. Defaults to {@code 500}.
|
||||
*/
|
||||
public Integer delay;
|
||||
public Double duration;
|
||||
/**
|
||||
* Position of the action title overlay. Defaults to {@code "top-right"}.
|
||||
*/
|
||||
public AnnotatePosition position;
|
||||
/**
|
||||
* Font size of the action title in pixels. Defaults to {@code 24}.
|
||||
*/
|
||||
public Integer fontSize;
|
||||
|
||||
/**
|
||||
* How long each annotation is displayed in milliseconds. Defaults to {@code 500}.
|
||||
*/
|
||||
public Annotate setDelay(int delay) {
|
||||
this.delay = delay;
|
||||
public Annotate setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Position of the action title overlay. Defaults to {@code "top-right"}.
|
||||
*/
|
||||
public Annotate setPosition(AnnotatePosition position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Font size of the action title in pixels. Defaults to {@code 24}.
|
||||
*/
|
||||
public Annotate setFontSize(int fontSize) {
|
||||
this.fontSize = fontSize;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.options;
|
||||
|
||||
public enum AnnotatePosition {
|
||||
TOP_LEFT,
|
||||
TOP,
|
||||
TOP_RIGHT,
|
||||
BOTTOM_LEFT,
|
||||
BOTTOM,
|
||||
BOTTOM_RIGHT
|
||||
}
|
||||
@ -19,61 +19,83 @@ package com.microsoft.playwright;
|
||||
import com.microsoft.playwright.options.PausedDetails;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestDebugger extends TestBase {
|
||||
@Test
|
||||
void shouldReturnEmptyPausedDetailsInitially() {
|
||||
void shouldReturnNullPausedDetailsInitially() {
|
||||
Debugger dbg = context.debugger();
|
||||
assertEquals(Collections.emptyList(), dbg.pausedDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPauseAtPauseCall() {
|
||||
page.setContent("<div>click me</div>");
|
||||
Debugger dbg = context.debugger();
|
||||
assertEquals(Collections.emptyList(), dbg.pausedDetails());
|
||||
|
||||
dbg.pause();
|
||||
|
||||
boolean[] paused = {false};
|
||||
dbg.onPausedStateChanged(() -> {
|
||||
if (!paused[0]) {
|
||||
paused[0] = true;
|
||||
List<PausedDetails> details = dbg.pausedDetails();
|
||||
assertEquals(1, details.size());
|
||||
assertTrue(details.get(0).title.contains("Pause"), "title: " + details.get(0).title);
|
||||
dbg.resume();
|
||||
}
|
||||
});
|
||||
|
||||
page.pause(); // blocks until dbg.resume() is called from event handler
|
||||
assertEquals(Collections.emptyList(), dbg.pausedDetails());
|
||||
assertNull(dbg.pausedDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPauseAtNextAndResume() {
|
||||
page.setContent("<div>click me</div>");
|
||||
Debugger dbg = context.debugger();
|
||||
assertEquals(Collections.emptyList(), dbg.pausedDetails());
|
||||
assertNull(dbg.pausedDetails());
|
||||
|
||||
dbg.pause();
|
||||
dbg.requestPause();
|
||||
|
||||
boolean[] paused = {false};
|
||||
dbg.onPausedStateChanged(() -> {
|
||||
if (!paused[0]) {
|
||||
paused[0] = true;
|
||||
List<PausedDetails> details = dbg.pausedDetails();
|
||||
assertEquals(1, details.size());
|
||||
assertTrue(details.get(0).title.contains("Click"), "title: " + details.get(0).title);
|
||||
PausedDetails details = dbg.pausedDetails();
|
||||
assertNotNull(details);
|
||||
assertTrue(details.title.contains("Click"), "title: " + details.title);
|
||||
dbg.resume();
|
||||
}
|
||||
});
|
||||
|
||||
page.click("div"); // blocks until dbg.resume() is called
|
||||
assertEquals(Collections.emptyList(), dbg.pausedDetails());
|
||||
assertNull(dbg.pausedDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldStepWithNext() {
|
||||
page.setContent("<div>click me</div>");
|
||||
Debugger dbg = context.debugger();
|
||||
assertNull(dbg.pausedDetails());
|
||||
|
||||
dbg.requestPause();
|
||||
|
||||
boolean[] paused = {false};
|
||||
dbg.onPausedStateChanged(() -> {
|
||||
if (!paused[0]) {
|
||||
paused[0] = true;
|
||||
PausedDetails details = dbg.pausedDetails();
|
||||
assertNotNull(details);
|
||||
assertTrue(details.title.contains("Click"), "title: " + details.title);
|
||||
dbg.next();
|
||||
} else if (dbg.pausedDetails() != null) {
|
||||
dbg.resume();
|
||||
}
|
||||
});
|
||||
|
||||
page.click("div");
|
||||
assertNull(dbg.pausedDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPauseAtPauseCall() {
|
||||
page.setContent("<div>click me</div>");
|
||||
Debugger dbg = context.debugger();
|
||||
assertNull(dbg.pausedDetails());
|
||||
|
||||
dbg.requestPause();
|
||||
|
||||
boolean[] paused = {false};
|
||||
dbg.onPausedStateChanged(() -> {
|
||||
if (!paused[0]) {
|
||||
paused[0] = true;
|
||||
PausedDetails details = dbg.pausedDetails();
|
||||
assertNotNull(details);
|
||||
assertTrue(details.title.contains("Pause"), "title: " + details.title);
|
||||
dbg.resume();
|
||||
}
|
||||
});
|
||||
|
||||
page.pause(); // blocks until dbg.resume() is called from event handler
|
||||
assertNull(dbg.pausedDetails());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.Overlay;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
// Note: The overlay elements are rendered inside a closed shadow root in driver mode,
|
||||
// so locator-based DOM assertions are not possible in Java. These tests verify that
|
||||
// the protocol calls succeed without errors.
|
||||
public class TestOverlay extends TestBase {
|
||||
@Test
|
||||
void shouldAddAndRemoveOverlay() throws Exception {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
AutoCloseable disposable = page.overlay().show("<div id=\"my-overlay\">Hello Overlay</div>");
|
||||
assertNotNull(disposable);
|
||||
disposable.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddMultipleOverlays() throws Exception {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
AutoCloseable d1 = page.overlay().show("<div id=\"overlay-1\">First</div>");
|
||||
AutoCloseable d2 = page.overlay().show("<div id=\"overlay-2\">Second</div>");
|
||||
d1.close();
|
||||
d2.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHideAndShowOverlays() throws Exception {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().show("<div id=\"my-overlay\">Visible</div>");
|
||||
page.overlay().setVisible(false);
|
||||
page.overlay().setVisible(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSurviveNavigation() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().show("<div id=\"persistent\">Survives Reload</div>");
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.reload();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRemoveOverlayAndNotRestoreAfterNavigation() throws Exception {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
AutoCloseable disposable = page.overlay().show("<div id=\"temp\">Temporary</div>");
|
||||
disposable.close();
|
||||
page.reload();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSanitizeScriptsFromOverlayHtml() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().show("<div id=\"safe\">Safe</div><script>window.__injected = true</script>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldStripEventHandlersFromOverlayHtml() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().show("<div id=\"clean\" onclick=\"window.__clicked=true\">Click me</div>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAutoRemoveOverlayAfterTimeout() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().show("<div id=\"timed\">Temporary</div>", new Overlay.ShowOptions().setDuration(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAllowStylesInOverlayHtml() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().show("<div id=\"styled\" style=\"color: red; font-size: 20px;\">Styled</div>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldShowChapter() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.overlay().chapter("Chapter Title");
|
||||
page.overlay().chapter("With Description", new Overlay.ChapterOptions().setDescription("Some details").setDuration(100));
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,35 @@ public class TestPageNetworkResponse extends TestBase {
|
||||
assertTrue(e.getMessage().contains("closed"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnNullExistingResponseBeforeResponseReceived() {
|
||||
Request[] capturedRequest = {null};
|
||||
page.route("**/*", route -> {
|
||||
capturedRequest[0] = route.request();
|
||||
assertNull(capturedRequest[0].existingResponse());
|
||||
route.resume();
|
||||
});
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertNotNull(capturedRequest[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnExistingResponseAfterReceived() {
|
||||
Response[] responses = {null};
|
||||
page.onResponse(r -> responses[0] = r);
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertNotNull(responses[0]);
|
||||
assertEquals(responses[0], responses[0].request().existingResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnHttpVersion() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Response response = page.waitForResponse("**/*", () -> page.navigate(server.EMPTY_PAGE));
|
||||
String version = response.httpVersion();
|
||||
assertTrue(version.matches("HTTP/[12](\\.[01])?"), "unexpected version: " + version);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectResponseFinishedIfContextCloses() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
|
||||
@ -1 +1 @@
|
||||
1.59.0-alpha-1774287265000
|
||||
1.59.0-alpha-1774622285000
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user