Skip to content

Commit

Permalink
feat(roll): roll to ToT Playwright (04-10-24) (#1545)
Browse files Browse the repository at this point in the history
  • Loading branch information
playwrightmachine authored Oct 4, 2024
1 parent ee4033b commit 536f5e8
Show file tree
Hide file tree
Showing 23 changed files with 184 additions and 174 deletions.
96 changes: 50 additions & 46 deletions java/docs/accessibility-testing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,24 @@ For example, you can use [`AxeBuilder.include()`](https://github.com/dequelabs/a
`AxeBuilder.analyze()` will scan the page *in its current state* when you call it. To scan parts of a page that are revealed based on UI interactions, use [Locators](./locators.mdx) to interact with the page before invoking `analyze()`:

```java
@Test
void navigationMenuFlyoutShouldNotHaveAutomaticallyDetectableAccessibilityViolations() throws Exception {
page.navigate("https://your-site.com/");
public class HomepageTests {
@Test
void navigationMenuFlyoutShouldNotHaveAutomaticallyDetectableAccessibilityViolations() throws Exception {
page.navigate("https://your-site.com/");

page.locator("button[aria-label=\"Navigation Menu\"]").click();
page.locator("button[aria-label=\"Navigation Menu\"]").click();

// It is important to waitFor() the page to be in the desired
// state *before* running analyze(). Otherwise, axe might not
// find all the elements your test expects it to scan.
page.locator("#navigation-menu-flyout").waitFor();
// It is important to waitFor() the page to be in the desired
// state *before* running analyze(). Otherwise, axe might not
// find all the elements your test expects it to scan.
page.locator("#navigation-menu-flyout").waitFor();

AxeResults accessibilityScanResults = new AxeBuilder(page)
.include(Arrays.asList("#navigation-menu-flyout"))
.analyze();
AxeResults accessibilityScanResults = new AxeBuilder(page)
.include(Arrays.asList("#navigation-menu-flyout"))
.analyze();

assertEquals(Collections.emptyList(), accessibilityScanResults.getViolations());
assertEquals(Collections.emptyList(), accessibilityScanResults.getViolations());
}
}
```

Expand Down Expand Up @@ -160,38 +162,40 @@ This approach avoids the downsides of using `AxeBuilder.exclude()` at the cost o
Here is an example of using fingerprints based on only rule IDs and "target" selectors pointing to each violation:

```java
@Test
shouldOnlyHaveAccessibilityViolationsMatchingKnownFingerprints() throws Exception {
page.navigate("https://your-site.com/");
public class HomepageTests {
@Test
shouldOnlyHaveAccessibilityViolationsMatchingKnownFingerprints() throws Exception {
page.navigate("https://your-site.com/");

AxeResults accessibilityScanResults = new AxeBuilder(page).analyze();
AxeResults accessibilityScanResults = new AxeBuilder(page).analyze();

List<ViolationFingerprint> violationFingerprints = fingerprintsFromScanResults(accessibilityScanResults);
List<ViolationFingerprint> violationFingerprints = fingerprintsFromScanResults(accessibilityScanResults);

assertEquals(Arrays.asList(
new ViolationFingerprint("aria-roles", "[span[role=\"invalid\"]]"),
new ViolationFingerprint("color-contrast", "[li:nth-child(2) > span]"),
new ViolationFingerprint("label", "[input]")
), violationFingerprints);
}
assertEquals(Arrays.asList(
new ViolationFingerprint("aria-roles", "[span[role=\"invalid\"]]"),
new ViolationFingerprint("color-contrast", "[li:nth-child(2) > span]"),
new ViolationFingerprint("label", "[input]")
), violationFingerprints);
}

// You can make your "fingerprint" as specific as you like. This one considers a violation to be
// "the same" if it corresponds the same Axe rule on the same element.
//
// Using a record type makes it easy to compare fingerprints with assertEquals
public record ViolationFingerprint(String ruleId, String target) { }

public List<ViolationFingerprint> fingerprintsFromScanResults(AxeResults results) {
return results.getViolations().stream()
// Each violation refers to one rule and multiple "nodes" which violate it
.flatMap(violation -> violation.getNodes().stream()
.map(node -> new ViolationFingerprint(
violation.getId(),
// Each node contains a "target", which is a CSS selector that uniquely identifies it
// If the page involves iframes or shadow DOMs, it may be a chain of CSS selectors
node.getTarget().toString()
)))
.collect(Collectors.toList());
// You can make your "fingerprint" as specific as you like. This one considers a violation to be
// "the same" if it corresponds the same Axe rule on the same element.
//
// Using a record type makes it easy to compare fingerprints with assertEquals
public record ViolationFingerprint(String ruleId, String target) { }

public List<ViolationFingerprint> fingerprintsFromScanResults(AxeResults results) {
return results.getViolations().stream()
// Each violation refers to one rule and multiple "nodes" which violate it
.flatMap(violation -> violation.getNodes().stream()
.map(node -> new ViolationFingerprint(
violation.getId(),
// Each node contains a "target", which is a CSS selector that uniquely identifies it
// If the page involves iframes or shadow DOMs, it may be a chain of CSS selectors
node.getTarget().toString()
)))
.collect(Collectors.toList());
}
}
```

Expand All @@ -210,11 +214,11 @@ This example fixture creates an `AxeBuilder` object which is pre-configured with

```java
class AxeTestFixtures extends TestFixtures {
AxeBuilder makeAxeBuilder() {
return new AxeBuilder(page)
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.exclude('#commonly-reused-element-with-known-issue');
}
AxeBuilder makeAxeBuilder() {
return new AxeBuilder(page)
.withTags(new String[]{"wcag2a", "wcag2aa", "wcag21a", "wcag21aa"})
.exclude("#commonly-reused-element-with-known-issue");
}
}
```

Expand All @@ -231,7 +235,7 @@ public class HomepageTests extends AxeTestFixtures {
AxeResults accessibilityScanResults = makeAxeBuilder()
// Automatically uses the shared AxeBuilder configuration,
// but supports additional test-specific configuration too
.include('#specific-element-under-test')
.include("#specific-element-under-test")
.analyze();

assertEquals(Collections.emptyList(), accessibilityScanResults.getViolations());
Expand Down
54 changes: 30 additions & 24 deletions java/docs/api-testing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public class TestGitHubAPI {
These tests assume that repository exists. You probably want to create a new one before running tests and delete it afterwards. Use `@BeforeAll` and `@AfterAll` hooks for that.

```java
public class TestGitHubAPI {
// ...

void createTestRepository() {
Expand Down Expand Up @@ -225,6 +226,7 @@ These tests assume that repository exists. You probably want to create a new one
disposeAPIRequestContext();
closePlaywright();
}
}
```

### Complete test example
Expand Down Expand Up @@ -382,18 +384,20 @@ See experimental [JUnit integration](./junit.mdx) to automatically initialize Pl
The following test creates a new issue via API and then navigates to the list of all issues in the project to check that it appears at the top of the list. The check is performed using [LocatorAssertions].

```java
@Test
void lastCreatedIssueShouldBeFirstInTheList() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Feature] request 1");
data.put("body", "Feature description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());

page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
Locator firstIssue = page.locator("a[data-hovercard-type='issue']").first();
assertThat(firstIssue).hasText("[Feature] request 1");
public class TestGitHubAPI {
@Test
void lastCreatedIssueShouldBeFirstInTheList() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Feature] request 1");
data.put("body", "Feature description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());

page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
Locator firstIssue = page.locator("a[data-hovercard-type='issue']").first();
assertThat(firstIssue).hasText("[Feature] request 1");
}
}
```

Expand All @@ -402,18 +406,20 @@ void lastCreatedIssueShouldBeFirstInTheList() {
The following test creates a new issue via user interface in the browser and then checks via API if it was created:

```java
@Test
void lastCreatedIssueShouldBeOnTheServer() {
page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
page.locator("text=New Issue").click();
page.locator("[aria-label='Title']").fill("Bug report 1");
page.locator("[aria-label='Comment body']").fill("Bug description");
page.locator("text=Submit new issue").click();
String issueId = page.url().substring(page.url().lastIndexOf('/'));

APIResponse newIssue = request.get("https://github.com/" + USER + "/" + REPO + "/issues/" + issueId);
assertThat(newIssue).isOK();
assertTrue(newIssue.text().contains("Bug report 1"));
public class TestGitHubAPI {
@Test
void lastCreatedIssueShouldBeOnTheServer() {
page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
page.locator("text=New Issue").click();
page.locator("[aria-label='Title']").fill("Bug report 1");
page.locator("[aria-label='Comment body']").fill("Bug description");
page.locator("text=Submit new issue").click();
String issueId = page.url().substring(page.url().lastIndexOf('/'));

APIResponse newIssue = request.get("https://github.com/" + USER + "/" + REPO + "/issues/" + issueId);
assertThat(newIssue).isOK();
assertTrue(newIssue.text().contains("Bug report 1"));
}
}
```

Expand Down
8 changes: 4 additions & 4 deletions java/docs/api/class-apiresponseassertions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import HTMLCard from '@site/src/components/HTMLCard';
The [APIResponseAssertions] class provides assertion methods that can be used to make assertions about the [APIResponse] in the tests.

```java
...
// ...
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

public class TestPage {
...
// ...
@Test
void navigatesToLoginPage() {
...
APIResponse response = page.request().get('https://playwright.dev');
// ...
APIResponse response = page.request().get("https://playwright.dev");
assertThat(response).isOK();
}
}
Expand Down
22 changes: 11 additions & 11 deletions java/docs/api/class-browser.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ A Browser is created via [BrowserType.launch()](/api/class-browsertype.mdx#brows
import com.microsoft.playwright.*;

public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
BrowserType firefox = playwright.firefox()
Browser browser = firefox.launch();
Page page = browser.newPage();
page.navigate('https://example.com');
browser.close();
}
}
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
BrowserType firefox = playwright.firefox();
Browser browser = firefox.launch();
Page page = browser.newPage();
page.navigate("https://example.com");
browser.close();
}
}
}
```

Expand Down Expand Up @@ -158,7 +158,7 @@ Browser browser = playwright.firefox().launch(); // Or 'chromium' or 'webkit'.
BrowserContext context = browser.newContext();
// Create a new page in a pristine context.
Page page = context.newPage();
page.navigate('https://example.com');
page.navigate("https://example.com");

// Graceful close up everything
context.close();
Expand Down Expand Up @@ -598,7 +598,7 @@ You can use [Browser.startTracing()](/api/class-browser.mdx#browser-start-tracin
```java
browser.startTracing(page, new Browser.StartTracingOptions()
.setPath(Paths.get("trace.json")));
page.goto('https://www.google.com');
page.navigate("https://www.google.com");
browser.stopTracing();
```

Expand Down
5 changes: 3 additions & 2 deletions java/docs/api/class-browsercontext.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ import com.microsoft.playwright.*;
public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
BrowserType webkit = playwright.webkit()
BrowserType webkit = playwright.webkit();
Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
BrowserContext context = browser.newContext();
context.exposeBinding("pageURL", (source, args) -> source.page().url());
Expand Down Expand Up @@ -367,8 +367,9 @@ import java.util.Base64;
public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
BrowserType webkit = playwright.webkit()
BrowserType webkit = playwright.webkit();
Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
BrowserContext context = browser.newContext();
context.exposeFunction("sha256", args -> {
String text = (String) args[0];
MessageDigest crypto;
Expand Down
4 changes: 2 additions & 2 deletions java/docs/api/class-consolemessage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ ConsoleMessage msg = page.waitForConsoleMessage(() -> {
});

// Deconstruct console.log arguments
msg.args().get(0).jsonValue() // hello
msg.args().get(1).jsonValue() // 42
msg.args().get(0).jsonValue(); // hello
msg.args().get(1).jsonValue(); // 42
```


Expand Down
6 changes: 3 additions & 3 deletions java/docs/api/class-formdata.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The [FormData] is used create form data that is sent via [APIRequestContext].

```java
import com.microsoft.playwright.options.FormData;
...
// ...
FormData form = FormData.create()
.set("firstName", "John")
.set("lastName", "Doe")
Expand All @@ -34,7 +34,7 @@ The difference between [FormData.set()](/api/class-formdata.mdx#form-data-set) a

```java
import com.microsoft.playwright.options.FormData;
...
// ...
FormData form = FormData.create()
// Only name and value are set.
.append("firstName", "John")
Expand Down Expand Up @@ -98,7 +98,7 @@ Sets a field on the form. File values can be passed either as `Path` or as `File

```java
import com.microsoft.playwright.options.FormData;
...
// ...
FormData form = FormData.create()
// Only name and value are set.
.set("firstName", "John")
Expand Down
10 changes: 5 additions & 5 deletions java/docs/api/class-frame.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -600,19 +600,19 @@ You can locate by text substring, exact string, or a regular expression:

```java
// Matches <span>
page.getByText("world")
page.getByText("world");

// Matches first <div>
page.getByText("Hello world")
page.getByText("Hello world");

// Matches second <div>
page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
page.getByText("Hello", new Page.GetByTextOptions().setExact(true));

// Matches both <div>s
page.getByText(Pattern.compile("Hello"))
page.getByText(Pattern.compile("Hello"));

// Matches second <div>
page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
```

**Arguments**
Expand Down
10 changes: 5 additions & 5 deletions java/docs/api/class-framelocator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -318,19 +318,19 @@ You can locate by text substring, exact string, or a regular expression:

```java
// Matches <span>
page.getByText("world")
page.getByText("world");

// Matches first <div>
page.getByText("Hello world")
page.getByText("Hello world");

// Matches second <div>
page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
page.getByText("Hello", new Page.GetByTextOptions().setExact(true));

// Matches both <div>s
page.getByText(Pattern.compile("Hello"))
page.getByText(Pattern.compile("Hello"));

// Matches second <div>
page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
```

**Arguments**
Expand Down
2 changes: 1 addition & 1 deletion java/docs/api/class-keyboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Shortcuts such as `key: "Control+o"`, `key: "Control++` or `key: "Control+Shift+
Page page = browser.newPage();
page.navigate("https://keycode.info");
page.keyboard().press("A");
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png"));
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")));
page.keyboard().press("ArrowLeft");
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png")));
page.keyboard().press("Shift+O");
Expand Down
Loading

0 comments on commit 536f5e8

Please sign in to comment.