chore: lint java docs snippets (#32945)
This commit is contained in:
parent
0a45549533
commit
895be9f8de
8
.github/workflows/infra.yml
vendored
8
.github/workflows/infra.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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") });
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||

|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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")));
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
|
|
|
|||
2
utils/doclint/linting-code-snippets/java/.gitignore
vendored
Normal file
2
utils/doclint/linting-code-snippets/java/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
target/
|
||||
dependency-reduced-pom.xml
|
||||
53
utils/doclint/linting-code-snippets/java/pom.xml
Normal file
53
utils/doclint/linting-code-snippets/java/pom.xml
Normal 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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue