chore: lint java docs snippets (#32945)

This commit is contained in:
Max Schmitt 2024-10-04 11:34:04 +02:00 committed by GitHub
parent 0a45549533
commit 895be9f8de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 349 additions and 157 deletions

View file

@ -38,7 +38,7 @@ jobs:
run: npm audit --omit dev
lint-snippets:
name: "Lint snippets"
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
@ -50,6 +50,12 @@ jobs:
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '21'
- run: npm ci
- run: pip install -r utils/doclint/linting-code-snippets/python/requirements.txt
- run: mvn package
working-directory: utils/doclint/linting-code-snippets/java
- run: node utils/doclint/linting-code-snippets/cli.js

View file

@ -70,22 +70,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.md) 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());
}
}
```
@ -158,38 +160,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) { }
// 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());
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());
}
}
```
@ -208,11 +212,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");
}
}
```
@ -229,7 +233,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());

View file

@ -194,6 +194,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() {
@ -223,6 +224,7 @@ These tests assume that repository exists. You probably want to create a new one
disposeAPIRequestContext();
closePlaywright();
}
}
```
### Complete test example
@ -381,18 +383,20 @@ The following test creates a new issue via API and then navigates to the list of
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());
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");
page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
Locator firstIssue = page.locator("a[data-hovercard-type='issue']").first();
assertThat(firstIssue).hasText("[Feature] request 1");
}
}
```
@ -402,18 +406,20 @@ The following test creates a new issue via user interface in the browser and the
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('/'));
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"));
APIResponse newIssue = request.get("https://github.com/" + USER + "/" + REPO + "/issues/" + issueId);
assertThat(newIssue).isOK();
assertTrue(newIssue.text().contains("Bug report 1"));
}
}
```

View file

@ -14,15 +14,15 @@ test('navigates to login', async ({ page }) => {
```
```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();
}
}

View file

@ -18,15 +18,15 @@ const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'.
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();
}
}
}
```
@ -202,7 +202,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();
@ -331,7 +331,7 @@ await browser.stopTracing();
```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();
```

View file

@ -655,7 +655,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());
@ -813,8 +813,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;

View file

@ -44,8 +44,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
```
```python async

View file

@ -6,7 +6,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")
@ -28,7 +28,7 @@ the new value onto the end of the existing set of values.
```java
import com.microsoft.playwright.options.FormData;
...
// ...
FormData form = FormData.create()
// Only name and value are set.
.append("firstName", "John")
@ -100,7 +100,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")

View file

@ -257,7 +257,7 @@ await browser.close();
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");

View file

@ -38,7 +38,7 @@ for li in page.get_by_role('listitem').all():
```
```java
for (Locator li : page.getByRole('listitem').all())
for (Locator li : page.getByRole("listitem").all())
li.click();
```

View file

@ -14,14 +14,14 @@ test('status becomes submitted', async ({ page }) => {
```
```java
...
// ...
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
public class TestLocator {
...
// ...
@Test
void statusBecomesSubmitted() {
...
// ...
page.getByRole(AriaRole.BUTTON).click();
assertThat(page.locator(".status")).hasText("Submitted");
}
@ -2048,7 +2048,7 @@ await expect(locator).toHaveValues([/R/, /G/]);
```
```java
page.locator("id=favorite-colors").selectOption(["R", "G"]);
page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
```

View file

