1
0
mirror of synced 2026-07-07 09:00:02 +00:00

feat: add web-first assertions for page (#657)

This commit is contained in:
Yury Semikhatsky
2021-10-21 18:22:00 -07:00
committed by GitHub
parent 38c5dc28a4
commit b7319c629d
17 changed files with 635 additions and 65 deletions
@@ -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"));
}
}