mirror of
https://github.com/microsoft/playwright-java.git
synced 2025-12-27 01:44:01 +00:00
feat: add web-first assertions for page (#657)
This commit is contained in:
parent
38c5dc28a4
commit
b7319c629d
72
assertions/pom.xml
Normal file
72
assertions/pom.xml
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.17.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>assertions</artifactId>
|
||||
<name>Playwright - Assertions</name>
|
||||
<description>
|
||||
This module provides AssertJ Matchers specific to Playwright.
|
||||
</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.opentest4j</groupId>
|
||||
<artifactId>opentest4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import com.microsoft.playwright.Page;
|
||||
|
||||
/**
|
||||
* The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page} state in the
|
||||
* tests.
|
||||
*/
|
||||
public interface PageAssertions {
|
||||
class HasTitleOptions {
|
||||
/**
|
||||
* Time to retry assertion for.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry assertion for.
|
||||
*/
|
||||
public HasTitleOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class HasURLOptions {
|
||||
/**
|
||||
* Time to retry the assertion for.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry the assertion for.
|
||||
*/
|
||||
public HasURLOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Ensures the page has a given title.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
*/
|
||||
default void hasTitle(String titleOrRegExp) {
|
||||
hasTitle(titleOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page has a given title.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
*/
|
||||
void hasTitle(String titleOrRegExp, HasTitleOptions options);
|
||||
/**
|
||||
* Ensures the page has a given title.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
*/
|
||||
default void hasTitle(Pattern titleOrRegExp) {
|
||||
hasTitle(titleOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page has a given title.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
*/
|
||||
void hasTitle(Pattern titleOrRegExp, HasTitleOptions options);
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL('.com');
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected substring or RegExp.
|
||||
*/
|
||||
default void hasURL(String urlOrRegExp) {
|
||||
hasURL(urlOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL('.com');
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected substring or RegExp.
|
||||
*/
|
||||
void hasURL(String urlOrRegExp, HasURLOptions options);
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL('.com');
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected substring or RegExp.
|
||||
*/
|
||||
default void hasURL(Pattern urlOrRegExp) {
|
||||
hasURL(urlOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL('.com');
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected substring or RegExp.
|
||||
*/
|
||||
void hasURL(Pattern urlOrRegExp, HasURLOptions options);
|
||||
/**
|
||||
* Makes the assertion check for the opposite condition. For example, this code tests that the page URL doesn't contain
|
||||
* {@code "error"}:
|
||||
* <pre>{@code
|
||||
* assertThat(page).not().hasURL('error');
|
||||
* }</pre>
|
||||
*/
|
||||
PageAssertions not();
|
||||
}
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
import java.util.*;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.impl.PageAssertionsImpl;
|
||||
|
||||
/**
|
||||
* The {@code PlaywrightAssertions} class provides convenience methods for creating assertions that will wait until the expected
|
||||
* condition is met.
|
||||
*
|
||||
* <p> Consider the following example:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator('.status')).hasText('Submitted');
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Playwright will be re-testing the node with the selector {@code .status} until fetched Node has the {@code "Submitted"} text. It
|
||||
* will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is reached.
|
||||
* You can pass this timeout as an option.
|
||||
*
|
||||
* <p> By default, the timeout for assertions is set to 5 seconds.
|
||||
*/
|
||||
public interface PlaywrightAssertions {
|
||||
/**
|
||||
* Creates a {@code PageAssertions} object for the given {@code Page}.
|
||||
* <pre>{@code
|
||||
* PlaywrightAssertions.assertThat(page).hasTitle("News");
|
||||
* }</pre>
|
||||
*
|
||||
* @param page {@code Page} object to use for assertions.
|
||||
*/
|
||||
static PageAssertions assertThat(Page page) {
|
||||
return new PageAssertionsImpl(page);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.assertions.PageAssertions;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.UrlMatcher.resolveUrl;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class PageAssertionsImpl implements PageAssertions {
|
||||
private final PageImpl actual;
|
||||
private final boolean isNot;
|
||||
|
||||
public PageAssertionsImpl(Page page) {
|
||||
this(page, false);
|
||||
}
|
||||
|
||||
private PageAssertionsImpl(Page page, boolean isNot) {
|
||||
this.actual = (PageImpl) page;
|
||||
this.isNot = isNot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasTitle(String title, HasTitleOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = title;
|
||||
expectImpl("to.have.title", expected, title, "Page title expected to be", options == null ? null : options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasTitle(Pattern pattern, HasTitleOptions options) {
|
||||
//urlOrRegExp.flags();
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.regexSource = pattern.pattern();
|
||||
// expected.regexFlags =
|
||||
expectImpl("to.have.title", expected, pattern, "Page title expected to match regex", options == null ? null : options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasURL(String url, HasURLOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
if (actual.context().baseUrl != null) {
|
||||
url = resolveUrl(actual.context().baseUrl, url);
|
||||
}
|
||||
expected.string = url;
|
||||
expectImpl("to.have.url", expected, url, "Page URL expected to be", options == null ? null : options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasURL(Pattern pattern, HasURLOptions options) {
|
||||
//urlOrRegExp.flags();
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.regexSource = pattern.pattern();
|
||||
// expected.regexFlags =
|
||||
expectImpl("to.have.url", expected, pattern, "Page URL expected to match regex", options == null ? null : options.timeout);
|
||||
}
|
||||
|
||||
private void expectImpl(String expression, ExpectedTextValue textValue, Object expected, String message, Double timeout) {
|
||||
LocatorImpl locator = actual.locator(":root");
|
||||
FrameExpectOptions expectOptions = new FrameExpectOptions();
|
||||
expectOptions.expectedText = asList(textValue);
|
||||
expectOptions.isNot = isNot;
|
||||
expectOptions.timeout = timeout;
|
||||
FrameExpectResult result = locator.expect(expression, expectOptions);
|
||||
if (result.matches == isNot) {
|
||||
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
|
||||
String log = String.join("\n", result.log);
|
||||
if (!log.isEmpty()) {
|
||||
log = "\nCall log:\n" + log;
|
||||
}
|
||||
throw new AssertionFailedError(message + log, expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageAssertions not() {
|
||||
return new PageAssertionsImpl(actual, !isNot);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.assertions.PageAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestPageAssertions extends TestBase {
|
||||
@Test
|
||||
void hasURLTextPass() {
|
||||
page.navigate("data:text/html,<div>A</div>");
|
||||
assertThat(page).hasURL("data:text/html,<div>A</div>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasURLTextFail() {
|
||||
page.navigate("data:text/html,<div>B</div>");
|
||||
try {
|
||||
assertThat(page).hasURL("foo", new PageAssertions.HasURLOptions().setTimeout(1_000));
|
||||
fail("did not throw");
|
||||
} catch (AssertionFailedError e) {
|
||||
assertEquals("foo", e.getExpected().getValue());
|
||||
assertEquals("data:text/html,<div>B</div>", e.getActual().getValue());
|
||||
assertTrue(e.getMessage().contains("Page URL expected to be"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportHasUrlWithBaseUrl() {
|
||||
try (BrowserContext context = browser.newContext(new Browser.NewContextOptions().setBaseURL(server.PREFIX))) {
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertThat(page).hasURL("/empty.html", new PageAssertions.HasURLOptions().setTimeout(1_000));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void notHasUrlText() {
|
||||
page.navigate("data:text/html,<div>B</div>");
|
||||
assertThat(page).not().hasURL("about:blank", new PageAssertions.HasURLOptions().setTimeout(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasURLRegexPass() {
|
||||
page.navigate("data:text/html,<div>A</div>");
|
||||
assertThat(page).hasURL(Pattern.compile("text"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasURLRegexFail() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
try {
|
||||
assertThat(page).hasURL(Pattern.compile(".*foo.*"), new PageAssertions.HasURLOptions().setTimeout(1_000));
|
||||
fail("did not throw");
|
||||
} catch (AssertionFailedError e) {
|
||||
assertEquals(".*foo.*", e.getExpected().getStringRepresentation());
|
||||
assertEquals(server.EMPTY_PAGE, e.getActual().getValue());
|
||||
assertTrue(e.getMessage().contains("Page URL expected to match regex"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void notHasUrlRegEx() {
|
||||
page.navigate("data:text/html,<div>B</div>");
|
||||
assertThat(page).not().hasURL(Pattern.compile("about"), new PageAssertions.HasURLOptions().setTimeout(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasTitleTextPass() {
|
||||
page.navigate(server.PREFIX + "/title.html");
|
||||
assertThat(page).hasTitle("Woof-Woof", new PageAssertions.HasTitleOptions().setTimeout(1_000));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasTitleTextFail() {
|
||||
page.navigate(server.PREFIX + "/title.html");
|
||||
try {
|
||||
assertThat(page).hasTitle("foo", new PageAssertions.HasTitleOptions().setTimeout(1_000));
|
||||
fail("did not throw");
|
||||
} catch (AssertionFailedError e) {
|
||||
assertEquals("foo", e.getExpected().getValue());
|
||||
assertEquals("Woof-Woof", e.getActual().getValue());
|
||||
assertTrue(e.getMessage().contains("Page title expected to be"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasTitleRegexPass() {
|
||||
page.navigate(server.PREFIX + "/title.html");
|
||||
assertThat(page).hasTitle(Pattern.compile("^.oof.+oof$"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasTitleRegexFail() {
|
||||
page.navigate(server.PREFIX + "/title.html");
|
||||
try {
|
||||
assertThat(page).hasTitle(Pattern.compile("^foo[AB]"), new PageAssertions.HasTitleOptions().setTimeout(1_000));
|
||||
fail("did not throw");
|
||||
} catch (AssertionFailedError e) {
|
||||
assertEquals("^foo[AB]", e.getExpected().getStringRepresentation());
|
||||
assertEquals("Woof-Woof", e.getActual().getValue());
|
||||
assertTrue(e.getMessage().contains("Page title expected to match regex"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void notHasTitleRegEx() {
|
||||
page.navigate(server.PREFIX + "/title.html");
|
||||
assertThat(page).not().hasTitle(Pattern.compile("ab.ut"));
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,25 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<targetPath>resources</targetPath>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@ -560,7 +560,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator locator(String selector) {
|
||||
public LocatorImpl locator(String selector) {
|
||||
return new LocatorImpl(this, selector);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.ElementHandle;
|
||||
import com.microsoft.playwright.Frame;
|
||||
import com.microsoft.playwright.JSHandle;
|
||||
@ -13,6 +15,8 @@ import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Serialization.serializeArgument;
|
||||
import static com.microsoft.playwright.impl.Utils.convertViaJson;
|
||||
|
||||
class LocatorImpl implements Locator {
|
||||
@ -415,4 +419,24 @@ class LocatorImpl implements Locator {
|
||||
public String toString() {
|
||||
return "Locator@" + selector;
|
||||
}
|
||||
|
||||
FrameExpectResult expect(String expression, FrameExpectOptions options) {
|
||||
return frame.withLogging("Locator.expect", () -> expectImpl(expression, options));
|
||||
}
|
||||
|
||||
private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
|
||||
if (options == null) {
|
||||
options = new FrameExpectOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", expression);
|
||||
if (options.expectedValue != null) {
|
||||
params.remove("expectedValue");
|
||||
params.add("expectedValue", gson().toJsonTree(serializeArgument(options.expectedValue)));
|
||||
}
|
||||
JsonElement json = frame.sendMessage("expect", params);
|
||||
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -875,7 +875,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator locator(String selector) {
|
||||
public LocatorImpl locator(String selector) {
|
||||
return mainFrame.locator(selector);
|
||||
}
|
||||
|
||||
|
||||
@ -18,18 +18,12 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
class Binary {
|
||||
}
|
||||
import java.util.List;
|
||||
|
||||
class Channel {
|
||||
String guid;
|
||||
}
|
||||
|
||||
class Metadata{
|
||||
String stack;
|
||||
}
|
||||
|
||||
|
||||
class SerializedValue{
|
||||
Number n;
|
||||
Boolean b;
|
||||
@ -51,45 +45,11 @@ class SerializedValue{
|
||||
Number h;
|
||||
}
|
||||
|
||||
|
||||
class SerializedArgument{
|
||||
SerializedValue value;
|
||||
Channel[] handles;
|
||||
}
|
||||
|
||||
class AXNode{
|
||||
String role;
|
||||
String name;
|
||||
String valueString;
|
||||
Number valueNumber;
|
||||
String description;
|
||||
String keyshortcuts;
|
||||
String roledescription;
|
||||
String valuetext;
|
||||
Boolean disabled;
|
||||
Boolean expanded;
|
||||
Boolean focused;
|
||||
Boolean modal;
|
||||
Boolean multiline;
|
||||
Boolean multiselectable;
|
||||
Boolean readonly;
|
||||
Boolean required;
|
||||
Boolean selected;
|
||||
// Possible values: { 'checked, 'unchecked, 'mixed }
|
||||
String checked;
|
||||
// Possible values: { 'pressed, 'released, 'mixed }
|
||||
String pressed;
|
||||
Number level;
|
||||
Number valuemin;
|
||||
Number valuemax;
|
||||
String autocomplete;
|
||||
String haspopup;
|
||||
String invalid;
|
||||
String orientation;
|
||||
AXNode[] children;
|
||||
}
|
||||
|
||||
|
||||
class SerializedError{
|
||||
public static class Error {
|
||||
String message;
|
||||
@ -119,3 +79,28 @@ class SerializedError{
|
||||
}
|
||||
}
|
||||
|
||||
class ExpectedTextValue {
|
||||
String string;
|
||||
String regexSource;
|
||||
String regexFlags;
|
||||
Boolean matchSubstring;
|
||||
Boolean normalizeWhiteSpace;
|
||||
}
|
||||
|
||||
class FrameExpectOptions {
|
||||
Object expressionArg;
|
||||
List<ExpectedTextValue> expectedText;
|
||||
Integer expectedNumber;
|
||||
SerializedArgument expectedValue;
|
||||
Boolean useInnerText;
|
||||
boolean isNot;
|
||||
Double timeout;
|
||||
}
|
||||
|
||||
class FrameExpectResult {
|
||||
boolean matches;
|
||||
SerializedValue received;
|
||||
List<String> log;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ class UrlMatcher {
|
||||
throw new PlaywrightException("Url must be String, Pattern or Predicate<String>, found: " + object.getClass().getTypeName());
|
||||
}
|
||||
|
||||
private static String resolveUrl(URL baseUrl, String spec) {
|
||||
static String resolveUrl(URL baseUrl, String spec) {
|
||||
if (baseUrl == null) {
|
||||
return spec;
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.KeyStore;
|
||||
|
||||
class HttpsConfiguratorImpl extends HttpsConfigurator {
|
||||
@ -52,8 +51,7 @@ class HttpsConfiguratorImpl extends HttpsConfigurator {
|
||||
String password = "password";
|
||||
// Generated via
|
||||
// keytool -genkey -keyalg RSA -validity 36500 -keysize 4096 -dname cn=Playwright,ou=Playwright,o=Playwright,c=US -keystore keystore.jks -storepass password -keypass password
|
||||
ks.load(new FileInputStream("src/test/resources/keys/keystore.jks"), password.toCharArray());
|
||||
|
||||
ks.load(HttpsConfiguratorImpl.class.getClassLoader().getResourceAsStream("resources/keys/keystore.jks"), password.toCharArray());
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(ks, password.toCharArray());
|
||||
|
||||
|
||||
@ -35,7 +35,6 @@ public class Server implements HttpHandler {
|
||||
public final String CROSS_PROCESS_PREFIX;
|
||||
public final int PORT;
|
||||
public final String EMPTY_PAGE;
|
||||
private final File resourcesDir;
|
||||
|
||||
private final Map<String, CompletableFuture<Request>> requestSubscribers = Collections.synchronizedMap(new HashMap<>());
|
||||
private final Map<String, Auth> auths = Collections.synchronizedMap(new HashMap<>());
|
||||
@ -79,7 +78,6 @@ public class Server implements HttpHandler {
|
||||
server.setExecutor(null); // creates a default executor
|
||||
|
||||
File cwd = FileSystems.getDefault().getPath(".").toFile();
|
||||
resourcesDir = new File(cwd, "src/test/resources");
|
||||
server.start();
|
||||
}
|
||||
|
||||
@ -192,21 +190,24 @@ public class Server implements HttpHandler {
|
||||
if ("/".equals(path)) {
|
||||
path = "/index.html";
|
||||
}
|
||||
File file = new File(resourcesDir, path.substring(1));
|
||||
if (!file.exists()) {
|
||||
|
||||
// Resources from "src/test/resources/" are copied to "resources/" directory in the jar.
|
||||
String resourcePath = "resources" + path;
|
||||
InputStream resource = getClass().getClassLoader().getResourceAsStream(resourcePath);
|
||||
if (resource == null) {
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write("File not found: " + file.getCanonicalPath());
|
||||
writer.write("File not found: " + resourcePath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
exchange.getResponseHeaders().add("Content-Type", mimeType(file));
|
||||
exchange.getResponseHeaders().add("Content-Type", mimeType(new File(resourcePath)));
|
||||
ByteArrayOutputStream body = new ByteArrayOutputStream();
|
||||
OutputStream output = body;
|
||||
if (gzipRoutes.contains(path)) {
|
||||
exchange.getResponseHeaders().add("Content-Encoding", "gzip");
|
||||
}
|
||||
try (FileInputStream input = new FileInputStream(file)) {
|
||||
try (InputStream input = resource) {
|
||||
if (gzipRoutes.contains(path)) {
|
||||
output = new GZIPOutputStream(output);
|
||||
}
|
||||
|
||||
@ -47,8 +47,6 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
fail("did not throw");
|
||||
} catch (TimeoutError e) {
|
||||
assertTrue(e.getMessage().contains("Timeout 5000ms exceeded"));
|
||||
// assertTrue(e.getMessage().contains("waiting for navigation to '**/frame.html' until 'load'"));
|
||||
// assertTrue(e.getMessage().contains("navigated to '${server.EMPTY_PAGE}'"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
pom.xml
7
pom.xml
@ -39,6 +39,7 @@
|
||||
<module>driver</module>
|
||||
<module>driver-bundle</module>
|
||||
<module>playwright</module>
|
||||
<module>assertions</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
@ -47,6 +48,7 @@
|
||||
<junit.version>5.7.0</junit.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<websocket.version>1.5.1</websocket.version>
|
||||
<opentest4j.version>1.2.0</opentest4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -66,6 +68,11 @@
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.opentest4j</groupId>
|
||||
<artifactId>opentest4j</artifactId>
|
||||
<version>${opentest4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
||||
@ -1 +1 @@
|
||||
1.16.0-1634781227000
|
||||
1.17.0-next-1634863457000
|
||||
|
||||
@ -24,6 +24,7 @@ import com.google.gson.JsonObject;
|
||||
import java.io.*;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@ -627,6 +628,14 @@ class Method extends Element {
|
||||
output.add(offset + "}");
|
||||
return;
|
||||
}
|
||||
if ("PlaywrightAssertions.assertThat".equals(jsonPath)) {
|
||||
writeJavadoc(params, output, offset);
|
||||
output.add(offset + "static PageAssertions assertThat(Page page) {");
|
||||
output.add(offset + " return new PageAssertionsImpl(page);");
|
||||
output.add(offset + "}");
|
||||
output.add("");
|
||||
return;
|
||||
}
|
||||
int numOverloads = 1;
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
if (params.get(i).type.isTypeUnion()) {
|
||||
@ -844,9 +853,7 @@ class Interface extends TypeDefinition {
|
||||
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
|
||||
" * See the License for the specific language governing permissions and\n" +
|
||||
" * limitations under the License.\n" +
|
||||
" */\n" +
|
||||
"\n" +
|
||||
"package com.microsoft.playwright;\n";
|
||||
" */\n";
|
||||
|
||||
private static Set<String> allowedBaseInterfaces = new HashSet<>(asList("Browser", "JSHandle", "BrowserContext"));
|
||||
private static Set<String> autoCloseableInterfaces = new HashSet<>(asList("Playwright", "Browser", "BrowserContext", "Page"));
|
||||
@ -877,7 +884,6 @@ class Interface extends TypeDefinition {
|
||||
}
|
||||
|
||||
void writeTo(List<String> output, String offset) {
|
||||
output.add(header);
|
||||
if ("Playwright".equals(jsonName)) {
|
||||
output.add("import com.microsoft.playwright.impl.PlaywrightImpl;");
|
||||
}
|
||||
@ -900,9 +906,20 @@ class Interface extends TypeDefinition {
|
||||
if (asList("Page", "Frame", "BrowserContext", "WebSocket").contains(jsonName)) {
|
||||
output.add("import java.util.function.Predicate;");
|
||||
}
|
||||
if (asList("Page", "Frame", "BrowserContext").contains(jsonName)) {
|
||||
if (asList("Page", "Frame", "BrowserContext", "PageAssertions").contains(jsonName)) {
|
||||
output.add("import java.util.regex.Pattern;");
|
||||
}
|
||||
if ("PlaywrightAssertions".equals(jsonName)) {
|
||||
output.add("import com.microsoft.playwright.Page;");
|
||||
output.add("import com.microsoft.playwright.Locator;");
|
||||
output.add("import com.microsoft.playwright.impl.PageAssertionsImpl;");
|
||||
}
|
||||
if ("PageAssertions".equals(jsonName)) {
|
||||
output.add("import com.microsoft.playwright.Page;");
|
||||
}
|
||||
if ("LocatorAssertions".equals(jsonName)) {
|
||||
output.add("import com.microsoft.playwright.Locator;");
|
||||
}
|
||||
output.add("");
|
||||
|
||||
List<String> superInterfaces = new ArrayList<>();
|
||||
@ -1062,10 +1079,22 @@ public class ApiGenerator {
|
||||
ApiGenerator(Reader reader) throws IOException {
|
||||
JsonArray api = new Gson().fromJson(reader, JsonArray.class);
|
||||
File cwd = FileSystems.getDefault().getPath(".").toFile();
|
||||
filterOtherLangs(api, new Stack<>());
|
||||
|
||||
File dir = new File(cwd, "playwright/src/main/java/com/microsoft/playwright");
|
||||
System.out.println("Writing files to: " + dir.getCanonicalPath());
|
||||
Stack<String> path = new Stack<>();
|
||||
filterOtherLangs(api, path);
|
||||
generate(api, dir, "com.microsoft.playwright", isAssertion().negate());
|
||||
|
||||
File assertionsDir = new File(cwd,"assertions/src/main/java/com/microsoft/playwright/assertions");
|
||||
System.out.println("Writing assertion files to: " + dir.getCanonicalPath());
|
||||
generate(api, assertionsDir, "com.microsoft.playwright.assertions", isAssertion());
|
||||
}
|
||||
|
||||
private static Predicate<String> isAssertion() {
|
||||
return className -> className.toLowerCase().contains("assert");
|
||||
}
|
||||
|
||||
private void generate(JsonArray api, File dir, String packageName, Predicate<String> classFilter) throws IOException {
|
||||
Map<String, TypeDefinition> topLevelTypes = new HashMap<>();
|
||||
for (JsonElement entry: api) {
|
||||
String name = entry.getAsJsonObject().get("name").getAsString();
|
||||
@ -1073,17 +1102,26 @@ public class ApiGenerator {
|
||||
if (asList("PlaywrightException", "TimeoutError").contains(name)) {
|
||||
continue;
|
||||
}
|
||||
if (!classFilter.test(name)) {
|
||||
continue;
|
||||
}
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add(Interface.header);
|
||||
lines.add("package " + packageName + ";");
|
||||
lines.add("");
|
||||
new Interface(entry.getAsJsonObject(), topLevelTypes).writeTo(lines, "");
|
||||
String text = String.join("\n", lines);
|
||||
try (FileWriter writer = new FileWriter(new File(dir, name + ".java"))) {
|
||||
writer.write(text);
|
||||
}
|
||||
}
|
||||
|
||||
dir = new File(dir, "options");
|
||||
for (TypeDefinition e : topLevelTypes.values()) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add(Interface.header.replace("package com.microsoft.playwright;", "package com.microsoft.playwright.options;"));
|
||||
lines.add(Interface.header);
|
||||
lines.add("package " + packageName + ".options;");
|
||||
lines.add("");
|
||||
e.writeTo(lines, "");
|
||||
String text = String.join("\n", lines);
|
||||
try (FileWriter writer = new FileWriter(new File(dir, e.name() + ".java"))) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user