Skip to content

Commit

Permalink
SoftAssertions Implementation (microsoft#1340)
Browse files Browse the repository at this point in the history
  • Loading branch information
uchagani committed Aug 17, 2023
1 parent f76af33 commit 632fba5
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.microsoft.playwright.assertions;

import com.microsoft.playwright.Page;
import com.microsoft.playwright.impl.PageAssertionsImpl;

import java.util.List;
import java.util.regex.Pattern;

class PageAssertionsImplProxy extends SoftAssertionsBase implements PageAssertions {
private final PageAssertionsImpl pageAssertions;

PageAssertionsImplProxy(Page page, List<Throwable> results) {
super(results);
this.pageAssertions = new PageAssertionsImpl(page);
}

private PageAssertionsImplProxy(List<Throwable> results, PageAssertionsImpl pageAssertions) {
super(results);
this.pageAssertions = pageAssertions;
}

@Override
public PageAssertions not() {
return new PageAssertionsImplProxy(super.results, (PageAssertionsImpl) pageAssertions.not());
}

@Override
public void hasTitle(String titleOrRegExp, HasTitleOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
}

@Override
public void hasTitle(Pattern titleOrRegExp, HasTitleOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
}

@Override
public void hasURL(String urlOrRegExp, HasURLOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
}

@Override
public void hasURL(Pattern urlOrRegExp, HasURLOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.microsoft.playwright.assertions;

import com.microsoft.playwright.Page;
import com.microsoft.playwright.impl.PageAssertionsImpl;

import java.util.List;
import java.util.regex.Pattern;

class PageAssertionsProxy extends SoftAssertionsBase implements PageAssertions {
private final PageAssertionsImpl pageAssertions;

PageAssertionsProxy(Page page, List<Throwable> results) {
super(results);
this.pageAssertions = new PageAssertionsImpl(page);
}

@Override
public PageAssertions not() {
return pageAssertions.not();
}

@Override
public void hasTitle(String titleOrRegExp, HasTitleOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
}

@Override
public void hasTitle(Pattern titleOrRegExp, HasTitleOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
}

@Override
public void hasURL(String urlOrRegExp, HasURLOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
}

@Override
public void hasURL(Pattern urlOrRegExp, HasURLOptions options) {
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.microsoft.playwright.assertions;

import com.microsoft.playwright.Page;

public interface SoftAssertions {
PageAssertions assertThat(Page page);

void assertAll();

static SoftAssertions create() {
return new SoftAssertionsImpl();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.microsoft.playwright.assertions;

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

import java.util.List;

class SoftAssertionsBase {
final List<Throwable> results;

public SoftAssertionsBase(List<Throwable> results) {
this.results = results;
}

void assertAndCaptureResult(Runnable assertion) {
try {
assertion.run();
} catch (AssertionFailedError | PlaywrightException failure) {
results.add(failure);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.microsoft.playwright.assertions;

import com.microsoft.playwright.Page;
import org.opentest4j.AssertionFailedError;

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

class SoftAssertionsImpl implements SoftAssertions {
final List<Throwable> results;

SoftAssertionsImpl() {
this.results = new ArrayList<>();
}

@Override
public PageAssertions assertThat(Page page) {
return new PageAssertionsImplProxy(page, results);
}

@Override
public void assertAll() {
if (!results.isEmpty()) {
throw new AssertionFailedError(getFormattedErrorMessage());
}
}

private String getFormattedErrorMessage() {
StringBuilder message = new StringBuilder();
message
.append(results.size())
.append(" assertion(s) failed:");

for (Throwable t : results) {
message.append("\n");
message.append("----------------------------------------\n");
message.append(t.getMessage());
}

return message.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package com.microsoft.playwright;

import com.microsoft.playwright.assertions.PageAssertions;
import com.microsoft.playwright.assertions.SoftAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opentest4j.AssertionFailedError;

import java.util.regex.Pattern;

import static com.microsoft.playwright.Utils.assertFailureCount;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TestSoftPageAssertions extends TestBase {
private SoftAssertions softly;

@BeforeEach
void beforeEach() {
softly = SoftAssertions.create();
}

@Test
void hasUrlTextPass() {
page.navigate("data:text/html,<div>A</div>");
softly.assertThat(page).hasURL("data:text/html,<div>A</div>");
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasURLTextFail() {
page.navigate("data:text/html,<div>B</div>");
softly.assertThat(page).hasURL("foo", new PageAssertions.HasURLOptions().setTimeout(1_000));
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
assertTrue(e.getMessage().contains("Page URL expected to be"), e.getMessage());
assertFailureCount(softly, 1);
}

@Test
void shouldSupportHasUrlWithBaseUrl() {
try (BrowserContext context = browser.newContext(new Browser.NewContextOptions().setBaseURL(server.PREFIX))) {
Page page = context.newPage();
page.navigate(server.EMPTY_PAGE);
softly.assertThat(page).hasURL("/empty.html", new PageAssertions.HasURLOptions().setTimeout(1_000));
softly.assertAll();
assertFailureCount(softly, 0);
}
}

@Test
void notHasUrlText() {
page.navigate("data:text/html,<div>B</div>");
softly.assertThat(page).not().hasURL("about:blank", new PageAssertions.HasURLOptions().setTimeout(1000));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasURLRegexPass() {
page.navigate("data:text/html,<div>A</div>");
softly.assertThat(page).hasURL(Pattern.compile("text"));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasURLRegexFail() {
page.navigate(server.EMPTY_PAGE);
softly.assertThat(page).hasURL(Pattern.compile(".*foo.*"), new PageAssertions.HasURLOptions().setTimeout(1_000));
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
assertTrue(e.getMessage().contains("Page URL expected to match regex"), e.getMessage());
assertFailureCount(softly, 1);
}

@Test
void notHasUrlRegEx() {
page.navigate("data:text/html,<div>B</div>");
softly.assertThat(page).not().hasURL(Pattern.compile("about"), new PageAssertions.HasURLOptions().setTimeout(1000));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasTitleTextPass() {
page.navigate(server.PREFIX + "/title.html");
softly.assertThat(page).hasTitle("Woof-Woof", new PageAssertions.HasTitleOptions().setTimeout(1_000));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasTitleTextNormalizeWhitespaces() {
page.setContent("<title> Foo Bar </title>");
softly.assertThat(page).hasTitle(" Foo Bar", new PageAssertions.HasTitleOptions().setTimeout(1_000));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasTitleTextFail() {
page.navigate(server.PREFIX + "/title.html");
softly.assertThat(page).hasTitle("foo", new PageAssertions.HasTitleOptions().setTimeout(1_000));
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
assertTrue(e.getMessage().contains("Page title expected to be: foo\nReceived: Woof-Woof"), e.getMessage());
assertFailureCount(softly, 1);
}

@Test
void hasTitleRegexPass() {
page.navigate(server.PREFIX + "/title.html");
softly.assertThat(page).hasTitle(Pattern.compile("^.oof.+oof$"));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasTitleRegexFail() {
page.navigate(server.PREFIX + "/title.html");
softly.assertThat(page).hasTitle(Pattern.compile("^foo[AB]"), new PageAssertions.HasTitleOptions().setTimeout(1_000));
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
assertTrue(e.getMessage().contains("Page title expected to match regex: ^foo[AB]\nReceived: Woof-Woof"), e.getMessage());
assertFailureCount(softly, 1);
}

@Test
void notHasTitleRegEx() {
page.navigate(server.PREFIX + "/title.html");
softly.assertThat(page).not().hasTitle(Pattern.compile("ab.ut"));
softly.assertAll();
assertFailureCount(softly, 0);
}

@Test
void hasTitleRegExCaseInsensitivePass() {
page.navigate(server.PREFIX + "/title.html");
softly.assertThat(page).hasTitle(Pattern.compile("woof-woof", Pattern.CASE_INSENSITIVE));
softly.assertAll();
assertFailureCount(softly, 0);
}
}
14 changes: 14 additions & 0 deletions playwright/src/test/java/com/microsoft/playwright/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.microsoft.playwright.assertions.SoftAssertions;

import java.io.*;
import java.lang.reflect.Field;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -214,4 +216,16 @@ static String generateDifferentOriginHostname(final Server server){
static String generateDifferentOriginPort(final Server server){
return server.PREFIX.replace(String.valueOf(server.PORT), String.valueOf(server.PORT+1));
}

static void assertFailureCount(SoftAssertions softAssertions, int expectedCount) {
try {
Class<? extends SoftAssertions> clazz = softAssertions.getClass();
Field resultsField = clazz.getDeclaredField("results");
resultsField.setAccessible(true);
List<Throwable> results = (List<Throwable>) resultsField.get(softAssertions);
assertEquals(results.size(), expectedCount);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

0 comments on commit 632fba5

Please sign in to comment.