Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
tobiasstamann committed Dec 5, 2024
2 parents 929a22f + bd29299 commit 746f229
Show file tree
Hide file tree
Showing 30 changed files with 495 additions and 216 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Why you should use this project?

Page Objects are a good way to produce a maintainable and reusable codebase to implement automated ui tests with selenium.
Nevertheless those page objects can contain a lot of (selenium related) boilerplate code that is mostly reused via copy and paste.
Nevertheless those page objects can contain a lot of (selenium related) boilerplate code that is mostly reused via copy and paste. (like for example having fluent waits or Actions)
This project provides processors to generate page object implementations by processing annotations placed on interfaces.
By doing that it drastically increases readability of page objects and reduces time for development.

Expand All @@ -22,7 +22,7 @@ By doing that it drastically increases readability of page objects and reduces t

# Restrictions

The project is still in development, so it currently just supports a few Actions like clicking or writing to input fields. Other Actions will be added in the near future or can be easily integrated via an SPI.
The project is still in development, so it currently just supports a few Actions like clicking or writing to input fields. Nevertheless it's quite simple to define custom Action annotations and their implementations.

Please create an issue, if you need specific action to be implemented. Usually it will be included shortly after ;)

Expand Down
2 changes: 1 addition & 1 deletion pogen4selenium-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<parent>
<groupId>io.toolisticon.pogen4selenium</groupId>
<artifactId>pogen4selenium</artifactId>
<version>0.6.1</version>
<version>0.7.0</version>
</parent>

<name>pogen4selenium-api</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import io.toolisticon.pogen4selenium.runtime.DefaultSideCondition;
import io.toolisticon.pogen4selenium.runtime.LocatorCondition;
import io.toolisticon.pogen4selenium.runtime.actions.BaseAction;

