Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement native scroll actions and use Selenium 4.23.0 #142

Merged
merged 1 commit into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
<dependency>
<groupId>com.github.aquality-automation</groupId>
<artifactId>aquality-selenium-core</artifactId>
<version>4.0.3</version>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/aquality/selenium/browser/Browser.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.openqa.selenium.*;
import org.openqa.selenium.WebDriver.Navigation;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.WheelInput.ScrollOrigin;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.RemoteWebDriver;
Expand Down Expand Up @@ -352,9 +354,32 @@ public void handlePromptAlert(AlertActions alertAction, String text) {
* @param y coordinate y
*/
public void scrollWindowBy(int x, int y) {
localizedLogger.info("loc.scrolling.by", x, y);
new Actions(getDriver()).scrollByAmount(x, y).perform();
}

/**
* Executes scrolling of the page to given coordinates x and y using JavaScript.
*
* @param x coordinate x
* @param y coordinate y
*/
public void scrollWindowByViaJs(int x, int y) {
localizedLogger.info("loc.scrolling.by.js", x, y);
executeScript(JavaScript.SCROLL_WINDOW_BY.getScript(), x, y);
}

/**
* Scrolls portion of screen from specified origin.
*
* @param scrollOrigin Origination point (either viewport or element, with possible offset)
* @param x coordinate x
* @param y coordinate y
*/
public void scrollFromOrigin(ScrollOrigin scrollOrigin, int x, int y) {
new Actions(getDriver()).scrollFromOrigin(scrollOrigin, x, y).perform();
}

/**
* Sets given window size
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void scrollIntoView() {
* @param y vertical coordinate
*/
public void scrollBy(int x, int y) {
logElementAction("loc.scrolling.js");
logElementAction("loc.scrolling.by.js", x, y);
executeScript(JavaScript.SCROLL_BY, x, y);
}

Expand Down
84 changes: 63 additions & 21 deletions src/main/java/aquality/selenium/elements/actions/MouseActions.java
Original file line number Diff line number Diff line change
@@ -1,81 +1,123 @@
package aquality.selenium.elements.actions;

import aquality.selenium.browser.AqualityServices;
import aquality.selenium.core.localization.ILocalizedLogger;
import aquality.selenium.core.utilities.IElementActionRetrier;
import aquality.selenium.elements.interfaces.IElement;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.WheelInput.ScrollOrigin;

import java.util.function.UnaryOperator;
import java.util.function.BiFunction;

import static aquality.selenium.browser.AqualityServices.getBrowser;

public class MouseActions {
private final IElement element;
private final String type;
private final String name;
private final ILocalizedLogger logger;
private final IElementActionRetrier elementActionRetrier;

public MouseActions(IElement element, String type) {
this.element = element;
this.type = type;
this.name = element.getName();
this.logger = AqualityServices.getLocalizedLogger();
this.elementActionRetrier = AqualityServices.get(IElementActionRetrier.class);
}

/**
* Click via Action.
*/
public void click() {
infoLoc("loc.clicking");
logElementAction("loc.clicking");
new JsActions(element, type).highlightElement();
performAction(Actions::click);
performActionAfterMove((elem, actions) -> actions.click());
}

/**
* Click Right (calls context menu) on the element
*/
public void rightClick() {
infoLoc("loc.clicking.right");
performAction(actions -> actions.contextClick(element.getElement()));
logElementAction("loc.clicking.right");
performActionAfterMove((elem, actions) -> actions.contextClick(elem));
}

/**
* Scrolling to element
*/
public void scrollToElement() {
logElementAction("loc.scrolling");
performAction((elem, actions) -> actions.scrollToElement(elem));
}

/**
* Scrolling by coordinates
*
* @param x horizontal coordinate
* @param y vertical coordinate
*/
public void scrollFromOrigin(int x, int y) {
scrollFromOrigin(x, y, 0, 0);
}

/**
* Scrolling by coordinates
*
* @param x horizontal coordinate
* @param y vertical coordinate
* @param xOffset horizontal offset
* @param yOffset vertical offset
*/
public void scrollFromOrigin(int x, int y, int xOffset, int yOffset)
{
logElementAction("loc.scrolling.by", x, y);
elementActionRetrier.doWithRetry(() -> {
ScrollOrigin scrollOrigin = ScrollOrigin.fromElement(element.getElement(), xOffset, yOffset);
getBrowser().scrollFromOrigin(scrollOrigin, x, y);
});
}

/**
* Move mouse to this element.
*/
public void moveMouseToElement() {
infoLoc("loc.moving");
performAction(actions -> actions);
logElementAction("loc.moving");
performActionAfterMove((elem, actions) -> actions);
}

/**
* Move mouse from this element.
*/
public void moveMouseFromElement() {
infoLoc("loc.movingFrom");
AqualityServices.get(IElementActionRetrier.class).doWithRetry(() ->
new Actions(getBrowser().getDriver())
.moveToElement(element.getElement(), -element.getElement().getSize().width, -element.getElement().getSize().height)
.build().perform());
logElementAction("loc.movingFrom");
performAction(((elem, actions) -> actions.moveToElement(elem, elem.getSize().width, elem.getSize().height)));
}

/**
* Performs double-click on the element.
*/
public void doubleClick() {
infoLoc("loc.clicking.double");
performAction(actions -> actions.doubleClick(element.getElement()));
logElementAction("loc.clicking.double");
performActionAfterMove((elem, actions) -> actions.doubleClick(elem));
}

private void performActionAfterMove(BiFunction<WebElement, Actions, Actions> function) {
performAction((elem, actions) -> function.apply(elem, actions.moveToElement(elem)));
}

private void performAction(UnaryOperator<Actions> function) {
Actions actions = new Actions(getBrowser().getDriver()).moveToElement(element.getElement());
AqualityServices.get(IElementActionRetrier.class).doWithRetry(() ->
function.apply(actions).build().perform());
private void performAction(BiFunction<WebElement, Actions, Actions> action) {
elementActionRetrier.doWithRetry(() -> action.apply(element.getElement(), new Actions(getBrowser().getDriver())).perform());
}

/**
* The implementation of a method for logging of MouseActions
*
* @param key key in localization resource of message to display in the log.
* @param key key in localization resource of message to display in the log.
* @param args Arguments, which will be provided to template of localized message.
*/
private void infoLoc(String key) {
AqualityServices.getLocalizedLogger().infoElementAction(type, name, key);
private void logElementAction(String key, Object... args) {
logger.infoElementAction(type, name, key, args);
}
}
10 changes: 10 additions & 0 deletions src/main/java/aquality/selenium/forms/Form.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ public IElementStateProvider state() {
* @param y vertical coordinate
*/
public void scrollBy(int x, int y) {
getFormLabel().getMouseActions().scrollFromOrigin(x, y);
}

/**
* Scroll form via JavaScript without scrolling entire page
*
* @param x horizontal coordinate
* @param y vertical coordinate
*/
public void scrollByJs(int x, int y) {
getFormLabel().getJsActions().scrollBy(x, y);
}

Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/localization/be.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@
"loc.movingFrom": "Адводзім курсор мышы ад элемента",
"loc.radio": "Радыёкнопка",
"loc.scrolling.center.js": "Пракручваем старонку да цэнтра элемента праз JavaScript",
"loc.scrolling.js": "Пракручваем старонку праз JavaScript",
"loc.scrolling.js": "Пракручваем старонку да элемента праз JavaScript",
"loc.scrolling": "Пракручваем старонку да элемента",
"loc.scrolling.by": "Пракручваем на (%s,%s)",
"loc.scrolling.by.js": "Пракручваем на (%s,%s) праз JavaScript",
"loc.selecting.value": "Выбіраем значэнне - '%s'",
"loc.deselecting.value": "Адмяняем выбар значэння - '%s'",
"loc.send.text": "Задаем тэкст - '%s'",
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/localization/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@
"loc.movingFrom": "Moving mouse from element",
"loc.radio": "RadioButton",
"loc.scrolling.center.js": "Scrolling to the center via JavaScript",
"loc.scrolling.js": "Scrolling via JavaScript",
"loc.scrolling.js": "Scrolling to element via JavaScript",
"loc.scrolling": "Scrolling to element",
"loc.scrolling.by": "Scrolling by (%s,%s)",
"loc.scrolling.by.js": "Scrolling by (%s,%s) via JavaScript",
"loc.selecting.value": "Selecting value - '%s'",
"loc.deselecting.value": "Deselecting value - '%s'",
"loc.send.text": "Setting text - '%s'",
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/localization/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@
"loc.movingFrom": "Przesuwanie myszy z elementu",
"loc.radio": "RadioButton",
"loc.scrolling.center.js": "Przewijanie do centrum przez JavaScript",
"loc.scrolling.js": "Przewijanie przez JavaScript",
"loc.scrolling.js": "Przewijanie do elementu przez JavaScript",
"loc.scrolling": "Przewijanie do elementu",
"loc.scrolling.by": "Przewijanie o (%s,%s)",
"loc.scrolling.by.js": "Przewijanie o (%s,%s) przez JavaScript",
"loc.selecting.value": "Wybieranie wartości - '%s'",
"loc.deselecting.value": "Anulowanie wybierania wartości - '%s'",
"loc.send.text": "Ustawianie tekstu - '%s'",
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/localization/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@
"loc.movingFrom": "Сдвиг курсора с элемента",
"loc.radio": "Радиокнопка",
"loc.scrolling.center.js": "Скроллинг в центр (посредством JavaScript)",
"loc.scrolling.js": "Скроллинг посредством JavaScript",
"loc.scrolling.js": "Скроллинг к элементу (посредством JavaScript)",
"loc.scrolling": "Скроллинг к элементу",
"loc.scrolling.by": "Скроллинг на (%s,%s)",
"loc.scrolling.by.js": "Скроллинг на (%s,%s) посредством JavaScript",
"loc.selecting.value": "Выбор значения - '%s'",
"loc.deselecting.value": "Отмена выбора значения - '%s'",
"loc.send.text": "Ввод текста - '%s'",
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/localization/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@
"loc.movingFrom": "Переміщення миші від елемента",
"loc.radio": "Радіокнопка",
"loc.scrolling.center.js": "Прокрутка до центру за допомогою JavaScript",
"loc.scrolling.js": "Прокрутка за допомогою JavaScript",
"loc.scrolling.js": "Прокрутка до елемента за допомогою JavaScript",
"loc.scrolling": "Прокрутка до елемента",
"loc.scrolling.by": "Прокрутка на (%s,%s)",
"loc.scrolling.by.js": "Прокрутка на (%s,%s) за допомогою JavaScript",
"loc.selecting.value": "Вибір значення - '%s'",
"loc.deselecting.value": "Скасування выбору значення - '%s'",
"loc.send.text": "Встановлення тексту - '%s'",
Expand Down
36 changes: 34 additions & 2 deletions src/test/java/tests/integration/ActionTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import theinternet.forms.JQueryMenuForm;
import theinternet.forms.WelcomeForm;

import java.awt.*;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;

Expand All @@ -22,7 +23,7 @@ public class ActionTests extends BaseTest {
@BeforeMethod
@Override
protected void beforeMethod() {
AqualityServices.getBrowser().getDriver().manage().window().maximize();
getBrowser().maximize();
}

@Test
Expand All @@ -35,11 +36,42 @@ public void testScrollToTheCenter() {

Long windowHeight = getScriptResultOrDefault("getWindowSize.js", 10L);
double currentY = getScriptResultOrDefault("getElementYCoordinate.js", 0.0, link.getElement());
double coordinateRelatingWindowCenter = windowHeight.doubleValue() / 2 - currentY;
double coordinateRelatingWindowCenter = windowHeight.doubleValue() / 2 - currentY;
Assert.assertTrue(Math.abs(coordinateRelatingWindowCenter) <= accuracy,
"Upper bound of element should be in the center of the page");
}

@Test
public void testScrollToElement() throws TimeoutException {
InfiniteScrollForm infiniteScrollForm = new InfiniteScrollForm();
getBrowser().goTo(infiniteScrollForm.getUrl());
infiniteScrollForm.waitForMoreExamples();
Dimension size = infiniteScrollForm.getLastExampleLabel().visual().getSize();
getBrowser().scrollWindowBy(size.width, size.height);
getBrowser().setWindowSize(size.width, size.height);
getBrowser().scrollWindowBy(0, 0);
int defaultCount = infiniteScrollForm.getExampleLabels().size();
AtomicReference<ILabel> lastExampleLabel = new AtomicReference<>(infiniteScrollForm.getLastExampleLabel());
AqualityServices.getConditionalWait().waitForTrue(() -> {
lastExampleLabel.set(infiniteScrollForm.getLastExampleLabel());
lastExampleLabel.get().getMouseActions().scrollToElement();
return infiniteScrollForm.getExampleLabels().size() > defaultCount;
}, "Some examples should be added after scroll");
}

@Test
public void testScrollFromOrigin() throws TimeoutException {
InfiniteScrollForm infiniteScrollForm = new InfiniteScrollForm();
getBrowser().goTo(infiniteScrollForm.getUrl());
int defaultCount = infiniteScrollForm.getExampleLabels().size();
AtomicReference<ILabel> lastExampleLabel = new AtomicReference<>(infiniteScrollForm.getLastExampleLabel());
AqualityServices.getConditionalWait().waitForTrue(() -> {
lastExampleLabel.set(infiniteScrollForm.getLastExampleLabel());
lastExampleLabel.get().getMouseActions().scrollFromOrigin(0, lastExampleLabel.get().visual().getSize().height);
return infiniteScrollForm.getExampleLabels().size() > defaultCount;
}, "Some examples should be added after scroll");
}

@Test
public void testScrollIntoView() throws TimeoutException {
InfiniteScrollForm infiniteScrollForm = new InfiniteScrollForm();
Expand Down
9 changes: 9 additions & 0 deletions src/test/java/tests/integration/BrowserTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ public void testShouldBePossibleToScrollWindowBy(){
getBrowser().scrollWindowBy(0, formHeight);
Assert.assertEquals(initialY - scrollForm.getFormPointInViewPort().getY(), formHeight);
}
@Test
public void testShouldBePossibleToScrollWindowByViaJavaScript(){
WelcomeForm scrollForm = new WelcomeForm();
getBrowser().goTo(scrollForm.getUrl());
int initialY = scrollForm.getFormPointInViewPort().getY();
int formHeight = (int) scrollForm.getSize().getHeight();
getBrowser().scrollWindowByViaJs(0, formHeight);
Assert.assertEquals(initialY - scrollForm.getFormPointInViewPort().getY(), formHeight);
}

@Test
public void testShouldBePossibleToGetBrowserName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import aquality.selenium.browser.AqualityServices;
import aquality.selenium.browser.devtools.EmulationHandling;
import com.google.common.collect.ImmutableMap;
import org.openqa.selenium.devtools.v124.emulation.Emulation;
import org.openqa.selenium.devtools.v124.emulation.model.DisplayFeature;
import org.openqa.selenium.devtools.v127.emulation.Emulation;
import org.openqa.selenium.devtools.v127.emulation.model.DisplayFeature;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import aquality.selenium.browser.AqualityServices;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.devtools.v124.network.model.ConnectionType;
import org.openqa.selenium.devtools.v127.network.model.ConnectionType;
import org.testng.Assert;
import org.testng.annotations.Test;
import tests.BaseTest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import manytools.BrowserLanguageForm;
import manytools.UserAgentForm;
import org.openqa.selenium.devtools.idealized.Network;
import org.openqa.selenium.devtools.v124.emulation.Emulation;
import org.openqa.selenium.devtools.v127.emulation.Emulation;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
Expand Down
Loading