This is an automated email from the ASF dual-hosted git repository.

lprimak pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/shiro.git


The following commit(s) were added to refs/heads/main by this push:
     new a2f7ba29f Refactor Jakarta EE integration tests with Graphene page 
objects (#2944)
a2f7ba29f is described below

commit a2f7ba29f4f0e2bcc34549043126c531441eacc8
Author: Lenny Primak <[email protected]>
AuthorDate: Sat Nov 7 14:20:13 2026 -0600

    Refactor Jakarta EE integration tests with Graphene page objects (#2944)
---
 integration-tests/jakarta-ee/pom.xml               |   2 +-
 .../shiro/testing/cdi/ComponentInjectionIT.java    |   5 +-
 .../shiro/testing/jakarta/ee/Deployments.java      |   4 +-
 .../shiro/testing/jakarta/ee/FacesTagsIT.java      | 147 +++-------
 .../shiro/testing/jakarta/ee/ShiroAuthFormsIT.java | 322 +++++++--------------
 .../shiro/testing/jakarta/ee/ShiroBeansIT.java     | 164 ++++-------
 .../shiro/testing/jakarta/ee/ShiroSSLFilterIT.java |   2 +-
 .../shiro/testing/jakarta/ee/pages/FormPage.java   | 116 ++++++++
 .../shiro/testing/jakarta/ee/pages/LoginPage.java  | 115 ++++++++
 .../testing/jakarta/ee/pages/ManyBeansPage.java    | 108 +++++++
 .../testing/jakarta/ee/pages/SessionControls.java  |  51 ++++
 .../shiro/testing/jakarta/ee/pages/TagsPage.java   | 134 +++++++++
 .../apache/shiro/testing/jaxrs/NoIniJaxRsIT.java   |   2 +-
 13 files changed, 743 insertions(+), 429 deletions(-)

diff --git a/integration-tests/jakarta-ee/pom.xml 
b/integration-tests/jakarta-ee/pom.xml
index c40138d8b..729970bf3 100644
--- a/integration-tests/jakarta-ee/pom.xml
+++ b/integration-tests/jakarta-ee/pom.xml
@@ -106,7 +106,7 @@
         <dependency>
             <groupId>com.flowlogix</groupId>
             <artifactId>flowlogix-jee</artifactId>
-            <version>11.7.3</version>
+            <version>11.7.6</version>
         </dependency>
 
         <dependency>
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java
index ed0a40981..9e0d29113 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java
@@ -39,6 +39,7 @@ import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
 
 import java.util.Optional;
+import java.util.UUID;
 
 /**
  * Tests @Injecting Subject, Session, Principal and SecurityManager with CDI
@@ -111,11 +112,11 @@ public class ComponentInjectionIT {
 
     @Deployment(name = TESTABLE_MODE)
     public static WebArchive createDeployment() {
-        return createDeployment("security-manager-injection.war");
+        return createDeployment("security-manager-injection");
     }
 
     public static WebArchive createDeployment(String archive) {
-        var webArchive = ShrinkWrap.create(WebArchive.class, archive)
+        var webArchive = ShrinkWrap.create(WebArchive.class, 
"s%s-%s.war".formatted(UUID.randomUUID(), archive))
                 .addAsResource("META-INF/beans.xml")
                 .addAsResource(new 
StringAsset("org.apache.shiro.cdi.ShiroSecurityExtension"),
                         
"META-INF/services/jakarta.enterprise.inject.spi.Extension")
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java
index ddb69fb2d..c62300580 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java
@@ -51,7 +51,7 @@ public class Deployments {
 
     @Deployment(testable = false, name = DEPLOYMENT_DEV_MODE)
     public static WebArchive createDeployment() {
-        return ShiroAuthFormsIT.createDeploymentDev("ShiroSuiteTest-ui.war");
+        return ShiroAuthFormsIT.createDeploymentDev("ShiroSuiteTest-ui");
     }
 
     @Deployment(testable = false, name = DEPLOYMENT_PROD_MODE)
@@ -61,7 +61,7 @@ public class Deployments {
 
     @Deployment(name = TESTABLE_MODE)
     public static WebArchive createNonUIDeployment() {
-        return ComponentInjectionIT.createDeployment("ShiroSuiteTest.war");
+        return ComponentInjectionIT.createDeployment("ShiroSuiteTest");
     }
 
     private static List<Action> initializeStandardActions() {
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java
index c4aa72708..2b4b30d47 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java
@@ -13,20 +13,18 @@
  */
 package org.apache.shiro.testing.jakarta.ee;
 
-import java.net.URL;
-
 import static 
org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_DEV_MODE;
 import static 
org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.createDeploymentDev;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.shiro.testing.jakarta.ee.pages.LoginPage;
+import org.apache.shiro.testing.jakarta.ee.pages.TagsPage;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.container.test.api.OperateOnDeployment;
 import org.jboss.arquillian.drone.api.annotation.Drone;
 
-import static org.jboss.arquillian.graphene.Graphene.guardHttp;
-
+import org.jboss.arquillian.graphene.page.Page;
 import org.jboss.arquillian.junit5.ArquillianExtension;
-import org.jboss.arquillian.test.api.ArquillianResource;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
 
 import org.junit.jupiter.api.BeforeEach;
@@ -34,8 +32,6 @@ import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.FindBy;
 
 @ExtendWith(ArquillianExtension.class)
 @Tag("UserInterface")
@@ -43,60 +39,11 @@ public class FacesTagsIT {
     @Drone
     private WebDriver webDriver;
 
-    @SuppressWarnings("DeclarationOrder")
-    @ArquillianResource
-    protected URL baseURL;
-
-    @FindBy(id = "username")
-    private WebElement username;
-
-    @FindBy(id = "password")
-    private WebElement password;
-
-    @FindBy(id = "login")
-    private WebElement login;
-
-    @FindBy(id = "guestTag")
-    private WebElement guest;
-
-    @FindBy(id = "userTag")
-    private WebElement user;
-
-    @FindBy(id = "authenticatedTag")
-    private WebElement authenticated;
-
-    @FindBy(id = "notAuthenticatedTag")
-    private WebElement notAuthenticated;
-
-    @FindBy(id = "principalTag")
-    private WebElement principal;
-
-    @FindBy(id = "principalTagByType")
-    private WebElement principalByType;
-
-    @FindBy(id = "principalTagByProperty")
-    private WebElement principalByProperty;
-
-    @FindBy(id = "hasRegularRoleTag")
-    private WebElement regularRole;
-
-    @FindBy(id = "lacksAdminRoleTag")
-    private WebElement lacksAdminRole;
-
-    @FindBy(id = "hasAnyRoleTag")
-    private WebElement hasAnyRole;
-
-    @FindBy(id = "hasPermissionTag")
-    private WebElement hasPermission;
-
-    @FindBy(id = "lacksPermissionTag")
-    private WebElement lacksPermission;
-
-    @FindBy(id = "hasAnyPermissionTag")
-    private WebElement hasAnyPermission;
+    @Page
+    private LoginPage loginPage;
 
-    @FindBy(id = "rememberedTag")
-    private WebElement remembered;
+    @Page
+    private TagsPage tagsPage;
 
     @BeforeEach
     void deleteAllCookies() {
@@ -106,49 +53,49 @@ public class FacesTagsIT {
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void guestTag() {
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(guest.getText()).isEqualTo("Guest Content");
+        tagsPage.goTo();
+        assertThat(tagsPage.guest()).isEqualTo("Guest Content");
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(guest.getText()).isEqualTo("");
+        tagsPage.goTo();
+        assertThat(tagsPage.guest()).isEqualTo("");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void userTag() {
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(user.getText()).isEqualTo("");
+        tagsPage.goTo();
+        assertThat(tagsPage.user()).isEqualTo("");
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(user.getText()).isEqualTo("User Content");
+        tagsPage.goTo();
+        assertThat(tagsPage.user()).isEqualTo("User Content");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void authenticated() {
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(authenticated.getText()).isEqualTo("");
+        tagsPage.goTo();
+        assertThat(tagsPage.authenticated()).isEqualTo("");
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(authenticated.getText()).isEqualTo("Authenticated Content");
+        tagsPage.goTo();
+        assertThat(tagsPage.authenticated()).isEqualTo("Authenticated 
Content");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void notAuthenticated() {
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(notAuthenticated.getText()).isEqualTo("Not Authenticated 
Content");
+        tagsPage.goTo();
+        assertThat(tagsPage.notAuthenticated()).isEqualTo("Not Authenticated 
Content");
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(notAuthenticated.getText()).isEqualTo("");
+        tagsPage.goTo();
+        assertThat(tagsPage.notAuthenticated()).isEqualTo("");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void principal() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(principal.getText()).isEqualTo("webuser");
+        tagsPage.goTo();
+        assertThat(tagsPage.principal()).isEqualTo("webuser");
     }
 
     @Test
@@ -156,83 +103,81 @@ public class FacesTagsIT {
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void principalByType() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(principalByType.getText()).isEqualTo("5");
+        tagsPage.goTo();
+        assertThat(tagsPage.principalByType()).isEqualTo("5");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void principalByProperty() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(principalByProperty.getText()).isEqualTo("webuser");
+        tagsPage.goTo();
+        assertThat(tagsPage.principalByProperty()).isEqualTo("webuser");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void hasRegularRole() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(regularRole.getText()).isEqualTo("Regular Role");
+        tagsPage.goTo();
+        assertThat(tagsPage.regularRole()).isEqualTo("Regular Role");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void lacksAdminRole() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(lacksAdminRole.getText()).isEqualTo("Lacks Admin Role");
+        tagsPage.goTo();
+        assertThat(tagsPage.lacksAdminRole()).isEqualTo("Lacks Admin Role");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void hasAnyRole() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(hasAnyRole.getText()).isEqualTo("Has Some Role");
+        tagsPage.goTo();
+        assertThat(tagsPage.hasAnyRole()).isEqualTo("Has Some Role");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void hasAnyPermission() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(hasAnyPermission.getText()).isEqualTo("Has Some 
Permission");
+        tagsPage.goTo();
+        assertThat(tagsPage.hasAnyPermission()).isEqualTo("Has Some 
Permission");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void hasPermission() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(hasPermission.getText()).isEqualTo("Has Permission");
+        tagsPage.goTo();
+        assertThat(tagsPage.hasPermission()).isEqualTo("Has Permission");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void lacksPermissio() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(lacksPermission.getText()).isEqualTo("Lacks Permission");
+        tagsPage.goTo();
+        assertThat(tagsPage.lacksPermission()).isEqualTo("Lacks Permission");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void remembered() {
         login();
-        webDriver.get(baseURL + "shiro/unprotected/tags");
-        assertThat(remembered.getText()).isEqualTo("");
+        tagsPage.goTo();
+        assertThat(tagsPage.remembered()).isEqualTo("");
     }
 
     private void login() {
-        webDriver.get(baseURL + "shiro/auth/loginform");
-        username.sendKeys("webuser");
-        password.sendKeys("webpwd");
-        guardHttp(login).click();
+        loginPage.goTo();
+        loginPage.login();
     }
 
     @Deployment(testable = false, name = DEPLOYMENT_DEV_MODE)
     public static WebArchive createDeployment() {
-        return createDeploymentDev("shiro-facelet-tags.war");
+        return createDeploymentDev("shiro-facelet-tags");
     }
 }
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java
index 096a0be84..5bf66aa33 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java
@@ -28,31 +28,25 @@ import java.util.stream.Stream;
 import static 
org.apache.shiro.web.servlet.ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.shiro.testing.jakarta.ee.pages.FormPage;
+import org.apache.shiro.testing.jakarta.ee.pages.LoginPage;
+import org.apache.shiro.testing.jakarta.ee.pages.SessionControls;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.container.test.api.OperateOnDeployment;
 import org.jboss.arquillian.drone.api.annotation.Drone;
 
-import static org.jboss.arquillian.graphene.Graphene.guardAjax;
-import static org.jboss.arquillian.graphene.Graphene.guardHttp;
-import static org.jboss.arquillian.graphene.Graphene.waitForHttp;
-import static org.jboss.arquillian.graphene.Graphene.waitGui;
-
+import org.jboss.arquillian.graphene.page.Page;
 import org.jboss.arquillian.junit5.ArquillianExtension;
 import org.jboss.arquillian.test.api.ArquillianResource;
-import org.jboss.shrinkwrap.api.ShrinkWrap;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.jboss.shrinkwrap.resolver.api.maven.archive.importer.MavenImporter;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
-import org.openqa.selenium.By;
 import org.openqa.selenium.Cookie;
 import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
-import org.openqa.selenium.support.ui.ExpectedConditions;
 
 /**
  * Form resubmit tests
@@ -71,68 +65,14 @@ public class ShiroAuthFormsIT {
     @ArquillianResource
     protected URL baseURL;
 
-    @FindBy(id = "username")
-    private WebElement username;
-
-    @FindBy(id = "password")
-    private WebElement password;
-
-    @FindBy(id = "login")
-    private WebElement login;
-
-    @FindBy(id = "login2")
-    private WebElement nonJSFLogin;
-
-    @FindBy(id = "rememberMe")
-    private WebElement rememberMe;
-
-    @FindBy(id = "form:logout")
-    private WebElement logout;
-
-    @FindBy(id = "logoutFiaFilter")
-    private WebElement logoutViaFilter;
-
-    @FindBy(id = "firstForm:firstName")
-    private WebElement firstName;
-
-    @FindBy(id = "firstForm:lastName")
-    private WebElement lastName;
-
-    @FindBy(id = "firstForm:submitFirst")
-    private WebElement submitFirst;
-
-    @FindBy(id = "secondForm:address")
-    private WebElement address;
+    @Page
+    private LoginPage loginPage;
 
-    @FindBy(id = "secondForm:city")
-    private WebElement city;
+    @Page
+    private FormPage formPage;
 
-    @FindBy(id = "secondForm:submitSecond")
-    private WebElement submitSecond;
-
-    @FindBy(id = "secondForm:messages")
-    private WebElement secondFormMessages;
-
-    @FindBy(id = "firstForm:messages")
-    private WebElement firstFormMessages;
-
-    @FindBy(id = "invalidate")
-    private WebElement invalidateSession;
-
-    @FindBy(id = "messages")
-    private WebElement messages;
-
-    @FindBy(id = "sessionExpiredMessage")
-    private WebElement sessionExpiredMessage;
-
-    @FindBy(id = "loginFailureMessage")
-    private WebElement loginFailureMessage;
-
-    @FindBy(className = "shiro-form-data-notice")
-    private WebElement formDataNotice;
-
-    @FindBy(name = "org.apache.shiro.form-data.discard")
-    private WebElement discardFormData;
+    @FindBy(tagName = "body")
+    private SessionControls session;
 
     @BeforeEach
     void deleteAllCookies() {
@@ -144,7 +84,7 @@ public class ShiroAuthFormsIT {
     void protectedPageWithLogin() {
         webDriver.get(baseURL + "shiro/protected");
         
assertThat(webDriver.getCurrentUrl().contains("shiro/auth")).as("redirect to 
login").isTrue();
-        login();
+        loginPage.login();
         assertThat(webDriver.getTitle()).isEqualTo("Protected Page");
     }
 
@@ -152,10 +92,10 @@ public class ShiroAuthFormsIT {
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void checkLogout() {
         webDriver.get(baseURL + "shiro/protected");
-        login();
-        guardHttp(logout).click();
+        loginPage.login();
+        session.logout();
         
assertThat(webDriver.getCurrentUrl().contains("shiro/auth")).as("redirect to 
login").isTrue();
-        login();
+        loginPage.login();
         assertThat(webDriver.getTitle()).isEqualTo("Protected Page");
     }
 
@@ -163,43 +103,33 @@ public class ShiroAuthFormsIT {
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void nonJSFLogin() {
         webDriver.get(baseURL + "shiro/protected");
-        username.sendKeys("webuser");
-        password.sendKeys("webpwd");
-        guardHttp(nonJSFLogin).click();
+        loginPage.loginNonJSF();
         assertThat(webDriver.getTitle()).isEqualTo("Protected Page");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void logoutViaFilterThenLoginAndForm() {
-        webDriver.get(baseURL + "shiro/form");
-        username.sendKeys("webuser");
-        password.sendKeys("webpwd");
-        guardHttp(nonJSFLogin).click();
-        guardHttp(logoutViaFilter).click();
+        formPage.goTo();
+        loginPage.loginNonJSF();
+        session.logoutViaFilter();
         
assertThat(webDriver.getCurrentUrl().contains("shiro/auth")).as("redirect to 
login").isTrue();
-        username.sendKeys("webuser");
-        password.sendKeys("webpwd");
-        guardHttp(nonJSFLogin).click();
-        firstName.sendKeys("Jack");
-        lastName.sendKeys("Frost");
-        guardHttp(submitFirst).click();
-        assertThat(messages.getText()).isEqualTo("Form Submitted - firstName: 
Jack, lastName: Frost");
+        loginPage.loginNonJSF();
+        formPage.submitFirstForm("Jack", "Frost");
+        assertThat(formPage.submissionMessage()).isEqualTo("Form Submitted - 
firstName: Jack, lastName: Frost");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void rememberMe() {
         webDriver.get(baseURL + "shiro/protected");
-        if (!rememberMe.isSelected()) {
-            rememberMe.click();
-        }
-        login();
+        loginPage.rememberMe();
+        loginPage.login();
         
webDriver.manage().deleteCookieNamed(isShiroNativeSessionsIntegrationTest()
                 ? NATIVE_SESSION_COOKIE_NAME : DEFAULT_SESSION_ID_NAME);
         webDriver.navigate().refresh();
         assertThat(webDriver.getTitle()).isEqualTo("Protected Page");
-        guardHttp(logout).click();
+        session.logout();
         
assertThat(webDriver.getCurrentUrl().contains("shiro/auth")).as("redirect to 
login").isTrue();
     }
 
@@ -207,14 +137,12 @@ public class ShiroAuthFormsIT {
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void unauthorized() {
         webDriver.get(baseURL + "shiro/adminpage");
-        login();
+        loginPage.login();
         assertThat(webDriver.getTitle()).isEqualTo("Unauthorized");
-        guardHttp(logout).click();
+        session.logout();
         assertThat(webDriver.getCurrentUrl()).isEqualTo(baseURL + "index");
         webDriver.get(baseURL + "shiro/adminpage");
-        username.sendKeys("admin");
-        password.sendKeys("adminpwd");
-        guardHttp(login).click();
+        loginPage.login("admin", "adminpwd");
         assertThat(webDriver.getTitle()).isEqualTo("Admin Page");
     }
 
@@ -222,11 +150,9 @@ public class ShiroAuthFormsIT {
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void incorrectLoginOnce() {
         webDriver.get(baseURL + "shiro/protected");
-        username.sendKeys("webuser");
-        password.sendKeys("wrongpwd");
-        guardHttp(login).click();
-        assertThat(loginFailureMessage.getText()).isEqualTo("Login Failed");
-        login();
+        loginPage.login("webuser", "wrongpwd");
+        assertThat(loginPage.loginFailureMessage()).isEqualTo("Login Failed");
+        loginPage.login();
         assertThat(webDriver.getTitle()).isEqualTo("Protected Page");
     }
 
@@ -237,187 +163,153 @@ public class ShiroAuthFormsIT {
     }
 
     private void nonAjaxSessionExpired(String first, String last) {
-        webDriver.get(baseURL + "shiro/form");
-        login();
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
-        firstName.sendKeys(first);
-        lastName.sendKeys(last);
-        guardHttp(submitFirst).click();
-        assertThat(sessionExpiredMessage.getText()).isEqualTo("Your Session 
Has Expired");
+        formPage.goTo();
+        loginPage.login();
+        session.invalidateSession();
+        formPage.submitFirstForm(first, last);
+        assertThat(loginPage.sessionExpiredMessage()).isEqualTo("Your Session 
Has Expired");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void nonAjaxResubmit() {
         nonAjaxSessionExpired();
-        login();
-        assertThat(messages.getText()).isEqualTo("Form Submitted - firstName: 
Jack, lastName: Frost");
+        loginPage.login();
+        assertThat(formPage.submissionMessage()).isEqualTo("Form Submitted - 
firstName: Jack, lastName: Frost");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void nonAjaxResubmitPreservesEscapedInput() {
         nonAjaxSessionExpired("Jörg & Sons + =", "Frost 雪");
-        login();
-        assertThat(messages.getText()).isEqualTo("Form Submitted - firstName: 
Jörg & Sons + =, lastName: Frost 雪");
+        loginPage.login();
+        assertThat(formPage.submissionMessage()).isEqualTo("Form Submitted - 
firstName: Jörg & Sons + =, lastName: Frost 雪");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void formDataNoticeOnlyWhenFormDataIsSaved() {
         webDriver.get(baseURL + "shiro/protected");
-        
assertThat(webDriver.findElements(By.className("shiro-form-data-notice"))).isEmpty();
+        assertThat(loginPage.hasFormDataNotice()).isFalse();
         nonAjaxSessionExpired();
-        assertThat(formDataNotice.getText()).startsWith("We saved the form 
data you entered");
-        assertThat(discardFormData.isSelected()).isFalse();
+        assertThat(loginPage.formDataNotice()).startsWith("We saved the form 
data you entered");
+        assertThat(loginPage.isDiscardFormDataSelected()).isFalse();
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void discardSavedFormData() {
         nonAjaxSessionExpired();
-        discardFormData.click();
-        login();
+        loginPage.discardSavedFormData();
+        loginPage.login();
         assertThat(webDriver.getTitle()).isEqualTo("Form Page");
-        assertThat(webDriver.findElements(By.id("messages"))).as("no form data 
submitted").isEmpty();
-        assertThat(firstName.getAttribute("value")).isEmpty();
-        webDriver.get(baseURL + "shiro/auth/loginform");
-        
assertThat(webDriver.findElements(By.className("shiro-form-data-notice"))).as("discarded").isEmpty();
+        assertThat(formPage.hasSubmissionMessage()).as("no form data 
submitted").isFalse();
+        assertThat(formPage.firstName()).isEmpty();
+        loginPage.goTo();
+        assertThat(loginPage.hasFormDataNotice()).as("discarded").isFalse();
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void nonAjaxResubmitAfterFailedLogin() {
         nonAjaxSessionExpired();
-        username.sendKeys("xxx");
-        password.sendKeys("yyy");
-        guardHttp(login).click();
-        login();
-        assertThat(messages.getText()).isEqualTo("Form Submitted - firstName: 
Jack, lastName: Frost");
+        loginPage.login("xxx", "yyy");
+        loginPage.login();
+        assertThat(formPage.submissionMessage()).isEqualTo("Form Submitted - 
firstName: Jack, lastName: Frost");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void nonAjaxRememberedResubmit() {
-        webDriver.get(baseURL + "shiro/form");
-        rememberMe.click();
-        login();
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
-        firstName.sendKeys("Jack");
-        lastName.sendKeys("Frost");
-        guardHttp(submitFirst).click();
-        assertThat(messages.getText()).isEqualTo("Form Submitted - firstName: 
Jack, lastName: Frost");
+        formPage.goTo();
+        loginPage.rememberMe();
+        loginPage.login();
+        session.invalidateSession();
+        formPage.submitFirstForm("Jack", "Frost");
+        assertThat(formPage.submissionMessage()).isEqualTo("Form Submitted - 
firstName: Jack, lastName: Frost");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void ajaxSessionExpired() {
-        webDriver.get(baseURL + "shiro/form");
-        login();
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
-        address.sendKeys("1 Houston Street");
-        city.sendKeys("New York");
-        waitForHttp(submitSecond).click();
-        assertThat(sessionExpiredMessage.getText()).isEqualTo("Your Session 
Has Expired");
+        formPage.goTo();
+        loginPage.login();
+        session.invalidateSession();
+        formPage.fillSecondForm("1 Houston Street", "New York");
+        formPage.submitSecondFormWithRedirect();
+        assertThat(loginPage.sessionExpiredMessage()).isEqualTo("Your Session 
Has Expired");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void ajaxResubmit() {
         ajaxSessionExpired();
-        login();
-        assertThat(secondFormMessages.getText()).isEqualTo("2nd Form Submitted 
- Address: 1 Houston Street, City: New York");
-        address.sendKeys("Workshop");
-        city.sendKeys("North Pole");
-        guardAjax(submitSecond).click();
-        assertThat(secondFormMessages.getText()).isEqualTo("2nd Form Submitted 
- Address: Workshop, City: North Pole");
+        loginPage.login();
+        assertThat(formPage.secondFormMessage()).isEqualTo("2nd Form Submitted 
- Address: 1 Houston Street, City: New York");
+        formPage.fillSecondForm("Workshop", "North Pole");
+        formPage.submitSecondForm();
+        assertThat(formPage.secondFormMessage()).isEqualTo("2nd Form Submitted 
- Address: Workshop, City: North Pole");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void ajaxRememberedResubmit() {
-        webDriver.get(baseURL + "shiro/form");
-        rememberMe.click();
-        login();
-        address.sendKeys("1 Houston Street");
-        city.sendKeys("New York");
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
-        guardAjax(submitSecond).click();
-        address.clear();
-        city.clear();
-        assertThat(secondFormMessages.getText()).isEqualTo("2nd Form Submitted 
- Address: 1 Houston Street, City: New York");
-        address.sendKeys("Workshop");
-        city.sendKeys("North Pole");
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
-        guardAjax(submitSecond).click();
-        address.clear();
-        city.clear();
-        assertThat(secondFormMessages.getText()).isEqualTo("2nd Form Submitted 
- Address: Workshop, City: North Pole");
-        address.sendKeys("LAX Airport");
-        city.sendKeys("Los Angeles");
-        guardAjax(submitSecond).click();
-        assertThat(secondFormMessages.getText()).isEqualTo("2nd Form Submitted 
- Address: LAX Airport, City: Los Angeles");
+        formPage.goTo();
+        loginPage.rememberMe();
+        loginPage.login();
+        formPage.fillSecondForm("1 Houston Street", "New York");
+        session.invalidateSession();
+        formPage.submitSecondForm();
+        formPage.clearSecondForm();
+        assertThat(formPage.secondFormMessage()).isEqualTo("2nd Form Submitted 
- Address: 1 Houston Street, City: New York");
+        formPage.fillSecondForm("Workshop", "North Pole");
+        session.invalidateSession();
+        formPage.submitSecondForm();
+        formPage.clearSecondForm();
+        assertThat(formPage.secondFormMessage()).isEqualTo("2nd Form Submitted 
- Address: Workshop, City: North Pole");
+        formPage.fillSecondForm("LAX Airport", "Los Angeles");
+        formPage.submitSecondForm();
+        assertThat(formPage.secondFormMessage()).isEqualTo("2nd Form Submitted 
- Address: LAX Airport, City: Los Angeles");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void nonAjaxAnonymousResubmit() {
-        webDriver.get(baseURL + "shiro/unprotected/form");
+        formPage.goToAnonymous();
         assertThat(webDriver.getTitle()).isEqualTo("Anonymous Form Page");
         expireAnonymousSession();
-        firstName.sendKeys("Jack");
-        lastName.sendKeys("Frost");
-        guardHttp(submitFirst).click();
+        formPage.submitFirstForm("Jack", "Frost");
         assertThat(webDriver.getTitle()).as("no login 
page").isEqualTo("Anonymous Form Page");
-        assertThat(firstFormMessages.getText()).isEqualTo("Anonymous Form 
Submitted - firstName: Jack, lastName: Frost");
+        assertThat(formPage.firstFormMessage()).isEqualTo("Anonymous Form 
Submitted - firstName: Jack, lastName: Frost");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void ajaxAnonymousResubmit() {
-        webDriver.get(baseURL + "shiro/unprotected/form");
-        address.sendKeys("1 Houston Street");
-        city.sendKeys("New York");
+        formPage.goToAnonymous();
+        formPage.fillSecondForm("1 Houston Street", "New York");
         expireAnonymousSession();
-        guardAjax(submitSecond).click();
+        formPage.submitSecondForm();
         assertThat(webDriver.getTitle()).as("no login 
page").isEqualTo("Anonymous Form Page");
-        assertThat(secondFormMessages.getText())
+        assertThat(formPage.secondFormMessage())
                 .isEqualTo("2nd Anonymous Form Submitted - Address: 1 Houston 
Street, City: New York");
-        address.clear();
-        city.clear();
-        address.sendKeys("Workshop");
-        city.sendKeys("North Pole");
-        guardAjax(submitSecond).click();
-        assertThat(secondFormMessages.getText())
+        formPage.clearSecondForm();
+        formPage.fillSecondForm("Workshop", "North Pole");
+        formPage.submitSecondForm();
+        assertThat(formPage.secondFormMessage())
                 .isEqualTo("2nd Anonymous Form Submitted - Address: Workshop, 
City: North Pole");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void alreadyLoggedIn() {
-        webDriver.get(baseURL + "shiro/form");
-        login();
-        webDriver.get(baseURL + "shiro/auth/loginform");
-        login();
+        formPage.goTo();
+        loginPage.login();
+        loginPage.goTo();
+        loginPage.login();
         assertThat(webDriver.getTitle()).isEqualTo("Index");
     }
 
-    private void login() {
-        username.sendKeys("webuser");
-        password.sendKeys("webpwd");
-        guardHttp(login).click();
-    }
-
     /**
      * Simulates a timed-out anonymous session. Explicit invalidation of a 
native session also removes
      * its cookie from the browser, unlike a timeout, after which the browser 
still sends the stale id,
@@ -425,9 +317,7 @@ public class ShiroAuthFormsIT {
      */
     private void expireAnonymousSession() {
         var sessionCookie = 
webDriver.manage().getCookieNamed(NATIVE_SESSION_COOKIE_NAME);
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
+        session.invalidateSession();
         if (isShiroNativeSessionsIntegrationTest() && sessionCookie != null) {
             // Firefox rejects re-adding the cookie with its original 
attributes (e.g. secure) over plain HTTP
             webDriver.manage().addCookie(new Cookie(sessionCookie.getName(), 
sessionCookie.getValue(),
@@ -437,13 +327,11 @@ public class ShiroAuthFormsIT {
 
     @Deployment(testable = false, name = DEPLOYMENT_DEV_MODE)
     public static WebArchive createDeployment() {
-        return createDeploymentDev("shiro-auth-forms.war");
+        return createDeploymentDev("shiro-auth-forms");
     }
 
     static WebArchive createDeploymentDev(String archiveName) {
-        WebArchive archive = ShrinkWrap.create(MavenImporter.class, 
archiveName)
-                .loadPomFromFile("pom.xml").importBuildOutput()
-                .as(WebArchive.class)
+        var archive = ShrinkWrapManipulator.<WebArchive>createDeployment(name 
-> "%s-%s".formatted(name, archiveName))
                 .deletePackage("org.apache.shiro.testing.jaxrs");
         new ShrinkWrapManipulator().webXmlXPath(archive, standardActions);
         return archive;
@@ -451,13 +339,11 @@ public class ShiroAuthFormsIT {
 
     @Deployment(testable = false, name = DEPLOYMENT_PROD_MODE)
     public static WebArchive createDeploymentProd() {
-        return createDeploymentProd("shiro-auth-forms-prod.war");
+        return createDeploymentProd("shiro-auth-forms-prod");
     }
 
     static WebArchive createDeploymentProd(String archiveName) {
-        WebArchive archive = ShrinkWrap.create(MavenImporter.class, 
archiveName)
-                .loadPomFromFile("pom.xml").importBuildOutput()
-                .as(WebArchive.class)
+        var archive = ShrinkWrapManipulator.<WebArchive>createDeployment(name 
-> "%s-%s".formatted(name, archiveName))
                 .deletePackage("org.apache.shiro.testing.jaxrs");
         var productionList = List.of(new Action(
                 getContextParamValue("jakarta.faces.PROJECT_STAGE"),
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java
index 4c1964bc7..0cef008bc 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java
@@ -18,14 +18,14 @@ import java.net.URL;
 import static 
org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_DEV_MODE;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.shiro.testing.jakarta.ee.pages.LoginPage;
+import org.apache.shiro.testing.jakarta.ee.pages.ManyBeansPage;
+import org.apache.shiro.testing.jakarta.ee.pages.SessionControls;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.container.test.api.OperateOnDeployment;
 import org.jboss.arquillian.drone.api.annotation.Drone;
 
-import static org.jboss.arquillian.graphene.Graphene.guardAjax;
-import static org.jboss.arquillian.graphene.Graphene.guardHttp;
-import static org.jboss.arquillian.graphene.Graphene.waitGui;
-
+import org.jboss.arquillian.graphene.page.Page;
 import org.jboss.arquillian.junit5.ArquillianExtension;
 import org.jboss.arquillian.test.api.ArquillianResource;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
@@ -36,9 +36,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
-import org.openqa.selenium.support.ui.ExpectedConditions;
 
 /**
  * Protected EJB/CDI beans tests
@@ -53,47 +51,14 @@ public class ShiroBeansIT {
     @ArquillianResource
     protected URL baseURL;
 
-    @FindBy(id = "form:facesViewScoped")
-    private WebElement facesViewScoped;
-
-    @FindBy(id = "form:omniViewScoped")
-    private WebElement omniViewScoped;
-
-    @FindBy(id = "form:sessionScoped")
-    private WebElement sessionScoped;
-
-    @FindBy(id = "form:stateless")
-    private WebElement stateless;
-
-    @FindBy(id = "form:unprotected")
-    private WebElement unprotectedMethod;
-
-    @FindBy(id = "form:protected")
-    private WebElement protectedMethod;
-
-    @FindBy(id = "form:viaInterface")
-    private WebElement viaInterface;
+    @Page
+    private LoginPage loginPage;
 
-    @FindBy(id = "form:viaInterfaceMethod")
-    private WebElement viaInterfaceMethod;
+    @Page
+    private ManyBeansPage manyBeansPage;
 
-    @FindBy(id = "form:viaSuperclass")
-    private WebElement viaSuperclass;
-
-    @FindBy(id = "invalidate")
-    private WebElement invalidateSession;
-
-    @FindBy(id = "form:messages")
-    private WebElement messages;
-
-    @FindBy(id = "username")
-    private WebElement username;
-
-    @FindBy(id = "password")
-    private WebElement password;
-
-    @FindBy(id = "login")
-    private WebElement login;
+    @FindBy(tagName = "body")
+    private SessionControls session;
 
     @BeforeEach
     void deleteAllCookies() {
@@ -104,25 +69,26 @@ public class ShiroBeansIT {
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void checkDontCallWhenNotAuth() {
-        webDriver.get(baseURL + "shiro/unprotected/manybeans");
-        guardAjax(facesViewScoped).click();
-        assertThat(messages.getText()).startsWith("view scope unauth: 
Attempting to perform a user-only operation");
-        guardAjax(omniViewScoped).click();
-        assertThat(messages.getText()).startsWith("omni view scope unauth: 
Attempting to perform a user-only operation");
-        guardAjax(sessionScoped).click();
-        assertThat(messages.getText()).startsWith("session scoped unauth: 
Attempting to perform a user-only operation");
-        guardAjax(stateless).click();
-        assertThat(messages.getText()).startsWith("stateless bean unauth: 
Attempting to perform a user-only operation");
-        guardAjax(unprotectedMethod).click();
-        assertThat(messages.getText()).isEqualTo("unprotected method: hello 
from unprotected");
-        guardAjax(protectedMethod).click();
-        assertThat(messages.getText()).startsWith("protected unauth: 
Attempting to perform a user-only operation");
-        guardAjax(viaInterface).click();
-        assertThat(messages.getText()).startsWith("via interface unauth: 
Attempting to perform a user-only operation");
-        guardAjax(viaInterfaceMethod).click();
-        assertThat(messages.getText()).startsWith("via interface method 
unauth: Attempting to perform a user-only operation");
-        guardAjax(viaSuperclass).click();
-        assertThat(messages.getText()).startsWith("via superclass unauth: 
Attempting to perform a user-only operation");
+        manyBeansPage.goTo();
+        manyBeansPage.callFacesViewScoped();
+        assertThat(manyBeansPage.message()).startsWith("view scope unauth: 
Attempting to perform a user-only operation");
+        manyBeansPage.callOmniViewScoped();
+        assertThat(manyBeansPage.message()).startsWith("omni view scope 
unauth: Attempting to perform a user-only operation");
+        manyBeansPage.callSessionScoped();
+        assertThat(manyBeansPage.message()).startsWith("session scoped unauth: 
Attempting to perform a user-only operation");
+        manyBeansPage.callStateless();
+        assertThat(manyBeansPage.message()).startsWith("stateless bean unauth: 
Attempting to perform a user-only operation");
+        manyBeansPage.callUnprotectedMethod();
+        assertThat(manyBeansPage.message()).isEqualTo("unprotected method: 
hello from unprotected");
+        manyBeansPage.callProtectedMethod();
+        assertThat(manyBeansPage.message()).startsWith("protected unauth: 
Attempting to perform a user-only operation");
+        manyBeansPage.callViaInterface();
+        assertThat(manyBeansPage.message()).startsWith("via interface unauth: 
Attempting to perform a user-only operation");
+        manyBeansPage.callViaInterfaceMethod();
+        assertThat(manyBeansPage.message())
+                .startsWith("via interface method unauth: Attempting to 
perform a user-only operation");
+        manyBeansPage.callViaSuperclass();
+        assertThat(manyBeansPage.message()).startsWith("via superclass unauth: 
Attempting to perform a user-only operation");
         webDriver.get(baseURL + "lastException");
         String exceptionText = 
webDriver.findElement(By.tagName("body")).getText();
         assertThat(exceptionText).startsWith(
@@ -132,50 +98,48 @@ public class ShiroBeansIT {
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void checkCallWhenAuth() {
-        webDriver.get(baseURL + "shiro/auth/loginform");
-        login();
-
-        webDriver.get(baseURL + "shiro/unprotected/manybeans");
-        guardAjax(facesViewScoped).click();
-        assertThat(messages.getText()).startsWith("Hello from 
FacesViewScoped");
-        guardAjax(omniViewScoped).click();
-        assertThat(messages.getText()).startsWith("Hello from OmniViewScoped");
-        guardAjax(sessionScoped).click();
-        assertThat(messages.getText()).startsWith("Hello from SessionScoped");
-        guardAjax(stateless).click();
-        assertThat(messages.getText()).startsWith("Hello from 
ProtectedStatelessBean");
-        guardAjax(protectedMethod).click();
-        assertThat(messages.getText()).isEqualTo("protected method: hello from 
protected");
-        guardAjax(viaInterface).click();
-        assertThat(messages.getText()).isEqualTo("Hello from 
ProtectedViaInterfaceBean");
-        guardAjax(viaInterfaceMethod).click();
-        assertThat(messages.getText()).isEqualTo("Unprotected hello from 
ProtectedViaInterfaceMethodBean"
+        loginPage.goTo();
+        loginPage.login();
+
+        manyBeansPage.goTo();
+        manyBeansPage.callFacesViewScoped();
+        assertThat(manyBeansPage.message()).startsWith("Hello from 
FacesViewScoped");
+        manyBeansPage.callOmniViewScoped();
+        assertThat(manyBeansPage.message()).startsWith("Hello from 
OmniViewScoped");
+        manyBeansPage.callSessionScoped();
+        assertThat(manyBeansPage.message()).startsWith("Hello from 
SessionScoped");
+        manyBeansPage.callStateless();
+        assertThat(manyBeansPage.message()).startsWith("Hello from 
ProtectedStatelessBean");
+        manyBeansPage.callProtectedMethod();
+        assertThat(manyBeansPage.message()).isEqualTo("protected method: hello 
from protected");
+        manyBeansPage.callViaInterface();
+        assertThat(manyBeansPage.message()).isEqualTo("Hello from 
ProtectedViaInterfaceBean");
+        manyBeansPage.callViaInterfaceMethod();
+        assertThat(manyBeansPage.message()).isEqualTo("Unprotected hello from 
ProtectedViaInterfaceMethodBean"
                 + " / Hello from ProtectedViaInterfaceMethodBean");
-        guardAjax(viaSuperclass).click();
-        assertThat(messages.getText()).isEqualTo("Hello from 
ProtectedViaSuperclassBean");
+        manyBeansPage.callViaSuperclass();
+        assertThat(manyBeansPage.message()).isEqualTo("Hello from 
ProtectedViaSuperclassBean");
     }
 
     @Test
     @OperateOnDeployment(DEPLOYMENT_DEV_MODE)
     void beanDestroyCalled() {
-        exerciseViewAndSessionScoped(facesViewScoped, "api/statistics/pc_fv", 
"api/statistics/pd_fv");
+        exerciseViewAndSessionScoped(manyBeansPage::callFacesViewScoped, 
"api/statistics/pc_fv", "api/statistics/pd_fv");
         webDriver.get(baseURL + "api/statistics/clear");
-        exerciseViewAndSessionScoped(omniViewScoped, "api/statistics/pc_ofv", 
"api/statistics/pd_ofv");
+        exerciseViewAndSessionScoped(manyBeansPage::callOmniViewScoped, 
"api/statistics/pc_ofv", "api/statistics/pd_ofv");
     }
 
-    private void exerciseViewAndSessionScoped(WebElement elem, String 
createStatistic, String destroyStatistic) {
-        webDriver.get(baseURL + "shiro/auth/loginform");
-        login();
+    private void exerciseViewAndSessionScoped(Runnable callBean, String 
createStatistic, String destroyStatistic) {
+        loginPage.goTo();
+        loginPage.login();
 
-        webDriver.get(baseURL + "shiro/unprotected/manybeans");
-        guardAjax(elem).click();
+        manyBeansPage.goTo();
+        callBean.run();
         webDriver.navigate().refresh();
-        guardAjax(elem).click();
-        guardAjax(sessionScoped).click();
+        callBean.run();
+        manyBeansPage.callSessionScoped();
 
-        invalidateSession.click();
-        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
-        webDriver.switchTo().alert().accept();
+        session.invalidateSession();
         webDriver.get(baseURL + createStatistic);
         
assertThat(webDriver.findElement(By.tagName("body")).getText()).isEqualTo("2");
         webDriver.get(baseURL + destroyStatistic);
@@ -186,14 +150,8 @@ public class ShiroBeansIT {
         
assertThat(webDriver.findElement(By.tagName("body")).getText()).isEqualTo("1");
     }
 
-    private void login() {
-        username.sendKeys("webuser");
-        password.sendKeys("webpwd");
-        guardHttp(login).click();
-    }
-
     @Deployment(testable = false, name = DEPLOYMENT_DEV_MODE)
     public static WebArchive createDeployment() {
-        return ShiroAuthFormsIT.createDeploymentDev("shiro-beans-test.war");
+        return ShiroAuthFormsIT.createDeploymentDev("shiro-beans-test");
     }
 }
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java
index 19c064921..a68909848 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java
@@ -63,6 +63,6 @@ public class ShiroSSLFilterIT {
 
     @Deployment(testable = false, name = DEPLOYMENT_PROD_MODE)
     public static WebArchive createDeploymentProd() {
-        return 
ShiroAuthFormsIT.createDeploymentProd("ShiroSSLFilterTest-prod.war");
+        return 
ShiroAuthFormsIT.createDeploymentProd("ShiroSSLFilterTest-prod");
     }
 }
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/FormPage.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/FormPage.java
new file mode 100644
index 000000000..e33b7ba30
--- /dev/null
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/FormPage.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shiro.testing.jakarta.ee.pages;
+
+import static org.jboss.arquillian.graphene.Graphene.guardAjax;
+import static org.jboss.arquillian.graphene.Graphene.guardHttp;
+import static org.jboss.arquillian.graphene.Graphene.waitForHttp;
+
+import java.net.URL;
+import java.util.List;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Location;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+@Location("shiro/form")
+public class FormPage {
+    @Drone
+    private WebDriver webDriver;
+
+    @ArquillianResource
+    private URL baseURL;
+
+    @FindBy(id = "firstForm:firstName")
+    private WebElement firstName;
+
+    @FindBy(id = "firstForm:lastName")
+    private WebElement lastName;
+
+    @FindBy(id = "firstForm:submitFirst")
+    private WebElement submitFirst;
+
+    @FindBy(id = "secondForm:address")
+    private WebElement address;
+
+    @FindBy(id = "secondForm:city")
+    private WebElement city;
+
+    @FindBy(id = "secondForm:submitSecond")
+    private WebElement submitSecond;
+
+    @FindBy(id = "secondForm:messages")
+    private WebElement secondFormMessages;
+
+    @FindBy(id = "firstForm:messages")
+    private WebElement firstFormMessages;
+
+    @FindBy(id = "messages")
+    private List<WebElement> submissionMessages;
+
+    public void goTo() {
+        webDriver.get(baseURL + "shiro/form");
+    }
+
+    public void goToAnonymous() {
+        webDriver.get(baseURL + "shiro/unprotected/form");
+    }
+
+    public void submitFirstForm(String first, String last) {
+        firstName.sendKeys(first);
+        lastName.sendKeys(last);
+        guardHttp(submitFirst).click();
+    }
+
+    public void fillSecondForm(String street, String town) {
+        address.sendKeys(street);
+        city.sendKeys(town);
+    }
+
+    public void clearSecondForm() {
+        address.clear();
+        city.clear();
+    }
+
+    public void submitSecondForm() {
+        guardAjax(submitSecond).click();
+    }
+
+    public void submitSecondFormWithRedirect() {
+        waitForHttp(submitSecond).click();
+    }
+
+    public String firstName() {
+        return firstName.getAttribute("value");
+    }
+
+    public String firstFormMessage() {
+        return firstFormMessages.getText();
+    }
+
+    public String secondFormMessage() {
+        return secondFormMessages.getText();
+    }
+
+    public boolean hasSubmissionMessage() {
+        return !submissionMessages.isEmpty();
+    }
+
+    public String submissionMessage() {
+        return submissionMessages.get(0).getText();
+    }
+}
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/LoginPage.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/LoginPage.java
new file mode 100644
index 000000000..e3f47b4bb
--- /dev/null
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/LoginPage.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shiro.testing.jakarta.ee.pages;
+
+import static org.jboss.arquillian.graphene.Graphene.guardHttp;
+
+import java.net.URL;
+import java.util.List;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Location;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+@Location("shiro/auth/loginform")
+public class LoginPage {
+    @Drone
+    private WebDriver webDriver;
+
+    @ArquillianResource
+    private URL baseURL;
+
+    @FindBy(id = "username")
+    private WebElement username;
+
+    @FindBy(id = "password")
+    private WebElement password;
+
+    @FindBy(id = "login")
+    private WebElement login;
+
+    @FindBy(id = "login2")
+    private WebElement nonJSFLogin;
+
+    @FindBy(id = "rememberMe")
+    private WebElement rememberMe;
+
+    @FindBy(id = "sessionExpiredMessage")
+    private WebElement sessionExpiredMessage;
+
+    @FindBy(id = "loginFailureMessage")
+    private WebElement loginFailureMessage;
+
+    @FindBy(className = "shiro-form-data-notice")
+    private List<WebElement> formDataNotices;
+
+    @FindBy(name = "org.apache.shiro.form-data.discard")
+    private WebElement discardFormData;
+
+    public void goTo() {
+        webDriver.get(baseURL + "shiro/auth/loginform");
+    }
+
+    public void login() {
+        login("webuser", "webpwd");
+    }
+
+    public void login(String user, String pwd) {
+        enterCredentials(user, pwd);
+        guardHttp(login).click();
+    }
+
+    public void loginNonJSF() {
+        enterCredentials("webuser", "webpwd");
+        guardHttp(nonJSFLogin).click();
+    }
+
+    public void rememberMe() {
+        if (!rememberMe.isSelected()) {
+            rememberMe.click();
+        }
+    }
+
+    public String sessionExpiredMessage() {
+        return sessionExpiredMessage.getText();
+    }
+
+    public String loginFailureMessage() {
+        return loginFailureMessage.getText();
+    }
+
+    public boolean hasFormDataNotice() {
+        return !formDataNotices.isEmpty();
+    }
+
+    public String formDataNotice() {
+        return formDataNotices.get(0).getText();
+    }
+
+    public boolean isDiscardFormDataSelected() {
+        return discardFormData.isSelected();
+    }
+
+    public void discardSavedFormData() {
+        discardFormData.click();
+    }
+
+    private void enterCredentials(String user, String pwd) {
+        username.sendKeys(user);
+        password.sendKeys(pwd);
+    }
+}
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/ManyBeansPage.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/ManyBeansPage.java
new file mode 100644
index 000000000..df347ef41
--- /dev/null
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/ManyBeansPage.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shiro.testing.jakarta.ee.pages;
+
+import static org.jboss.arquillian.graphene.Graphene.guardAjax;
+
+import java.net.URL;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Location;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+@Location("shiro/unprotected/manybeans")
+public class ManyBeansPage {
+    @Drone
+    private WebDriver webDriver;
+
+    @ArquillianResource
+    private URL baseURL;
+
+    @FindBy(id = "form:facesViewScoped")
+    private WebElement facesViewScoped;
+
+    @FindBy(id = "form:omniViewScoped")
+    private WebElement omniViewScoped;
+
+    @FindBy(id = "form:sessionScoped")
+    private WebElement sessionScoped;
+
+    @FindBy(id = "form:stateless")
+    private WebElement stateless;
+
+    @FindBy(id = "form:unprotected")
+    private WebElement unprotectedMethod;
+
+    @FindBy(id = "form:protected")
+    private WebElement protectedMethod;
+
+    @FindBy(id = "form:viaInterface")
+    private WebElement viaInterface;
+
+    @FindBy(id = "form:viaInterfaceMethod")
+    private WebElement viaInterfaceMethod;
+
+    @FindBy(id = "form:viaSuperclass")
+    private WebElement viaSuperclass;
+
+    @FindBy(id = "form:messages")
+    private WebElement messages;
+
+    public void goTo() {
+        webDriver.get(baseURL + "shiro/unprotected/manybeans");
+    }
+
+    public void callFacesViewScoped() {
+        guardAjax(facesViewScoped).click();
+    }
+
+    public void callOmniViewScoped() {
+        guardAjax(omniViewScoped).click();
+    }
+
+    public void callSessionScoped() {
+        guardAjax(sessionScoped).click();
+    }
+
+    public void callStateless() {
+        guardAjax(stateless).click();
+    }
+
+    public void callUnprotectedMethod() {
+        guardAjax(unprotectedMethod).click();
+    }
+
+    public void callProtectedMethod() {
+        guardAjax(protectedMethod).click();
+    }
+
+    public void callViaInterface() {
+        guardAjax(viaInterface).click();
+    }
+
+    public void callViaInterfaceMethod() {
+        guardAjax(viaInterfaceMethod).click();
+    }
+
+    public void callViaSuperclass() {
+        guardAjax(viaSuperclass).click();
+    }
+
+    public String message() {
+        return messages.getText();
+    }
+}
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/SessionControls.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/SessionControls.java
new file mode 100644
index 000000000..f40082f6a
--- /dev/null
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/SessionControls.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shiro.testing.jakarta.ee.pages;
+
+import static org.jboss.arquillian.graphene.Graphene.guardHttp;
+import static org.jboss.arquillian.graphene.Graphene.waitGui;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+
+public class SessionControls {
+    @Drone
+    private WebDriver webDriver;
+
+    @FindBy(id = "invalidate")
+    private WebElement invalidateSession;
+
+    @FindBy(id = "form:logout")
+    private WebElement logout;
+
+    @FindBy(id = "logoutFiaFilter")
+    private WebElement logoutViaFilter;
+
+    public void invalidateSession() {
+        invalidateSession.click();
+        waitGui(webDriver).until(ExpectedConditions.alertIsPresent());
+        webDriver.switchTo().alert().accept();
+    }
+
+    public void logout() {
+        guardHttp(logout).click();
+    }
+
+    public void logoutViaFilter() {
+        guardHttp(logoutViaFilter).click();
+    }
+}
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/TagsPage.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/TagsPage.java
new file mode 100644
index 000000000..8f6a54daa
--- /dev/null
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/pages/TagsPage.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.shiro.testing.jakarta.ee.pages;
+
+import java.net.URL;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Location;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+@Location("shiro/unprotected/tags")
+public class TagsPage {
+    @Drone
+    private WebDriver webDriver;
+
+    @ArquillianResource
+    private URL baseURL;
+
+    @FindBy(id = "guestTag")
+    private WebElement guest;
+
+    @FindBy(id = "userTag")
+    private WebElement user;
+
+    @FindBy(id = "authenticatedTag")
+    private WebElement authenticated;
+
+    @FindBy(id = "notAuthenticatedTag")
+    private WebElement notAuthenticated;
+
+    @FindBy(id = "principalTag")
+    private WebElement principal;
+
+    @FindBy(id = "principalTagByType")
+    private WebElement principalByType;
+
+    @FindBy(id = "principalTagByProperty")
+    private WebElement principalByProperty;
+
+    @FindBy(id = "hasRegularRoleTag")
+    private WebElement regularRole;
+
+    @FindBy(id = "lacksAdminRoleTag")
+    private WebElement lacksAdminRole;
+
+    @FindBy(id = "hasAnyRoleTag")
+    private WebElement hasAnyRole;
+
+    @FindBy(id = "hasPermissionTag")
+    private WebElement hasPermission;
+
+    @FindBy(id = "lacksPermissionTag")
+    private WebElement lacksPermission;
+
+    @FindBy(id = "hasAnyPermissionTag")
+    private WebElement hasAnyPermission;
+
+    @FindBy(id = "rememberedTag")
+    private WebElement remembered;
+
+    public void goTo() {
+        webDriver.get(baseURL + "shiro/unprotected/tags");
+    }
+
+    public String guest() {
+        return guest.getText();
+    }
+
+    public String user() {
+        return user.getText();
+    }
+
+    public String authenticated() {
+        return authenticated.getText();
+    }
+
+    public String notAuthenticated() {
+        return notAuthenticated.getText();
+    }
+
+    public String principal() {
+        return principal.getText();
+    }
+
+    public String principalByType() {
+        return principalByType.getText();
+    }
+
+    public String principalByProperty() {
+        return principalByProperty.getText();
+    }
+
+    public String regularRole() {
+        return regularRole.getText();
+    }
+
+    public String lacksAdminRole() {
+        return lacksAdminRole.getText();
+    }
+
+    public String hasAnyRole() {
+        return hasAnyRole.getText();
+    }
+
+    public String hasPermission() {
+        return hasPermission.getText();
+    }
+
+    public String lacksPermission() {
+        return lacksPermission.getText();
+    }
+
+    public String hasAnyPermission() {
+        return hasAnyPermission.getText();
+    }
+
+    public String remembered() {
+        return remembered.getText();
+    }
+}
diff --git 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java
 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java
index 569eea07c..cd2aca1f3 100644
--- 
a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java
+++ 
b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java
@@ -161,6 +161,6 @@ public class NoIniJaxRsIT {
 
     @Deployment(name = TESTABLE_MODE)
     public static WebArchive createDeployment() {
-        return ComponentInjectionIT.createDeployment("no-ini-jaxrs.war");
+        return ComponentInjectionIT.createDeployment("no-ini-jaxrs");
     }
 }

Reply via email to