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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 Down Expand 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 Down Expand 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 Down Expand 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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

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
Member Author

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 Down Expand 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 Down Expand 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 number Diff line number Diff 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 Down Expand 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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 number Diff line number Diff 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
Loading