Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->138.0.7204.23<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.5<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->139.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |

## Documentation

Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<playwright.version>1.53.0</playwright.version>
<playwright.version>1.54.0</playwright.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -596,7 +596,8 @@ public WaitForPageOptions setTimeout(double timeout) {
*/
List<Page> backgroundPages();
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
* browser, e.g. Android or Electron.
*
* @since v1.8
*/
Expand DownExpand Up@@ -871,6 +872,7 @@ default void exposeBinding(String name, BindingCallback callback) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand DownExpand Up@@ -903,6 +905,7 @@ default void grantPermissions(List<String> permissions) {
* <li> {@code "notifications"}</li>
* <li> {@code "payment-handler"}</li>
* <li> {@code "storage-access"}</li>
* <li> {@code "local-fonts"}</li>
* </ul>
* @since v1.8
*/
Expand Down
5 changes: 5 additions & 0 deletions playwright/src/main/java/com/microsoft/playwright/Mouse.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,11 @@
/**
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
*
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
* mouse will be shown for every mouse action.
*
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
* <pre>{@code
* // Using ‘page.mouse’ to trace a 100x100 square.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@

package com.microsoft.playwright.impl;

import com.microsoft.playwright.PlaywrightException;
import org.opentest4j.AssertionFailedError;
import org.opentest4j.ValueWrapper;

Expand All@@ -29,12 +28,10 @@
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
import static java.util.Arrays.asList;

class AssertionsBase {
final LocatorImpl actualLocator;
abstract class AssertionsBase {
final boolean isNot;

AssertionsBase(LocatorImpl actual, boolean isNot) {
this.actualLocator = actual;
AssertionsBase(boolean isNot) {
this.isNot = isNot;
}

Expand All@@ -58,7 +55,7 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
if (isNot) {
message = message.replace("expected to", "expected not to");
}
FrameExpectResult result = actualLocator.expect(expression, expectOptions, title);
FrameExpectResult result = doExpect(expression, expectOptions, title);
if (result.matches == isNot) {
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
String log = (result.log == null) ? "" : String.join("\n", result.log);
Expand All@@ -75,7 +72,9 @@ void expectImpl(String expression, FrameExpectOptions expectOptions, Object expe
}
}

private static ValueWrapper formatValue(Object value) {
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);

protected static ValueWrapper formatValue(Object value) {
if (value == null || !value.getClass().isArray()) {
return ValueWrapper.create(value);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -506,7 +506,7 @@ private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> han

void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
if (contentPolicy == null) {
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);;
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
}
if (contentPolicy == null) {
contentPolicy = HarContentPolicy.ATTACH;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,13 +20,10 @@
import com.google.gson.JsonObject;
import com.microsoft.playwright.ConsoleMessage;
import com.microsoft.playwright.JSHandle;
import com.microsoft.playwright.Page;

import java.util.ArrayList;
import java.util.List;

import static com.microsoft.playwright.impl.Serialization.gson;

public class ConsoleMessageImpl implements ConsoleMessage {
private final Connection connection;
private PageImpl page;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,7 +993,8 @@ ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions option
@Override
public void waitForTimeout(double timeout) {
JsonObject params = new JsonObject();
sendMessage("waitForTimeout", params, timeout);
params.addProperty("waitTimeout", timeout);
sendMessage("waitForTimeout", params, NO_TIMEOUT);
}

@Override
Expand DownExpand Up@@ -1085,4 +1086,16 @@ protected double navigationTimeout(Double timeout) {
}
return new TimeoutSettings().navigationTimeout(timeout);
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return withTitle(title, () -> expect(expression, options));
}

FrameExpectResult expect(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("expression", expression);
JsonElement json = sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,12 +30,20 @@
import static com.microsoft.playwright.impl.Utils.convertType;

public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
LocatorImpl actualLocator;

public LocatorAssertionsImpl(Locator locator) {
this(locator, false);
}

private LocatorAssertionsImpl(Locator locator, boolean isNot) {
super((LocatorImpl) locator, isNot);
super(isNot);
this.actualLocator = (LocatorImpl) locator;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
return actualLocator.expect(expression, expectOptions, title);
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -645,7 +645,8 @@ public int hashCode() {
}

FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
return frame.withTitle(title, () -> expectImpl(expression, options));
options.selector = selector;
return frame.expect(expression, options, title);
}

JsonObject toProtocol() {
Expand All@@ -654,13 +655,4 @@ JsonObject toProtocol() {
result.addProperty("selector", selector);
return result;
}

private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
params.addProperty("expression", expression);
JsonElement json = frame.sendMessage("expect", params, options.timeout);
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
return result;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,10 +32,16 @@ public PageAssertionsImpl(Page page) {
}

private PageAssertionsImpl(Page page, boolean isNot) {
super((LocatorImpl) page.locator(":root"), isNot);
super(isNot);
this.actualPage = (PageImpl) page;
}

@Override
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
return frame.expect(expression, expectOptions, title);
}

@Override
public void hasTitle(String title, HasTitleOptions options) {
ExpectedTextValue expected = new ExpectedTextValue();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,8 +14,6 @@
* limitations under the License.
*/

// This file is generated by generate_java_rpc.js, do not edit manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore???

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the generate_java_rpc.js file, so I don't think so :D


package com.microsoft.playwright.impl;

import java.util.List;
Expand DownExpand Up@@ -105,6 +103,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
String selector;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,6 +68,10 @@ public void register(String name, Path path, RegisterOptions options) {
}

private void registerImpl(String name, String script, RegisterOptions options) {
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
}

JsonObject engine = new JsonObject();
engine.addProperty("name", name);
engine.addProperty("source", script);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,11 @@ void afterHandle() {
return;
}
// Ensure that websocket is "open" and can send messages without an actual server connection.
sendMessageAsync("ensureOpened");
try {
sendMessageAsync("ensureOpened");
} catch (PlaywrightException e) {
// If this happens after the page has been closed, ignore the error.
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,12 @@ public class Cookie {
* Optional.
*/
public SameSiteAttribute sameSite;
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public String partitionKey;

public Cookie(String name, String value) {
this.name = name;
Expand DownExpand Up@@ -103,4 +109,13 @@ public Cookie setSameSite(SameSiteAttribute sameSite) {
this.sameSite = sameSite;
return this;
}
/**
* For partitioned third-party cookies (aka <a
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
* partition key. Optional.
*/
public Cookie setPartitionKey(String partitionKey) {
this.partitionKey = partitionKey;
return this;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -436,7 +436,7 @@ void shouldSupportTimeoutOption() {
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
});
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand DownExpand Up@@ -468,7 +468,7 @@ void shouldRespectTimeoutAfterRedirects() {

context.setDefaultTimeout(100);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}

@Test
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -174,10 +174,19 @@ void shouldSerialiseStorageStateWithLoneSurrogates() {
@Test
void shouldSupportIndexedDB() {
page.navigate(server.PREFIX + "/to-do-notifications/index.html");

assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: Database initialised."
);
page.locator("label:has-text('Task title')").fill("Pet the cat");
page.locator("label:has-text('Hours')").fill("1");
page.locator("label:has-text('Mins')").fill("1");
page.locator("text=Add Task").click();
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
" - list:\n" +
" - listitem: \"Transaction completed: database modification finished.\""
);

String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,12 +63,22 @@ void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOExc
Path outputTraceFile = tempDir.resolve("trace.json");
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(outputTraceFile)
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
.setCategories(asList("disabled-by-default-cc.debug")));
page.evaluate("() => 1 + 1");
browser.stopTracing();
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
boolean hasTraceConfig =
traceJson.getAsJsonObject("metadata").get("trace-config") != null
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
.anyMatch(event -> {
JsonObject eventObj = (JsonObject) event;
return eventObj.has("cat") &&
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
});
assertTrue(hasTraceConfig || hasTraceEvents);
}
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,7 +189,7 @@ void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
}


Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ public void shouldWaitForHiddenByDefault2() {

PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
assertEquals(0, (int) page.evaluate("window.clicked"));
assertThat(page.locator("#interstitial")).isVisible();
assertTrue(page.locator("#interstitial").isVisible());
assertEquals(1, called[0]);
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
}
Expand Down
Loading