/**
* Meta-Annotation to allow custom annotations.
*
Expand All @@ -16,5 +20,12 @@
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Action {

/**
* The implementation class.
* @return
*/
Class<? extends ActionImpl> value();


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import io.toolisticon.pogen4selenium.runtime.DefaultSideCondition;
import io.toolisticon.pogen4selenium.runtime.LocatorCondition;
import io.toolisticon.pogen4selenium.runtime.actions.ActionClickImpl;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Action
@Action(ActionClickImpl.class)
public @interface ActionClick {

/**
Expand All @@ -19,4 +23,10 @@
/** The locator string to use. */
String value();

/**
* The locator strategy to use, will just be taken into account if by attribute is not set to ELEMENT.
* @return the Locator strategy, defaults to DefaultLocatorStrategy
*/
@ActionSideCondition
Class<? extends LocatorCondition> actionSideCondition() default DefaultSideCondition.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.toolisticon.pogen4selenium.api;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
* The base interface for all actions.
*/
public interface ActionImpl {

/**
* Execute action on passed webElement
* @param webElement
*/
public void executeAction(WebElement webElement);

/**
* Execute action on element located by locator
* @param locator
*/
public void executeAction(By locator);


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import io.toolisticon.pogen4selenium.runtime.DefaultSideCondition;
import io.toolisticon.pogen4selenium.runtime.LocatorCondition;
import io.toolisticon.pogen4selenium.runtime.actions.ActionMoveToAndClickImpl;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Action
@Action(ActionMoveToAndClickImpl.class)
public @interface ActionMoveToAndClick {

/**
Expand All @@ -19,4 +23,10 @@
/** The locator string to use. */
String value();

/**
* The locator strategy to use, will just be taken into account if by attribute is not set to ELEMENT.
* @return the Locator strategy, defaults to DefaultLocatorStrategy
*/
@ActionSideCondition
Class<? extends LocatorCondition> actionSideCondition() default DefaultSideCondition.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.toolisticon.pogen4selenium.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionSideCondition {

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import io.toolisticon.pogen4selenium.runtime.DefaultSideCondition;
import io.toolisticon.pogen4selenium.runtime.LocatorCondition;
import io.toolisticon.pogen4selenium.runtime.actions.ActionWriteImpl;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Action
@Action(ActionWriteImpl.class)
public @interface ActionWrite {

/**
Expand All @@ -19,4 +23,11 @@
/** The locator string to use. */
String value();

/**
* The locator strategy to use, will just be taken into account if by attribute is not set to ELEMENT.
* @return the Locator strategy, defaults to DefaultLocatorStrategy
*/
@ActionSideCondition
Class<? extends LocatorCondition> actionSideCondition() default DefaultSideCondition.class;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.toolisticon.pogen4selenium.runtime;

import java.util.Arrays;
import java.util.Collection;

import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class DefaultSideCondition implements LocatorCondition {

@Override
public boolean checkCondition(WebDriver driver, WebElement element) {
return true;
}

@Override
public Collection<Class<? extends Throwable>> exceptionsToIgnore() {
return Arrays.asList(NoSuchElementException.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.toolisticon.pogen4selenium.runtime;

import java.util.Collection;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public interface LocatorCondition{

boolean checkCondition(WebDriver driver, WebElement element);

Collection<Class<? extends Throwable>> exceptionsToIgnore();

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
Expand Down Expand Up @@ -102,6 +103,16 @@ public WebElement waitForElementToBeInteractable(By by) {
return wait.until(ExpectedConditions.elementToBeClickable(by));
}

public WebElement waitForElementToBeInteractable(ExpectedCondition<WebElement> expectedCondition) {
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(15))
.pollingEvery(Duration.ofMillis(300))
.ignoring(NoSuchElementException.class,ElementNotInteractableException.class);

return wait.until(expectedCondition);
}

protected WebElement waitForElementToBeInteractable(WebElement element) {
if(element == null) {
return null;
Expand Down Expand Up @@ -132,6 +143,21 @@ public WebElement waitForElementToBePresent(By by) {

}

public WebElement waitForElementToBePresent(ExpectedCondition<WebElement> expectedCondition) {
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(15))
.pollingEvery(Duration.ofMillis(300))
.ignoring(NoSuchElementException.class);

return wait.until(expectedCondition);

}





protected void waitForElementToBeAbsent(String xpath) {
Wait<WebDriver> wait =
new FluentWait<>(driver)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.toolisticon.pogen4selenium.runtime.actions;

import java.util.Arrays;
import java.util.Collection;

import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import io.toolisticon.pogen4selenium.runtime.LocatorCondition;

public class ActionClickImpl extends BaseAction {

public ActionClickImpl(WebDriver driver, LocatorCondition sideCondition) {
super(driver, sideCondition);

}

@Override
public boolean checkCondition(WebDriver driver, WebElement element) {
return element.isDisplayed() && element.isEnabled();
}

@Override
public Collection<Class<? extends Throwable>> exceptionsToIgnore() {
return Arrays.asList(NoSuchElementException.class);
}


@Override
protected void applyAction(WebElement webElement) {
webElement.click();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.toolisticon.pogen4selenium.runtime.actions;

import java.util.Arrays;
import java.util.Collection;

import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import io.toolisticon.pogen4selenium.runtime.LocatorCondition;

public class ActionMoveToAndClickImpl extends BaseAction {


public ActionMoveToAndClickImpl(WebDriver driver, LocatorCondition sideCondition) {
super(driver, sideCondition);
}

@Override
public boolean checkCondition(WebDriver driver, WebElement element) {
return element.isDisplayed() && element.isEnabled();
}

@Override
public Collection<Class<? extends Throwable>> exceptionsToIgnore() {
return Arrays.asList(NoSuchElementException.class);
}

@Override
protected void applyAction(WebElement webElement) {
new Actions(driver).moveToElement(webElement).pause(300).click().perform();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.toolisticon.pogen4selenium.runtime.actions;

import java.util.Arrays;
import java.util.Collection;

import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import io.toolisticon.pogen4selenium.runtime.LocatorCondition;

public class ActionWriteImpl extends BaseAction {


private final String toSet;

public ActionWriteImpl(WebDriver driver, LocatorCondition sideCondition, String toSet) {
super(driver, sideCondition);

this.toSet = toSet;
}

@Override
public boolean checkCondition(WebDriver driver, WebElement element) {
return element.isDisplayed() && element.isEnabled();
}

@Override
public Collection<Class<? extends Throwable>> exceptionsToIgnore() {
return Arrays.asList(NoSuchElementException.class);
}

@Override
protected void applyAction(WebElement webElement) {

webElement.click();
webElement.sendKeys(Keys.CONTROL + "a");
webElement.sendKeys(Keys.DELETE);
webElement.sendKeys(toSet);

}

}
Loading

0 comments on commit 746f229

Please sign in to comment.