hu.ibello.pages.PageObject Maven / Gradle / Ivy
Show all versions of ibello-api Show documentation
/*
* Ark-Sys Kft. licenses this file to you 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 hu.ibello.pages;
import hu.ibello.actions.ActionBuilder;
import hu.ibello.actions.KeyHelper;
import hu.ibello.core.Browser;
import hu.ibello.core.Name;
import hu.ibello.core.Value;
import hu.ibello.elements.WebElement;
import hu.ibello.elements.WebElements;
import hu.ibello.expect.ExpectationBuilder;
import hu.ibello.inject.Inject;
import hu.ibello.inject.Injectable;
import hu.ibello.inject.Scope;
import hu.ibello.search.Find;
import hu.ibello.search.Frame;
import hu.ibello.search.Position;
import hu.ibello.search.Relation;
import hu.ibello.search.SearchTool;
/**
*
* Superclass for page objects. Each class sub-classing it will be automatically injected by the injector in
* session-scope - there is no need for {@link Inject} annotation.
*
*
* During the dependency injection the injector automatically initializes all fields in a page object, when the
* field has one {@link Find} annotation and it's type is one of the followings:
*
*
* - {@link WebElement} - the field will represent a single element on the page,
* - {@link WebElements} - the field will represent multiple elements on the page.
*
*
* The fields even can be private. Examples:
*
*
* {@literal @}Find(selector="#ok-button")
* private WebElement okButton;
*
* {@literal @}Find(selector=".main-table tr")
* private WebElements tableRows;
*
*
* After the {@link Find} annotation some other (modifier) annotations can be added to a field.
* With the {@link Position} annotation the desired element's relative position can be specified to an anchor element.
* With the {@link Relation} annotation the structural relation between the desired and anchor elements can be
* specified. Examples:
*
*
* {@literal @}Find(selector="button")
* {@literal @}Position(type=PositionType.LEFT_FROM, selector="#ok-button")
* private WebElement cancelButton;
*
* {@literal @}Find(selector="button")
* {@literal @}Relation(type=RelationType.DESCENDANT_OF, selector="#modal-window")
* private WebElement modalButton;
*
*
* When the content of a page is included by an iframe
parent, then a single {@link Find} annotation will
* not find the desired elements. In this case, a {@link Frame} annotation should be added to the page object class,
* which specifies the search properties of the iframe
element. Every element search inside of this page object
* will be automatically performed inside of that iframe
.
*
*
* A page object encapsulates the technical functionality of a well-defined part of the application under test.
* For example, it can represent a single web-page, a navigation bar, a frame, ... Every
* necessary action available on that object is specified in the page object as public method. Every assertion
* that can be verified on that object is represented by a public method too.
*
*
* The abstract {@link PageObject} class contains some useful protected methods. These are for:
*
*
* - doing something with elements, see {@link PageObject#doWith(WebElement)},
* - accessing browser interface which can be used to open an URL, and to other things,
* see {@link PageObject#browser()},
* - verifying some expectations, see {@link PageObject#expectations()},
* - reading configuration values, see {@link PageObject#getConfigurationValue(String)}.
*
*
* Examples:
*
*
* public void clickButton() {
* // clicking a button
* doWith(okButton).click();
* }
*
* private WebElement findButton() {
* // finding a specific element on page
* return browser().find("#ok-button");
* }
*
* public void openPage() {
* // opening a specific URL
* browser().openURL("http://localhost/page");
* }
*
* public void expectButtonIsVisible() {
* // verifying that button is visible
* expectations().expect(okButton).toBe().visible();
* }
*
* public void expectPageIsOpened() {
* // verifying that a specific URL is opened
* expectations().expect(browser()).toHave().url("http://localhost/page");
* }
*
* private Long getDefaultTimeout() {
* // returning configuration value as number
* return getConfigurationValue("ibello.timeout.default").toLong();
* }
*
*
* All public methods of a page object are considered as test steps and therefore automatically logged when called.
* The log will contain the descriptive name of the methods. If the method has a {@link Name} annotation, then
* the descriptive name will be the one specified by that annotation. Otherwise the descriptive name will be transformed
* from the name of the method; all underscore character will be replaced by a space, and all camel-case substring
* will be separated into multiple words. Method parameters are also included in the descriptive name.
*
*
* Examples:
*
*
* public void clickBigButton() {
* // descriptive name is "Click Big Button"
* }
*
* public void open_page() {
* // descriptive name is "Open Page"
* }
*
* {@literal @}Name("Close Modal Dialog")
* public void doSomething() {
* // descriptive name is "Close Modal Dialog"
* }
*
* {@literal @}Name("Click Button in Row ${0}")
* public void clickButton(int index) {
* // the name may contain parameter substitution marker
* // eg. clickButton(5) will have descriptive name: "Click Button in Row 5"
* }
*
*
* A page object should have a public default constructor.
*
* @author Kornél Simon
* @see Find
* @see Position
* @see Relation
*/
@Injectable(Scope.PAGE)
public abstract class PageObject {
@Inject
private PageObjectTool tool;
/**
*
* Returns a {@link SearchTool} instance which is used to search elements on the page.
*
*
* The returned instance offers a fluent interface for element search. Example:
*
*
* WebElement image = ...;
* WebElement child = find().using(By.TAG_NAME, "span").leftFrom(image).first();
*
* @return an object used for element search on the page
*/
protected SearchTool find() {
return tool.find();
}
/**
* Returns a configuration property as a {@link Value}. The returned value offers some public methods to
* transform the configuration property into different java types.
* This method always has a non-null result, even if the configuration value does not exist - in this case,
* the wrapped value will be null
.
* @param name name of the configuration parameter
* @return value of the configuration parameter wrapped into a {@link Value} instance
*/
protected Value getConfigurationValue(String name) {
return tool.getConfigurationValue(name);
}
/**
* Returns a {@link Browser} instance which can be used for different browser-specific actions,
* including element search and opening URL.
* @return an interface which offers browser-specific actions
*/
protected Browser browser() {
return tool.browser();
}
/**
* Returns an {@link ActionBuilder} instance which can be used to perform different actions on the web element.
* @param element we want to perform an action with this elements
* @return an interface configured for doing actions with the element
*/
protected ActionBuilder doWith(WebElement element) {
return tool.doWith(element);
}
/**
*
* Returns an {@link ExpectationBuilder} instance which can be used to build and execute an expectation.
*
*
* The returned instance offers a fluent interface for element search. Example:
*
*
* WebElement okButton = ...;
* WebElements buttons = ...;
* expectations().assume(okButton).toHave().text("OK");
* expectations().expect(okButton).toBe().visible();
* expectations().expect(buttons).toHave().size(5);
* expectations().expect(browser()).toHave().url("http://localhost/page");
*
* @return an {@link ExpectationBuilder} instance which is configured to run expectations
*/
protected ExpectationBuilder expectations() {
return tool.expectations();
}
/**
* Returns a {@link KeyHelper} instance, which offers special keys and key modifiers.
* Those can be used in {@link ActionBuilder#sendKeys(CharSequence...)} and
* {@link ActionBuilder#sendKeys(hu.ibello.actions.KeyModifier, CharSequence...)} methods.
* @return a {@link KeyHelper} instance
*/
protected KeyHelper keys() {
return tool.keys();
}
}