@ -1041,9 +1041,9 @@ await page.dragAndDrop('#source', '#target', {
```
```java
page.dragAndDrop("#source", '#target');
page.dragAndDrop("#source", "#target");
// or specify exact positions relative to the top-left corners of the elements:
page.dragAndDrop("#source", '#target', new Page.DragAndDropOptions()
page.dragAndDrop("#source", "#target", new Page.DragAndDropOptions()
.setSourcePosition(34, 7).setTargetPosition(10, 20));
```
@ -1716,7 +1716,7 @@ public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
BrowserType webkit = playwright.webkit();
Browser browser = webkit.launch({ headless: false });
Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
BrowserContext context = browser.newContext();
Page page = context.newPage();
page.exposeBinding("pageURL", (source, args) -> source.page().url());
@ -1886,26 +1886,27 @@ public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
BrowserType webkit = playwright.webkit();
Browser browser = webkit.launch({ headless: false });
Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
Page page = browser.newPage();
page.exposeFunction("sha256", args -> {
String text = (String) args[0];
MessageDigest crypto;
try {
crypto = MessageDigest.getInstance("SHA-256");
String text = (String) args[0];
MessageDigest crypto = MessageDigest.getInstance("SHA-256");
byte[] token = crypto.digest(text.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(token);
} catch (NoSuchAlgorithmException e) {
return null;
}
byte[] token = crypto.digest(text.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(token);
});
page.setContent("<script>\n" +
page.setContent(
"<script>\n" +
" async function onClick() {\n" +
" document.querySelector('div').textContent = await window.sha256('PLAYWRIGHT');\n" +
" }\n" +
"</script>\n" +
"<button onclick=\"onClick()\">Click me</button>\n" +
"<div></div>\n");
"<div></div>"
);
page.click("button");
}
}
@ -2106,7 +2107,7 @@ const frame = page.frame({ url: /.*domain.*/ });
```
```java
Frame frame = page.frameByUrl(Pattern.compile(".*domain.*");
Frame frame = page.frameByUrl(Pattern.compile(".*domain.*"));
```
```py
@ -3161,12 +3162,12 @@ await page.getByRole('button', { name: 'Start here' }).click();
```java
// Setup the handler.
page.addLocatorHandler(page.getByText("Sign up to the newsletter"), () => {
page.addLocatorHandler(page.getByText("Sign up to the newsletter"), () -> {
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("No thanks")).click();
});
// Write the test as usual.
page.goto("https://example.com");
page.navigate("https://example.com");
page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
```
@ -3218,12 +3219,12 @@ await page.getByRole('button', { name: 'Start here' }).click();
```java
// Setup the handler.
page.addLocatorHandler(page.getByText("Confirm your security details")), () => {
page.addLocatorHandler(page.getByText("Confirm your security details"), () -> {
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Remind me later")).click();
});
// Write the test as usual.
page.goto("https://example.com");
page.navigate("https://example.com");
page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
```
@ -3275,12 +3276,12 @@ await page.getByRole('button', { name: 'Start here' }).click();
```java
// Setup the handler.
page.addLocatorHandler(page.locator("body")), () => {
page.addLocatorHandler(page.locator("body"), () -> {
page.evaluate("window.removeObstructionsForTestIfNeeded()");
}, new Page.AddLocatorHandlerOptions.setNoWaitAfter(true));
}, new Page.AddLocatorHandlerOptions().setNoWaitAfter(true));
// Write the test as usual.
page.goto("https://example.com");
page.navigate("https://example.com");
page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
```
@ -3326,7 +3327,7 @@ await page.addLocatorHandler(page.getByLabel('Close'), async locator => {
```
```java
page.addLocatorHandler(page.getByLabel("Close"), locator => {
page.addLocatorHandler(page.getByLabel("Close"), locator -> {
locator.click();
}, new Page.AddLocatorHandlerOptions().setTimes(1));
```

View file

@ -14,14 +14,14 @@ test('navigates to login', async ({ page }) => {
```
```java
...
// ...
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
public class TestPage {
...
// ...
@Test
void navigatesToLoginPage() {
...
// ...
page.getByText("Sign in").click();
assertThat(page).hasURL(Pattern.compile(".*/login"));
}

View file

@ -35,14 +35,13 @@ def test_status_becomes_submitted(page: Page) -> None:
```
```java
...
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
public class TestExample {
...
// ...
@Test
void statusBecomesSubmitted() {
...
// ...
page.locator("#submit-button").click();
assertThat(page.locator(".status")).hasText("Submitted");
}

View file

@ -1488,19 +1488,19 @@ page.get_by_text(re.compile("^hello$", re.IGNORECASE))
```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));
```
```csharp

View file

@ -188,7 +188,7 @@ page.setViewportSize(1600, 1200);
// Emulate high-DPI
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
.setViewportSize(2560, 1440)
.setDeviceScaleFactor(2);
.setDeviceScaleFactor(2));
```
```python async
@ -378,7 +378,7 @@ const context = await browser.newContext({
```java
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
.setPermissions(Arrays.asList("notifications"));
.setPermissions(Arrays.asList("notifications")));
```
```python async

View file

@ -122,7 +122,7 @@ await locator.click();
```java
Locator locator = page.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Sign in"))
new Page.GetByRoleOptions().setName("Sign in"));
locator.hover();
locator.click();
@ -946,7 +946,7 @@ page.getByRole(AriaRole.LISTITEM)
.setName("Product 2"))))
.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Add to cart"))
.click()
.click();
```
```python async
@ -987,7 +987,7 @@ assertThat(page
.getByRole(AriaRole.LISTITEM)
.filter(new Locator.FilterOptions()
.setHas(page.GetByRole(AriaRole.HEADING,
new Page.GetByRoleOptions().setName("Product 2"))))
new Page.GetByRoleOptions().setName("Product 2")))))
.hasCount(1);
```
@ -1033,7 +1033,7 @@ assertThat(page
.filter(new Locator.FilterOptions()
.setHas(page.GetByRole(AriaRole.LIST)
.GetByRole(AriaRole.HEADING,
new Page.GetByRoleOptions().setName("Product 2"))))
new Page.GetByRoleOptions().setName("Product 2")))))
.hasCount(1);
```
@ -1079,7 +1079,7 @@ await expect(page
```java
assertThat(page
.getByRole(AriaRole.LISTITEM)
.filter(new Locator.FilterOptions().setHasNot(page.getByText("Product 2")))
.filter(new Locator.FilterOptions().setHasNot(page.getByText("Product 2"))))
.hasCount(1);
```
@ -1356,7 +1356,7 @@ expect(page.get_by_role("listitem")).to_have_count(3)
```
```java
assertThat(page.getByRole(AriaRole.LISTITEM).hasCount(3);
assertThat(page.getByRole(AriaRole.LISTITEM)).hasCount(3);
```
```csharp

View file

@ -195,15 +195,15 @@ await Expect(page.GetByTextAsync("Loquat", new () { Exact = true })).ToBeVisible
page.route("*/**/api/v1/fruits", route -> {
Response response = route.fetch();
byte[] json = response.body();
parsed = new Gson().fromJson(json, JsonObject.class)
JsonObject parsed = new Gson().fromJson(new String(json), JsonObject.class);
parsed.add(new JsonObject().add("name", "Loquat").add("id", 100));
// Fulfill using the original response, while patching the response body
// with the given JSON object.
route.fulfill(new Route.FulfillOptions().setResponse(response).setBody(json.toString()));
route.fulfill(new Route.FulfillOptions().setResponse(response).setBody(parsed.toString()));
});
// Go to the page
page.goto("https://demo.playwright.dev/api-mocking");
page.navigate("https://demo.playwright.dev/api-mocking");
// Assert that the Loquat fruit is visible
assertThat(page.getByText("Loquat", new Page.GetByTextOptions().setExact(true))).isVisible();
@ -294,7 +294,7 @@ page.routeFromHAR(Path.of("./hars/fruit.har"), new RouteFromHAROptions()
);
// Go to the page
page.goto("https://demo.playwright.dev/api-mocking");
page.navigate("https://demo.playwright.dev/api-mocking");
// Assert that the fruit is visible
assertThat(page.getByText("Strawberry")).isVisible();
@ -392,10 +392,11 @@ page.routeFromHAR(Path.of("./hars/fruit.har"), new RouteFromHAROptions()
);
// Go to the page
page.goto("https://demo.playwright.dev/api-mocking");
page.navigate("https://demo.playwright.dev/api-mocking");
// Assert that the Playwright fruit is visible
assertThat(page.getByText("Playwright", new Page.GetByTextOptions().setExact(true))).isVisible();
assertThat(page.getByText("Playwright", new Page.GetByTextOptions()
.setExact(true))).isVisible();
```
In the trace of our test we can see that the route was fulfilled from the HAR file and the API was not called.
![trace showing the HAR file being used](https://github.com/microsoft/playwright/assets/13063165/1bd7ab66-ea4f-43c2-a4e5-ca17d4837ff1)

View file

@ -146,8 +146,8 @@ const browser = await chromium.launch({
```java
Browser browser = chromium.launch(new BrowserType.LaunchOptions()
.setProxy(new Proxy("http://myproxy.com:3128")
.setUsername('usr')
.setPassword('pwd')));
.setUsername("usr")
.setPassword("pwd")));
```
```python async
@ -627,7 +627,7 @@ page.route("**/title.html", route -> {
String body = response.text();
body = body.replace("<title>", "<title>My prefix:");
Map<String, String> headers = response.headers();
headers.put("content-type": "text/html");
headers.put("content-type", "text/html");
route.fulfill(new Route.FulfillOptions()
// Pass all fields from the response.
.setResponse(response)

View file

@ -289,7 +289,7 @@ Page objects can then be used inside a test.
```java
import models.SearchPage;
import com.microsoft.playwright.*;
...
// ...
// In the test
Page page = browser.newPage();

View file

@ -378,7 +378,7 @@ New method [`method: Page.addLocatorHandler`] registers a callback that will be
// Setup the handler.
page.addLocatorHandler(
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Hej! You are in control of your cookies.")),
() - > {
() -> {
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Accept all")).click();
});
// Write the test as usual.
@ -1187,14 +1187,12 @@ Playwright for Java 1.18 introduces [Web-First Assertions](./test-assertions).
Consider the following example:
```java
...
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
public class TestExample {
...
@Test
void statusBecomesSubmitted() {
...
// ...
page.locator("#submit-button").click();
assertThat(page.locator(".status")).hasText("Submitted");
}
@ -1471,19 +1469,19 @@ button.click("button >> visible=true");
Traces are recorded using the new [`property: BrowserContext.tracing`] API:
```java
Browser browser = chromium.launch();
Browser browser = playwright.chromium().launch();
BrowserContext context = browser.newContext();
// Start tracing before creating / navigating a page.
context.tracing.start(new Tracing.StartOptions()
context.tracing().start(new Tracing.StartOptions()
.setScreenshots(true)
.setSnapshots(true);
.setSnapshots(true));
Page page = context.newPage();
page.goto("https://playwright.dev");
page.navigate("https://playwright.dev");
// Stop tracing and export it into a zip archive.
context.tracing.stop(new Tracing.StopOptions()
context.tracing().stop(new Tracing.StopOptions()
.setPath(Paths.get("trace.zip")));
```

View file

@ -21,7 +21,7 @@ page.screenshot(path="screenshot.png")
```java
page.screenshot(new Page.ScreenshotOptions()
.setPath(Paths.get("screenshot.png")))
.setPath(Paths.get("screenshot.png")));
```
```csharp

View file

@ -202,7 +202,7 @@ You can use a Gradle build configuration script, written in Groovy or Kotlin.
}>
<TabItem value="gradle">
```java
```groovy
plugins {
application
id 'java'
@ -234,7 +234,7 @@ test {
</TabItem>
<TabItem value="gradle-kotlin">
```java
```groovy
plugins {
application
id("java")

View file

@ -209,6 +209,16 @@ class CSharpLintingService extends LintingService {
}
}
class JavaLintingService extends LintingService {
supports(codeLang) {
return codeLang === 'java';
}
async lint(snippets) {
return await this.spawnAsync('java', ['-jar', path.join(__dirname, 'java', 'target', 'java-syntax-checker-1.0-SNAPSHOT.jar')], snippets, path.join(__dirname, 'java'))
}
}
class LintingServiceFactory {
constructor() {
/** @type {LintingService[]} */
@ -219,6 +229,7 @@ class LintingServiceFactory {
this.services.push(
new PythonLintingService(),
new CSharpLintingService(),
new JavaLintingService(),
);
}
this._metrics = {};

View file

@ -0,0 +1,2 @@
target/
dependency-reduced-pom.xml

View file

@ -0,0 +1,53 @@
<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>
<groupId>com.example</groupId>
<artifactId>java-syntax-checker</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.26.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>JavaSyntaxChecker</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,110 @@
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.github.javaparser.JavaParser;
import com.github.javaparser.Problem;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class JavaSyntaxChecker {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Error: Please provide the path to the JSON file");
return;
}
String codeSnippetsPath = args[args.length - 1];
List<CodeSnippet> codeSnippets = readCodeSnippets(codeSnippetsPath);
if (codeSnippets == null) {
System.out.println("Error: codeSnippets is null");
return;
}
List<Map<String, Object>> output = new ArrayList<>();
ParserConfiguration config = new ParserConfiguration();
config.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_17);
for (CodeSnippet codeSnippet : codeSnippets) {
String cleanedCode = cleanSnippet(codeSnippet.code);
ParseResult<CompilationUnit> parseResult = new JavaParser(config).parse(cleanedCode);
List<Problem> syntaxErrors = parseResult.getProblems();
if (!syntaxErrors.isEmpty()) {
output.add(Map.of(
"status", "error",
"error", String.join("\n", syntaxErrors.stream()
.map(Problem::getMessage)
.collect(Collectors.toList()))
));
} else {
output.add(Map.of("status", "ok"));
}
}
System.out.println(new Gson().toJson(output));
}
private static String removeImports(String code) {
// Remove import statements
return Pattern.compile("^import.*;$", Pattern.MULTILINE)
.matcher(code)
.replaceAll("");
}
private static String cleanSnippet(String code) {
// if it contains "public class" then it's a full class, return immediately
if (code.contains("public class")) {
return code;
}
code = removeImports(code);
String wrappedCode = """
import com.microsoft.playwright.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.*;
public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch();
BrowserContext context = browser.newContext();
Page page = context.newPage();
%s
}
}
}
""".formatted(code);
return wrappedCode;
}
private static List<CodeSnippet> readCodeSnippets(String filePath) {
try (FileReader reader = new FileReader(filePath)) {
Type listType = new TypeToken<ArrayList<CodeSnippet>>(){}.getType();
return new Gson().fromJson(reader, listType);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
class CodeSnippet {
String filePath;
String codeLang;
String code;
public CodeSnippet(String filePath, String codeLang, String code) {
this.filePath = filePath;
this.codeLang = codeLang;
this.code = code;
}
}