Skip to content

Commit 632fba5

Browse files
authored
SoftAssertions Implementation (microsoft#1340)
1 parent f76af33 commit 632fba5

7 files changed

Lines changed: 324 additions & 0 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.microsoft.playwright.assertions;
2+
3+
import com.microsoft.playwright.Page;
4+
import com.microsoft.playwright.impl.PageAssertionsImpl;
5+
6+
import java.util.List;
7+
import java.util.regex.Pattern;
8+
9+
class PageAssertionsImplProxy extends SoftAssertionsBase implements PageAssertions {
10+
private final PageAssertionsImpl pageAssertions;
11+
12+
PageAssertionsImplProxy(Page page, List<Throwable> results) {
13+
super(results);
14+
this.pageAssertions = new PageAssertionsImpl(page);
15+
}
16+
17+
private PageAssertionsImplProxy(List<Throwable> results, PageAssertionsImpl pageAssertions) {
18+
super(results);
19+
this.pageAssertions = pageAssertions;
20+
}
21+
22+
@Override
23+
public PageAssertions not() {
24+
return new PageAssertionsImplProxy(super.results, (PageAssertionsImpl) pageAssertions.not());
25+
}
26+
27+
@Override
28+
public void hasTitle(String titleOrRegExp, HasTitleOptions options) {
29+
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
30+
}
31+
32+
@Override
33+
public void hasTitle(Pattern titleOrRegExp, HasTitleOptions options) {
34+
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
35+
}
36+
37+
@Override
38+
public void hasURL(String urlOrRegExp, HasURLOptions options) {
39+
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
40+
}
41+
42+
@Override
43+
public void hasURL(Pattern urlOrRegExp, HasURLOptions options) {
44+
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
45+
}
46+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.microsoft.playwright.assertions;
2+
3+
import com.microsoft.playwright.Page;
4+
import com.microsoft.playwright.impl.PageAssertionsImpl;
5+
6+
import java.util.List;
7+
import java.util.regex.Pattern;
8+
9+
class PageAssertionsProxy extends SoftAssertionsBase implements PageAssertions {
10+
private final PageAssertionsImpl pageAssertions;
11+
12+
PageAssertionsProxy(Page page, List<Throwable> results) {
13+
super(results);
14+
this.pageAssertions = new PageAssertionsImpl(page);
15+
}
16+
17+
@Override
18+
public PageAssertions not() {
19+
return pageAssertions.not();
20+
}
21+
22+
@Override
23+
public void hasTitle(String titleOrRegExp, HasTitleOptions options) {
24+
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
25+
}
26+
27+
@Override
28+
public void hasTitle(Pattern titleOrRegExp, HasTitleOptions options) {
29+
assertAndCaptureResult(() -> pageAssertions.hasTitle(titleOrRegExp, options));
30+
}
31+
32+
@Override
33+
public void hasURL(String urlOrRegExp, HasURLOptions options) {
34+
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
35+
}
36+
37+
@Override
38+
public void hasURL(Pattern urlOrRegExp, HasURLOptions options) {
39+
assertAndCaptureResult(() -> pageAssertions.hasURL(urlOrRegExp, options));
40+
}
41+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.microsoft.playwright.assertions;
2+
3+
import com.microsoft.playwright.Page;
4+
5+
public interface SoftAssertions {
6+
PageAssertions assertThat(Page page);
7+
8+
void assertAll();
9+
10+
static SoftAssertions create() {
11+
return new SoftAssertionsImpl();
12+
}
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.microsoft.playwright.assertions;
2+
3+
import com.microsoft.playwright.PlaywrightException;
4+
import org.opentest4j.AssertionFailedError;
5+
6+
import java.util.List;
7+
8+
class SoftAssertionsBase {
9+
final List<Throwable> results;
10+
11+
public SoftAssertionsBase(List<Throwable> results) {
12+
this.results = results;
13+
}
14+
15+
void assertAndCaptureResult(Runnable assertion) {
16+
try {
17+
assertion.run();
18+
} catch (AssertionFailedError | PlaywrightException failure) {
19+
results.add(failure);
20+
}
21+
}
22+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.microsoft.playwright.assertions;
2+
3+
import com.microsoft.playwright.Page;
4+
import org.opentest4j.AssertionFailedError;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
class SoftAssertionsImpl implements SoftAssertions {
10+
final List<Throwable> results;
11+
12+
SoftAssertionsImpl() {
13+
this.results = new ArrayList<>();
14+
}
15+
16+
@Override
17+
public PageAssertions assertThat(Page page) {
18+
return new PageAssertionsImplProxy(page, results);
19+
}
20+
21+
@Override
22+
public void assertAll() {
23+
if (!results.isEmpty()) {
24+
throw new AssertionFailedError(getFormattedErrorMessage());
25+
}
26+
}
27+
28+
private String getFormattedErrorMessage() {
29+
StringBuilder message = new StringBuilder();
30+
message
31+
.append(results.size())
32+
.append(" assertion(s) failed:");
33+
34+
for (Throwable t : results) {
35+
message.append("\n");
36+
message.append("----------------------------------------\n");
37+
message.append(t.getMessage());
38+
}
39+
40+
return message.toString();
41+
}
42+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package com.microsoft.playwright;
2+
3+
import com.microsoft.playwright.assertions.PageAssertions;
4+
import com.microsoft.playwright.assertions.SoftAssertions;
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.Test;
7+
import org.opentest4j.AssertionFailedError;
8+
9+
import java.util.regex.Pattern;
10+
11+
import static com.microsoft.playwright.Utils.assertFailureCount;
12+
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
13+
import static org.junit.jupiter.api.Assertions.assertThrows;
14+
import static org.junit.jupiter.api.Assertions.assertTrue;
15+
16+
public class TestSoftPageAssertions extends TestBase {
17+
private SoftAssertions softly;
18+
19+
@BeforeEach
20+
void beforeEach() {
21+
softly = SoftAssertions.create();
22+
}
23+
24+
@Test
25+
void hasUrlTextPass() {
26+
page.navigate("data:text/html,<div>A</div>");
27+
softly.assertThat(page).hasURL("data:text/html,<div>A</div>");
28+
softly.assertAll();
29+
assertFailureCount(softly, 0);
30+
}
31+
32+
@Test
33+
void hasURLTextFail() {
34+
page.navigate("data:text/html,<div>B</div>");
35+
softly.assertThat(page).hasURL("foo", new PageAssertions.HasURLOptions().setTimeout(1_000));
36+
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
37+
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
38+
assertTrue(e.getMessage().contains("Page URL expected to be"), e.getMessage());
39+
assertFailureCount(softly, 1);
40+
}
41+
42+
@Test
43+
void shouldSupportHasUrlWithBaseUrl() {
44+
try (BrowserContext context = browser.newContext(new Browser.NewContextOptions().setBaseURL(server.PREFIX))) {
45+
Page page = context.newPage();
46+
page.navigate(server.EMPTY_PAGE);
47+
softly.assertThat(page).hasURL("/empty.html", new PageAssertions.HasURLOptions().setTimeout(1_000));
48+
softly.assertAll();
49+
assertFailureCount(softly, 0);
50+
}
51+
}
52+
53+
@Test
54+
void notHasUrlText() {
55+
page.navigate("data:text/html,<div>B</div>");
56+
softly.assertThat(page).not().hasURL("about:blank", new PageAssertions.HasURLOptions().setTimeout(1000));
57+
softly.assertAll();
58+
assertFailureCount(softly, 0);
59+
}
60+
61+
@Test
62+
void hasURLRegexPass() {
63+
page.navigate("data:text/html,<div>A</div>");
64+
softly.assertThat(page).hasURL(Pattern.compile("text"));
65+
softly.assertAll();
66+
assertFailureCount(softly, 0);
67+
}
68+
69+
@Test
70+
void hasURLRegexFail() {
71+
page.navigate(server.EMPTY_PAGE);
72+
softly.assertThat(page).hasURL(Pattern.compile(".*foo.*"), new PageAssertions.HasURLOptions().setTimeout(1_000));
73+
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
74+
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
75+
assertTrue(e.getMessage().contains("Page URL expected to match regex"), e.getMessage());
76+
assertFailureCount(softly, 1);
77+
}
78+
79+
@Test
80+
void notHasUrlRegEx() {
81+
page.navigate("data:text/html,<div>B</div>");
82+
softly.assertThat(page).not().hasURL(Pattern.compile("about"), new PageAssertions.HasURLOptions().setTimeout(1000));
83+
softly.assertAll();
84+
assertFailureCount(softly, 0);
85+
}
86+
87+
@Test
88+
void hasTitleTextPass() {
89+
page.navigate(server.PREFIX + "/title.html");
90+
softly.assertThat(page).hasTitle("Woof-Woof", new PageAssertions.HasTitleOptions().setTimeout(1_000));
91+
softly.assertAll();
92+
assertFailureCount(softly, 0);
93+
}
94+
95+
@Test
96+
void hasTitleTextNormalizeWhitespaces() {
97+
page.setContent("<title> Foo Bar </title>");
98+
softly.assertThat(page).hasTitle(" Foo Bar", new PageAssertions.HasTitleOptions().setTimeout(1_000));
99+
softly.assertAll();
100+
assertFailureCount(softly, 0);
101+
}
102+
103+
@Test
104+
void hasTitleTextFail() {
105+
page.navigate(server.PREFIX + "/title.html");
106+
softly.assertThat(page).hasTitle("foo", new PageAssertions.HasTitleOptions().setTimeout(1_000));
107+
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
108+
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
109+
assertTrue(e.getMessage().contains("Page title expected to be: foo\nReceived: Woof-Woof"), e.getMessage());
110+
assertFailureCount(softly, 1);
111+
}
112+
113+
@Test
114+
void hasTitleRegexPass() {
115+
page.navigate(server.PREFIX + "/title.html");
116+
softly.assertThat(page).hasTitle(Pattern.compile("^.oof.+oof$"));
117+
softly.assertAll();
118+
assertFailureCount(softly, 0);
119+
}
120+
121+
@Test
122+
void hasTitleRegexFail() {
123+
page.navigate(server.PREFIX + "/title.html");
124+
softly.assertThat(page).hasTitle(Pattern.compile("^foo[AB]"), new PageAssertions.HasTitleOptions().setTimeout(1_000));
125+
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> softly.assertAll());
126+
assertTrue(e.getMessage().contains("1 assertion(s) failed"), e.getMessage());
127+
assertTrue(e.getMessage().contains("Page title expected to match regex: ^foo[AB]\nReceived: Woof-Woof"), e.getMessage());
128+
assertFailureCount(softly, 1);
129+
}
130+
131+
@Test
132+
void notHasTitleRegEx() {
133+
page.navigate(server.PREFIX + "/title.html");
134+
softly.assertThat(page).not().hasTitle(Pattern.compile("ab.ut"));
135+
softly.assertAll();
136+
assertFailureCount(softly, 0);
137+
}
138+
139+
@Test
140+
void hasTitleRegExCaseInsensitivePass() {
141+
page.navigate(server.PREFIX + "/title.html");
142+
softly.assertThat(page).hasTitle(Pattern.compile("woof-woof", Pattern.CASE_INSENSITIVE));
143+
softly.assertAll();
144+
assertFailureCount(softly, 0);
145+
}
146+
}

playwright/src/test/java/com/microsoft/playwright/Utils.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
import com.google.gson.Gson;
2020
import com.google.gson.JsonElement;
2121
import com.google.gson.JsonParser;
22+
import com.microsoft.playwright.assertions.SoftAssertions;
2223

2324
import java.io.*;
25+
import java.lang.reflect.Field;
2426
import java.net.ServerSocket;
2527
import java.nio.file.Files;
2628
import java.nio.file.Path;
@@ -214,4 +216,16 @@ static String generateDifferentOriginHostname(final Server server){
214216
static String generateDifferentOriginPort(final Server server){
215217
return server.PREFIX.replace(String.valueOf(server.PORT), String.valueOf(server.PORT+1));
216218
}
219+
220+
static void assertFailureCount(SoftAssertions softAssertions, int expectedCount) {
221+
try {
222+
Class<? extends SoftAssertions> clazz = softAssertions.getClass();
223+
Field resultsField = clazz.getDeclaredField("results");
224+
resultsField.setAccessible(true);
225+
List<Throwable> results = (List<Throwable>) resultsField.get(softAssertions);
226+
assertEquals(results.size(), expectedCount);
227+
} catch (NoSuchFieldException | IllegalAccessException e) {
228+
throw new RuntimeException(e);
229+
}
230+
}
217231
}

0 commit comments

Comments
 (0)