Introduce a new way of handling pages by Bobcat - a Page utility in favor of sub-classing PublishPage and AuthorPage.
Rationale:
Current approach
At the moment, in Bobcat we have abstract classes like AuthorPage or PublishPage that provide WebDriver instance for navigation properties and contain properties for domains.
The current approach with managing different pages is to subclass these types of pages, inject or simply hardcode the path and add additional fields, like specific page objects. These last items are usually driven by tests itself, they are not necessarily related to the page structure, e.g.:
tests of Title component on PageA will result in having the Title injected in PageA;
tests on the same page with a Box component will result in adding Box field to PageA;
but when running tests on the same component on PageB will require having additional PageObject PageB created - potentially with no difference to the page structure.
Additional few things worth considering / areas not addressed with the above approach:
we force inheritance with abstract classes
URL modifications like query strings or anchors are not easily handled with a fixed path
location != content - we have increasing number of Single-Page-Applications, where path of the current page has nothing to do with its content, same goes for content being modified by query strings/anchors - same URL means operating on different PageObjects based on the current * context/state of the application
automating authoring tests often is done on 'generic' pages - URL is a secondary property, we care only about currently needed parsys
it's not clear how switching between Edit/WcmModeDisabled or other modes should be done - same goes visiting same page on author/publish
in Cucumber tests, current page is more of a secondary concern - we usually operate on correctly scoped PageObjects related to sections/components/elements of the page, not the whole page itself
we keep paths for given pages in config files (like in the latest TouchUI module), approach driven by Cucumber (need of having human-readable keys for a given page)
redirects are problematic with PageObject-driven way (should the redirecting PageObject wait for the being redirected to or the other way around? how to pass paths between these two?)
Based on the above, Bobcat does not provide a clear guidance on how to approach page handling.
Proposed approach
Page utility
In favor of abstract classes, we could provide an extendable utility that would handle navigation and obtaining content.
Base assumptions:
contain required objects like WebDriver,
handle property injection
remember the state / handle redirects etc.
allow simple switching between different AEM modes
allow overriding/customization of the allowed items or actions
Example API
Opening pages
// based on path
Page.on(PUBLISH).path("/content/test/node").open();
// based on config, e.g pages.yml:
// Test page:
// - path: /content/test/page
Page.on(AUTHOR).named("Test page").open();
// with query string
Page.on(PUBLISH).path("tested page").query().open();
// custom env
Page.on("192.168.1.2:6103").path("/content/test/node").open();
// handling protocols
Page.protocol(HTTPS).on(PUBLISH).path("/content/test/node").open();
// setting defaults
Page.default().protocol(HTTPS);
Page.default().protocol(HTTP).on(PUBLISH);
// Remembering the context
Page.on(AUTHOR).path("/content/test/node").open(); //saves as current page
// ... operations on page objects causing a redirect ...
Page.lastPage().open();
// Following redirect
WebElement a = driver.findElement(By.cssLocator("a.my-link"));
Page.navigateBy(a -> a.click()).expecting().path("/content/redirected/path"); // handles `page loading, change of URL etc.
// Verifying redirects
Page.wasRedirected().path("/path/to/potential/redirect");
Obtaining content
// Obtaining parsys/component in authoring
// assuming navigation to an author page happened
// e.g. Page.on(AUTHOR).named("Test page").open();
// based on config, e.g pages.yml:
// Test page:
// - path: /content/test/page
// - parsys: /par
Page.current().get().parsys().component(Title.class);
// based on data-path (Touch UI)
Page.current().get().parsys("/data-path").component(Title.class);
// get 1st, last, nTh component from parsys
Page.current().get().parsys().first().component(Title.class) ;
Page.current().get().parsys().last().component(Title.class, 2) ;
Page.current().get().parsys().nth().component(Title.class, 2) ;
// obtaining scoped page objects
Page.current().get().pageobject(Section.class); // default scoping or based on PageObject(locator)
By locator = By.cssLocator(".my-scoped-element");
Page.current().get().scoped(locator).pageobject(Some.class);
WebElement myScope = driver.findElement(locator);
Page.current().get().scoped(myScope).pageobject(Another.class);
To be considered / nice to have
using EventFiringWebDriver and WebDriverEventListener to track navigation
introduce Navigable - wrapper for WebElements that action on causes navigation events (e.g. hyperlinks)
Introduce a new way of handling pages by Bobcat - a
Page
utility in favor of sub-classingPublishPage
andAuthorPage
.Rationale:
Current approach
At the moment, in Bobcat we have abstract classes like AuthorPage or PublishPage that provide WebDriver instance for navigation properties and contain properties for domains. The current approach with managing different pages is to subclass these types of pages, inject or simply hardcode the path and add additional fields, like specific page objects. These last items are usually driven by tests itself, they are not necessarily related to the page structure, e.g.:
In the end we're having multiple, redundant page objects being nothing else than wrappers for properties in specific use cases (as can be seen e.g. here: https://github.com/Cognifide/bobcat/blob/cb894457e92d3d02dbf146f682f35f1e52dc332a/bb-aem-integration-tests/src/main/java/com/cognifide/bdd/demo/po/product/CirclePage.java). Having such implementations indicates that we are recommending/suggesting this solution - while different projects have shown it is not being the most effective way of handling pages.
Additional few things worth considering / areas not addressed with the above approach:
Based on the above, Bobcat does not provide a clear guidance on how to approach page handling.
Proposed approach
Page utility
In favor of abstract classes, we could provide an extendable utility that would handle navigation and obtaining content. Base assumptions:
Example API
Opening pages
Opening pages in different AEM modes
Remembering the context, following redirects etc.
Obtaining content
To be considered / nice to have