diff --git a/.github/workflows/semantic-pr-footer.yml b/.github/workflows/semantic-pr-footer.yml
index d5e35af..da35cee 100644
--- a/.github/workflows/semantic-pr-footer.yml
+++ b/.github/workflows/semantic-pr-footer.yml
@@ -10,7 +10,10 @@ on:
jobs:
semantic-pr-footer:
+ if: ${{ github.event.pull_request.body != '' }}
runs-on: ubuntu-latest
timeout-minutes: 1
+ permissions:
+ pull-requests: read
steps:
- uses: dequelabs/axe-api-team-public/.github/actions/semantic-pr-footer-v1@main
diff --git a/java/playwright/basic/pom.xml b/java/playwright/basic/pom.xml
new file mode 100644
index 0000000..aa20a80
--- /dev/null
+++ b/java/playwright/basic/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+ com.deque.watcher_examples.playwright
+ basic
+ 1.0-SNAPSHOT
+
+
+ 17
+ 17
+ UTF-8
+ false
+
+
+
+
+ com.microsoft.playwright
+ playwright
+ 1.49.0
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.10.2
+ test
+
+
+ com.deque.axe_core
+ watcher
+ 4.4.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 3.1.0
+
+
+ install-playwright-browsers
+ process-test-classes
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/playwright/basic/src/main/java/com/deque/watcher_examples/playwright/Basic.java b/java/playwright/basic/src/main/java/com/deque/watcher_examples/playwright/Basic.java
new file mode 100644
index 0000000..104a811
--- /dev/null
+++ b/java/playwright/basic/src/main/java/com/deque/watcher_examples/playwright/Basic.java
@@ -0,0 +1,7 @@
+package com.deque.watcher_examples.playwright;
+
+public class Basic {
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+}
diff --git a/java/playwright/basic/src/test/java/com/deque/watcher_examples/playwright/BasicTest.java b/java/playwright/basic/src/test/java/com/deque/watcher_examples/playwright/BasicTest.java
new file mode 100644
index 0000000..4e93b64
--- /dev/null
+++ b/java/playwright/basic/src/test/java/com/deque/watcher_examples/playwright/BasicTest.java
@@ -0,0 +1,82 @@
+package com.deque.watcher_examples.playwright;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import com.deque.axe_core.commons.AxeWatcherOptions;
+import com.deque.axe_core.playwright.AxeWatcherPage;
+import com.deque.axe_core.playwright.AxeWatcherPlaywright;
+import com.microsoft.playwright.BrowserContext;
+import com.microsoft.playwright.BrowserType;
+import com.microsoft.playwright.ElementHandle;
+import com.microsoft.playwright.Playwright;
+
+
+@DisplayName("My Login Application")
+class BasicTest {
+
+ String apiKey = "test-api-key";
+ String projectId = "test-project-id";
+ String serverUrl = "https://axe.deque.com";
+
+ Playwright playwright;
+ BrowserContext browserContext;
+ AxeWatcherPage page;
+
+ @BeforeEach
+ void setUp() {
+ AxeWatcherPlaywright axeWatcher =
+ new AxeWatcherPlaywright(
+ new AxeWatcherOptions().setApiKey(apiKey).setProjectId(projectId).setServerUrl(serverUrl))
+ .enableDebugLogger();
+
+ BrowserType.LaunchPersistentContextOptions launchOptions =
+ axeWatcher.configure(
+ new BrowserType.LaunchPersistentContextOptions()
+ .setHeadless(true)
+ .setChannel("chromium")
+ .setArgs(List.of("--no-sandbox", "--disable-dev-shm-usage")));
+
+ playwright = Playwright.create();
+ // An empty user-data dir lets Playwright create a fresh temporary profile.
+ browserContext = playwright.chromium().launchPersistentContext(Paths.get(""), launchOptions);
+ page = axeWatcher.wrapPage(browserContext.newPage());
+ }
+
+ @AfterEach
+ void tearDown() {
+ page.axeWatcher().flush();
+ browserContext.close();
+ playwright.close();
+ }
+
+ @Nested
+ @DisplayName("Login")
+ class LoginTests {
+ @Nested
+ @DisplayName("with valid credentials")
+ class ShouldLoginTests {
+ @Test
+ @DisplayName("should login")
+ void shouldLoginTest() {
+ page.navigate("https://the-internet.herokuapp.com/login");
+
+ page.locator("#username").fill("tomsmith");
+ page.locator("#password").fill("SuperSecretPassword!");
+
+ page.locator("button[type='submit']").click();
+
+ ElementHandle element = page.waitForSelector("#flash");
+ assertNotNull(element);
+ }
+ }
+ }
+}
diff --git a/java/playwright/manual-mode/pom.xml b/java/playwright/manual-mode/pom.xml
new file mode 100644
index 0000000..f388792
--- /dev/null
+++ b/java/playwright/manual-mode/pom.xml
@@ -0,0 +1,80 @@
+
+
+ 4.0.0
+
+ com.deque.watcher_examples.playwright
+ manual-mode
+ 1.0-SNAPSHOT
+
+
+ 17
+ 17
+ UTF-8
+ false
+
+
+
+
+
+ com.microsoft.playwright
+ playwright
+ 1.49.0
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.10.2
+ test
+
+
+ com.deque.axe_core
+ watcher
+ 4.4.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 3.1.0
+
+
+ install-playwright-browsers
+ process-test-classes
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/playwright/manual-mode/src/main/java/com/deque/watcher_examples/playwright/ManualMode.java b/java/playwright/manual-mode/src/main/java/com/deque/watcher_examples/playwright/ManualMode.java
new file mode 100644
index 0000000..fd0d604
--- /dev/null
+++ b/java/playwright/manual-mode/src/main/java/com/deque/watcher_examples/playwright/ManualMode.java
@@ -0,0 +1,7 @@
+package com.deque.watcher_examples.playwright;
+
+public class ManualMode {
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+}
diff --git a/java/playwright/manual-mode/src/test/java/com/deque/watcher_examples/playwright/ManualModeTest.java b/java/playwright/manual-mode/src/test/java/com/deque/watcher_examples/playwright/ManualModeTest.java
new file mode 100644
index 0000000..fa425cb
--- /dev/null
+++ b/java/playwright/manual-mode/src/test/java/com/deque/watcher_examples/playwright/ManualModeTest.java
@@ -0,0 +1,112 @@
+package com.deque.watcher_examples.playwright;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import com.deque.axe_core.commons.AxeWatcherOptions;
+import com.deque.axe_core.playwright.AxeWatcherPage;
+import com.deque.axe_core.playwright.AxeWatcherPlaywright;
+import com.microsoft.playwright.BrowserContext;
+import com.microsoft.playwright.BrowserType;
+import com.microsoft.playwright.ElementHandle;
+import com.microsoft.playwright.Playwright;
+
+
+@DisplayName("My Login Application")
+class ManualModeTest {
+
+ String apiKey = "test-api-key";
+ String projectId = "test-project-id";
+ String serverUrl = "https://axe.deque.com";
+
+ Playwright playwright;
+ BrowserContext browserContext;
+ AxeWatcherPage page;
+
+ @BeforeEach
+ void setUp() {
+ AxeWatcherPlaywright axeWatcher =
+ new AxeWatcherPlaywright(
+ new AxeWatcherOptions()
+ .setApiKey(apiKey)
+ .setProjectId(projectId)
+ .setServerUrl(serverUrl)
+ // Disable automatic analysis.
+ .setAutoAnalyze(false))
+ .enableDebugLogger();
+
+ BrowserType.LaunchPersistentContextOptions launchOptions =
+ axeWatcher.configure(
+ new BrowserType.LaunchPersistentContextOptions()
+ .setHeadless(true)
+ .setChannel("chromium")
+ .setArgs(List.of("--no-sandbox", "--disable-dev-shm-usage")));
+
+ playwright = Playwright.create();
+ browserContext = playwright.chromium().launchPersistentContext(Paths.get(""), launchOptions);
+ page = axeWatcher.wrapPage(browserContext.newPage());
+ }
+
+ @AfterEach
+ void tearDown() {
+ // Flush axe-watcher results after each test.
+ page.axeWatcher().flush();
+ browserContext.close();
+ playwright.close();
+ }
+
+ @Nested
+ @DisplayName("Login")
+ class LoginTests {
+ @Nested
+ @DisplayName("with valid credentials")
+ class ShouldLoginTests {
+ @Test
+ @DisplayName("should login")
+ void shouldLoginTest() {
+ /*
+ Let's calculate the number of page states.
+ Auto-analyze is false, so it will not analyze automatically.
+
+ We navigate to the page,
+ then manually analyze it. (+1)
+ We fill out the form,
+ then turn on auto-analysis.
+ We click the button,
+ causing an auto-analysis (+1),
+ then assure the element appears.
+ We turn off auto-analysis,
+ then analyze manually (+1).
+
+ So, we expect the total number of page states to be 3.
+ */
+ page.navigate("https://the-internet.herokuapp.com/login");
+ // Analyze after navigating to the page.
+ page.axeWatcher().analyze();
+
+ page.locator("#username").fill("tomsmith");
+ page.locator("#password").fill("SuperSecretPassword!");
+ // Start automatic axe analysis.
+ page.axeWatcher().start();
+
+ page.locator("button[type='submit']").click();
+
+ ElementHandle element = page.waitForSelector("#flash");
+ assertNotNull(element);
+
+ // Stop automatic axe analysis.
+ page.axeWatcher().stop();
+ // Analyze after logging in.
+ page.axeWatcher().analyze();
+ }
+ }
+ }
+}
diff --git a/java/playwright/multi-page/pom.xml b/java/playwright/multi-page/pom.xml
new file mode 100644
index 0000000..a7a2ee0
--- /dev/null
+++ b/java/playwright/multi-page/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+ com.deque.watcher_examples.playwright
+ multi-page
+ 1.0-SNAPSHOT
+
+
+ 17
+ 17
+ UTF-8
+ false
+
+
+
+
+ com.microsoft.playwright
+ playwright
+ 1.49.0
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.10.2
+ test
+
+
+ com.deque.axe_core
+ watcher
+ 4.4.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 3.1.0
+
+
+ install-playwright-browsers
+ process-test-classes
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/playwright/multi-page/src/main/java/com/deque/watcher_examples/playwright/MultiPage.java b/java/playwright/multi-page/src/main/java/com/deque/watcher_examples/playwright/MultiPage.java
new file mode 100644
index 0000000..e0b28fe
--- /dev/null
+++ b/java/playwright/multi-page/src/main/java/com/deque/watcher_examples/playwright/MultiPage.java
@@ -0,0 +1,7 @@
+package com.deque.watcher_examples.playwright;
+
+public class MultiPage {
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+}
diff --git a/java/playwright/multi-page/src/test/java/com/deque/watcher_examples/playwright/MultiPageTest.java b/java/playwright/multi-page/src/test/java/com/deque/watcher_examples/playwright/MultiPageTest.java
new file mode 100644
index 0000000..9a14e97
--- /dev/null
+++ b/java/playwright/multi-page/src/test/java/com/deque/watcher_examples/playwright/MultiPageTest.java
@@ -0,0 +1,157 @@
+package com.deque.watcher_examples.playwright;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import com.deque.axe_core.commons.AxeWatcherOptions;
+import com.deque.axe_core.playwright.AxeWatcherPage;
+import com.deque.axe_core.playwright.AxeWatcherPlaywright;
+import com.microsoft.playwright.BrowserContext;
+import com.microsoft.playwright.BrowserType;
+import com.microsoft.playwright.ElementHandle;
+import com.microsoft.playwright.Playwright;
+
+
+@DisplayName("Multipage Test")
+class MultiPageTest {
+
+ static Playwright playwright;
+ static BrowserContext browserContext;
+ static AxeWatcherPage page;
+
+ @BeforeAll
+ static void setup() {
+ String apiKey = "test-api-key";
+ String projectId = "test-project-id";
+ String serverUrl = "https://axe.deque.com";
+
+ AxeWatcherPlaywright axeWatcher =
+ new AxeWatcherPlaywright(
+ new AxeWatcherOptions()
+ .setApiKey(apiKey)
+ .setProjectId(projectId)
+ .setServerUrl(serverUrl));
+
+ BrowserType.LaunchPersistentContextOptions launchOptions =
+ axeWatcher.configure(
+ new BrowserType.LaunchPersistentContextOptions()
+ .setHeadless(true)
+ .setChannel("chromium")
+ .setArgs(List.of("--no-sandbox", "--disable-dev-shm-usage")));
+
+ playwright = Playwright.create();
+ browserContext = playwright.chromium().launchPersistentContext(Paths.get(""), launchOptions);
+ page = axeWatcher.wrapPage(browserContext.newPage());
+ }
+
+ @AfterAll
+ static void teardown() {
+ browserContext.close();
+ playwright.close();
+ }
+
+ @AfterEach
+ void tearDown() {
+ // Flush axe-watcher results after each test.
+ page.axeWatcher().flush();
+ }
+
+ @Nested
+ @DisplayName("Homepage")
+ class HomepageTests {
+ @BeforeEach
+ void visit() {
+ page.navigate("https://the-internet.herokuapp.com");
+ }
+
+ @Test
+ @DisplayName("should contain a list of links")
+ void shouldContainAListOfLinksTest() {
+ assertTrue(page.locator("ul li a").count() >= 20);
+ }
+
+ @Test
+ @DisplayName("should contain a link to the login page")
+ void shouldContainALinkToTheLoginPageTest() {
+ ElementHandle loginLink = page.querySelector("ul li a[href='/login']");
+ assertNotNull(loginLink);
+ }
+ }
+
+ @Nested
+ @DisplayName("Login page")
+ class LoginPageTests {
+
+ @BeforeEach
+ void visit() {
+ page.navigate("https://the-internet.herokuapp.com/login");
+ }
+
+ @Test
+ @DisplayName("should contain a username input")
+ void shouldContainAUsernameInputTest() {
+ ElementHandle usernameInput = page.querySelector("#username");
+ assertNotNull(usernameInput);
+ }
+
+ @Test
+ @DisplayName("should contain a password input")
+ void shouldContainAPasswordInputTest() {
+ ElementHandle passwordInput = page.querySelector("#password");
+ assertNotNull(passwordInput);
+ }
+
+ @Test
+ @DisplayName("should contain a submit button")
+ void shouldContainASubmitButton() {
+ ElementHandle submitButton = page.querySelector("button[type='submit']");
+ assertNotNull(submitButton);
+ }
+
+ @Test
+ @DisplayName("entering credentials and submitting the form should login")
+ void shouldLoginTest() {
+ page.locator("#username").fill("tomsmith");
+ page.locator("#password").fill("SuperSecretPassword!");
+
+ page.locator("button[type='submit']").click();
+
+ ElementHandle element = page.waitForSelector("#flash");
+ assertNotNull(element);
+ }
+ }
+
+ @Nested
+ @DisplayName("Forgot password page")
+ class MultiPageForgotPasswordTest {
+
+ @BeforeEach
+ void visit() {
+ page.navigate("https://the-internet.herokuapp.com/forgot_password");
+ }
+
+ @Test
+ @DisplayName("should contain an email input")
+ void shouldContainAnEmailInputTest() {
+ ElementHandle input = page.querySelector("#email");
+ assertNotNull(input);
+ }
+
+ @Test
+ @DisplayName("should contain a submit button")
+ void shouldContainASubmitButtonTest() {
+ ElementHandle button = page.querySelector("button[type='submit']");
+ assertNotNull(button);
+ }
+ }
+}