chore: roll 1.32.0-alpha driver (#1223)

This commit is contained in:
Yury Semikhatsky 2023-03-10 10:05:19 -08:00 committed by GitHub
parent 2db2762a0d
commit f8fc1068bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 240 additions and 77 deletions

View File

@ -11,7 +11,7 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->111.0.5563.19<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->111.0.5563.64<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->109.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

View File

@ -175,6 +175,18 @@ public interface BrowserContext extends AutoCloseable {
}
}
class RouteFromHAROptions {
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} is specified, resources are persisted as separate files or entries in the ZIP archive. If {@code embed}
* is specified, content is stored inline the HAR file
*/
public HarContentPolicy content;
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* minimal}.
*/
public HarMode mode;
/**
* <ul>
* <li> If set to 'abort' any request not found in the HAR file will be aborted.</li>
@ -195,6 +207,24 @@ public interface BrowserContext extends AutoCloseable {
*/
public Object url;
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} is specified, resources are persisted as separate files or entries in the ZIP archive. If {@code embed}
* is specified, content is stored inline the HAR file
*/
public RouteFromHAROptions setContent(HarContentPolicy content) {
this.content = content;
return this;
}
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* minimal}.
*/
public RouteFromHAROptions setMode(HarMode mode) {
this.mode = mode;
return this;
}
/**
* <ul>
* <li> If set to 'abort' any request not found in the HAR file will be aborted.</li>

View File

@ -4886,24 +4886,7 @@ public interface Frame {
*/
void waitForLoadState(LoadState state, WaitForLoadStateOptions options);
/**
* Waits for the frame navigation and returns the main resource response. In case of multiple redirects, the navigation
* will resolve with the response of the last redirect. In case of navigation to a different anchor or navigation due to
* History API usage, the navigation will resolve with {@code null}.
*
* <p> **Usage**
*
* <p> This method waits for the frame to navigate to a new URL. It is useful for when you run code which will indirectly cause
* the frame to navigate. Consider this example:
* <pre>{@code
* // The method returns after navigation has finished
* frame.waitForNavigation(() -> {
* // Clicking the link will indirectly cause a navigation
* frame.click("a.delayed-navigation");
* });
* }</pre>
*
* <p> <strong>NOTE:</strong> Usage of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API">History API</a> to change the URL is
* considered a navigation.
* @deprecated This method is inherently racy, please use {@link Frame#waitForURL Frame.waitForURL()} instead.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.8
@ -4912,24 +4895,7 @@ public interface Frame {
return waitForNavigation(null, callback);
}
/**
* Waits for the frame navigation and returns the main resource response. In case of multiple redirects, the navigation
* will resolve with the response of the last redirect. In case of navigation to a different anchor or navigation due to
* History API usage, the navigation will resolve with {@code null}.
*
* <p> **Usage**
*
* <p> This method waits for the frame to navigate to a new URL. It is useful for when you run code which will indirectly cause
* the frame to navigate. Consider this example:
* <pre>{@code
* // The method returns after navigation has finished
* frame.waitForNavigation(() -> {
* // Clicking the link will indirectly cause a navigation
* frame.click("a.delayed-navigation");
* });
* }</pre>
*
* <p> <strong>NOTE:</strong> Usage of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API">History API</a> to change the URL is
* considered a navigation.
* @deprecated This method is inherently racy, please use {@link Frame#waitForURL Frame.waitForURL()} instead.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.8

View File

@ -899,11 +899,11 @@ public interface FrameLocator {
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element.
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.17
*/
default Locator locator(String selector) {
return locator(selector, null);
default Locator locator(String selectorOrLocator) {
return locator(selectorOrLocator, null);
}
/**
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
@ -911,10 +911,32 @@ public interface FrameLocator {
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element.
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.17
*/
Locator locator(String selector, LocatorOptions options);
Locator locator(String selectorOrLocator, LocatorOptions options);
/**
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.17
*/
default Locator locator(Locator selectorOrLocator) {
return locator(selectorOrLocator, null);
}
/**
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.17
*/
Locator locator(Locator selectorOrLocator, LocatorOptions options);
/**
* Returns locator to the n-th matching frame. It's zero based, {@code nth(0)} selects the first frame.
*

View File

@ -2821,10 +2821,10 @@ public interface Locator {
* locator.click();
* }</pre>
*
* @param selector A selector to use when resolving DOM element.
* @param selectorOrLocator A selector to use when resolving DOM element.
* @since v1.17
*/
FrameLocator frameLocator(String selector);
FrameLocator frameLocator(String selectorOrLocator);
/**
* Returns the matching element's attribute value.
*
@ -3683,11 +3683,11 @@ public interface Locator {
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element.
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.14
*/
default Locator locator(String selector) {
return locator(selector, null);
default Locator locator(String selectorOrLocator) {
return locator(selectorOrLocator, null);
}
/**
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
@ -3695,10 +3695,32 @@ public interface Locator {
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element.
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.14
*/
Locator locator(String selector, LocatorOptions options);
Locator locator(String selectorOrLocator, LocatorOptions options);
/**
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.14
*/
default Locator locator(Locator selectorOrLocator) {
return locator(selectorOrLocator, null);
}
/**
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selectorOrLocator A selector or locator to use when resolving DOM element.
* @since v1.14
*/
Locator locator(Locator selectorOrLocator, LocatorOptions options);
/**
* Returns locator to the n-th matching element. It's zero based, {@code nth(0)} selects the first element.
*

View File

@ -2250,6 +2250,8 @@ public interface Page extends AutoCloseable {
}
}
class RouteFromHAROptions {
public HarContentPolicy content;
public HarMode mode;
/**
* <ul>
* <li> If set to 'abort' any request not found in the HAR file will be aborted.</li>
@ -2270,6 +2272,14 @@ public interface Page extends AutoCloseable {
*/
public Object url;
public RouteFromHAROptions setContent(HarContentPolicy content) {
this.content = content;
return this;
}
public RouteFromHAROptions setMode(HarMode mode) {
this.mode = mode;
return this;
}
/**
* <ul>
* <li> If set to 'abort' any request not found in the HAR file will be aborted.</li>

View File

@ -580,7 +580,7 @@ public interface LocatorAssertions {
*
* <p> **Usage**
* <pre>{@code
* Locator locator = page.locator("button.submit");
* Locator locator = page.getByRole(AriaRole.BUTTON);
* // Make sure at least some part of element intersects viewport.
* assertThat(locator).isInViewport();
* // Make sure element is fully outside of viewport.
@ -600,7 +600,7 @@ public interface LocatorAssertions {
*
* <p> **Usage**
* <pre>{@code
* Locator locator = page.locator("button.submit");
* Locator locator = page.getByRole(AriaRole.BUTTON);
* // Make sure at least some part of element intersects viewport.
* assertThat(locator).isInViewport();
* // Make sure element is fully outside of viewport.

View File

@ -0,0 +1,8 @@
package com.microsoft.playwright.impl;
import com.google.gson.JsonArray;
class CallMetadata {
int id;
JsonArray stack;
}

View File

@ -16,6 +16,7 @@
package com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.microsoft.playwright.Playwright;
@ -24,10 +25,10 @@ import com.microsoft.playwright.TimeoutError;
import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import static com.microsoft.playwright.impl.Serialization.gson;
import static java.lang.System.currentTimeMillis;
class Message {
int id;
@ -67,6 +68,7 @@ public class Connection {
}
LocalUtils localUtils;
final Map<String, String> env;
private Set<List<CallMetadata>> stackCollectors = Collections.newSetFromMap(new IdentityHashMap<>());
class Root extends ChannelOwner {
Root(Connection connection) {
@ -101,8 +103,15 @@ public class Connection {
stackTraceCollector = StackTraceCollector.createFromEnv(env);
}
boolean isCollectingStacks() {
return stackTraceCollector != null;
void startCollectingCallMetadata(List<CallMetadata> collection) {
if (stackTraceCollector == null) {
throw new PlaywrightException("Source root directory must be specified via PLAYWRIGHT_JAVA_SRC environment variable when source collection is enabled");
}
stackCollectors.add(collection);
}
void stopCollectingCallMetadata(List<CallMetadata> collection) {
stackCollectors.remove(collection);
}
String setApiName(String name) {
@ -133,6 +142,7 @@ public class Connection {
message.addProperty("method", method);
message.add("params", params);
JsonObject metadata = new JsonObject();
metadata.addProperty("wallTime", currentTimeMillis());
if (apiName == null) {
metadata.addProperty("internal", true);
} else {
@ -140,7 +150,21 @@ public class Connection {
// All but first message in an API call are considered internal and will be hidden from the inspector.
apiName = null;
if (stackTraceCollector != null) {
metadata.add("stack", stackTraceCollector.currentStackTrace());
JsonArray stack = stackTraceCollector.currentStackTrace();
CallMetadata callMetadata = new CallMetadata();
callMetadata.id = id;
callMetadata.stack = stack;
for (List<CallMetadata> collector : stackCollectors) {
collector.add(callMetadata);
}
if (!stack.isEmpty()) {
JsonObject location = new JsonObject();
JsonObject frame = stack.get(0).getAsJsonObject();
location.addProperty("file", frame.get("file").getAsString());
location.addProperty("line", frame.get("line").getAsInt());
location.addProperty("column", frame.get("column").getAsInt());
metadata.add("location", location);
}
}
}
message.add("metadata", metadata);

View File

@ -18,6 +18,7 @@ package com.microsoft.playwright.impl;
import com.microsoft.playwright.FrameLocator;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.options.AriaRole;
import java.util.regex.Pattern;
@ -119,6 +120,15 @@ class FrameLocatorImpl implements FrameLocator {
return new LocatorImpl(frame, frameSelector + " >> internal:control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
}
@Override
public Locator locator(Locator selectorOrLocator, LocatorOptions options) {
LocatorImpl other = (LocatorImpl) selectorOrLocator;
if (other.frame != frame) {
throw new PlaywrightException("Locators must belong to the same frame.");
}
return locator(other.selector, options);
}
@Override
public FrameLocator nth(int index) {
return new FrameLocatorImpl(frame, frameSelector + " >> nth=" + index);

View File

@ -20,16 +20,22 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.nio.file.Path;
import java.util.List;
import static com.microsoft.playwright.impl.Serialization.gson;
class LocalUtils extends ChannelOwner {
LocalUtils(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
void zip(Path zipFile, JsonArray entries) {
void zip(Path zipFile, JsonArray entries, List<CallMetadata> metadata, boolean appendMode, boolean includeSources) {
JsonObject params = new JsonObject();
params.addProperty("zipFile", zipFile.toString());
params.add("entries", entries);
params.addProperty("mode", appendMode ? "append" : "write");
params.add("metadata", gson().toJsonTree(metadata));
params.addProperty("includeSources", includeSources);
sendMessage("zip", params);
}
}

View File

@ -20,8 +20,8 @@ import static com.microsoft.playwright.impl.Utils.convertType;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
class LocatorImpl implements Locator {
private final FrameImpl frame;
private final String selector;
final FrameImpl frame;
final String selector;
public LocatorImpl(FrameImpl frame, String selector, LocatorOptions options) {
this.frame = frame;
@ -384,6 +384,15 @@ class LocatorImpl implements Locator {
return new LocatorImpl(frame, this.selector + " >> " + selector, options);
}
@Override
public Locator locator(Locator selectorOrLocator, LocatorOptions options) {
LocatorImpl other = (LocatorImpl) selectorOrLocator;
if (other.frame != frame) {
throw new PlaywrightException("Locators must belong to the same frame.");
}
return locator(other.selector, options);
}
@Override
public Locator nth(int index) {
return new LocatorImpl(frame, selector + " >> nth=" + index, null);

View File

@ -118,6 +118,7 @@ class StackTraceCollector {
JsonObject jsonFrame = new JsonObject();
jsonFrame.addProperty("file", sourceFile(frame));
jsonFrame.addProperty("line", frame.getLineNumber());
jsonFrame.addProperty("column", 0);
jsonFrame.addProperty("function", frame.getClassName() + "." + frame.getMethodName());
jsonStack.add(jsonFrame);
}

View File

@ -22,26 +22,45 @@ import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.Tracing;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static com.microsoft.playwright.impl.Serialization.gson;
class TracingImpl extends ChannelOwner implements Tracing {
private boolean includeSources;
private List<CallMetadata> metadataCollector = new ArrayList<>();
TracingImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
}
private void stopChunkImpl(Path path) {
connection.stopCollectingCallMetadata(metadataCollector);
List<CallMetadata> metadata = metadataCollector;
metadataCollector = new ArrayList<>();
JsonObject params = new JsonObject();
String mode = "doNotSave";
if (path != null) {
if (connection.isRemote) {
mode = "compressTrace";
} else {
mode = "compressTraceAndSources";
}
// Not interested in artifacts.
if (path == null) {
params.addProperty("mode", "discard");
sendMessage("tracingStopChunk", params);
return;
}
params.addProperty("mode", mode);
boolean isLocal = !connection.isRemote;
if (isLocal) {
params.addProperty("mode", "entries");
JsonObject json = sendMessage("tracingStopChunk", params).getAsJsonObject();
JsonArray entries = json.getAsJsonArray("entries");
connection.localUtils.zip(path, entries, metadata, false, includeSources);
return;
}
params.addProperty("mode", "archive");
JsonObject json = sendMessage("tracingStopChunk", params).getAsJsonObject();
// The artifact may be missing if the browser closed while stopping tracing.
if (!json.has("artifact")) {
return;
}
@ -52,9 +71,9 @@ class TracingImpl extends ChannelOwner implements Tracing {
// Add local sources to the remote trace if necessary.
// In case of CDP connection since the connection is established by
// the driver it is safe to consider the artifact local.
if (connection.isRemote && json.has("sourceEntries")) {
JsonArray entries = json.getAsJsonArray("sourceEntries");
connection.localUtils.zip(path, entries);
if (json.has("entries")) {
JsonArray entries = json.getAsJsonArray("entries");
connection.localUtils.zip(path, entries, metadata, true, includeSources);
}
}
@ -74,6 +93,10 @@ class TracingImpl extends ChannelOwner implements Tracing {
if (options == null) {
options = new StartChunkOptions();
}
if (includeSources) {
metadataCollector = new ArrayList<>();
connection.startCollectingCallMetadata(metadataCollector);
}
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
sendMessage("tracingStartChunk", params);
}
@ -83,11 +106,10 @@ class TracingImpl extends ChannelOwner implements Tracing {
options = new StartOptions();
}
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
boolean includeSources = options.sources != null && options.sources;
includeSources = options.sources != null && options.sources;
if (includeSources) {
if (!connection.isCollectingStacks()) {
throw new PlaywrightException("Source root directory must be specified via PLAYWRIGHT_JAVA_SRC environment variable when source collection is enabled");
}
metadataCollector = new ArrayList<>();
connection.startCollectingCallMetadata(metadataCollector);
params.addProperty("sources", true);
}
sendMessage("tracingStart", params);

View File

@ -38,6 +38,7 @@ import static com.microsoft.playwright.Utils.copy;
import static com.microsoft.playwright.Utils.extractZip;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static com.microsoft.playwright.options.HarContentPolicy.ATTACH;
import static com.microsoft.playwright.options.HarContentPolicy.EMBED;
import static org.junit.jupiter.api.Assertions.*;
public class TestBrowserContextHar extends TestBase {
@ -430,6 +431,24 @@ public class TestBrowserContextHar extends TestBase {
}
}
@Test
void shouldUpdateHarZipForPageWithDifferentOptions(@TempDir Path tmpDir) {
Path harPath = tmpDir.resolve("har.zip");
try (BrowserContext context1 = browser.newContext()) {
Page page1 = context1.newPage();
page1.routeFromHAR(harPath, new Page.RouteFromHAROptions().setUpdate(true).setContent(EMBED).setMode(HarMode.FULL));
page1.navigate(server.PREFIX + "/one-style.html");
}
try (BrowserContext context2 = browser.newContext()) {
Page page2 = context2.newPage();
page2.routeFromHAR(harPath, new Page.RouteFromHAROptions().setNotFound(HarNotFound.ABORT));
page2.navigate(server.PREFIX + "/one-style.html");
assertTrue(page2.content().contains("hello, world!"));
assertThat(page2.locator("body")).hasCSS("background-color", "rgb(255, 192, 203)");
}
}
@Test
void shouldUpdateExtractedHarZipForPage(@TempDir Path tmpDir) {
Path harPath = tmpDir.resolve("har.har");

View File

@ -12,7 +12,7 @@ public class TestElementHandleSelectText extends TestBase {
ElementHandle textarea = page.querySelector("textarea");
textarea.evaluate("textarea => textarea.value = 'some value'");
textarea.selectText();
if (isFirefox()) {
if (isFirefox() || isWebKit()) {
assertEquals(0, textarea.evaluate("el => el.selectionStart"));
assertEquals(10, textarea.evaluate("el => el.selectionEnd"));
} else {
@ -26,7 +26,7 @@ public class TestElementHandleSelectText extends TestBase {
ElementHandle input = page.querySelector("input");
input.evaluate("input => input.value = 'some value'");
input.selectText();
if (isFirefox()) {
if (isFirefox() || isWebKit()) {
assertEquals(0, input.evaluate("el => el.selectionStart"));
assertEquals(10, input.evaluate("el => el.selectionEnd"));
} else {

View File

@ -102,4 +102,18 @@ public class TestLocatorMisc extends TestBase{
assertTrue(blurred[0]);
assertEquals(false, button.evaluate("button => document.activeElement === button"));
}
@Test
void LocatorLocatorAndFrameLocatorLocatorShouldAcceptLocator() {
page.setContent("<div><input value=outer></div>\n" +
" <iframe srcdoc=\"<div><input value=inner></div>\"></iframe>\n");
Locator inputLocator = page.locator("input");
assertEquals("outer", inputLocator.inputValue());
assertEquals("outer", page.locator("div").locator(inputLocator).inputValue());
assertEquals("inner", page.frameLocator("iframe").locator(inputLocator).inputValue());
assertEquals("inner", page.frameLocator("iframe").locator("div").locator(inputLocator).inputValue());
Locator divLocator = page.locator("div");
assertEquals("outer", divLocator.locator("input").inputValue());
assertEquals("inner", page.frameLocator("iframe").locator(divLocator).locator("input").inputValue());
}
}

View File

@ -1 +1 @@
1.31.0-beta-1676596096000
1.32.0-alpha-1678387519000