diff --git a/docs/modules/plugins/pages/plugin-mobile-app.adoc b/docs/modules/plugins/pages/plugin-mobile-app.adoc index 05cd791826..7cb54f5d16 100644 --- a/docs/modules/plugins/pages/plugin-mobile-app.adoc +++ b/docs/modules/plugins/pages/plugin-mobile-app.adoc @@ -436,6 +436,9 @@ When I clear field located `accessibilityId(username)` Swipes to an element in either UP, DOWN, LEFT, or RIGHT direction with the specified swipe duration +[INFO] +The step takes into account current context. If you need to perform swipe on the element, you need to switch the context to this element. + ==== *_Wording_* [source,gherkin] @@ -467,6 +470,16 @@ When I swipe UP to element located `accessibilityId(end-of-screen)` with duratio Then number of elements found by `accessibilityId(end-of-screen)` is equal to `1` ---- +.Swipe context element.story +[source,gherkin] +---- +Scenario: Switch slides +When I change context to element located `accessibilityId(carousel)` +Then number of elements found by `accessibilityId(slide 2)` is equal to `0` +When I swipe LEFT to element located `accessibilityId(slide 2)` with duration PT1S +Then number of elements found by `accessibilityId(slide 2)` is equal to `1` +---- + === Upload a file to a device ==== *_Info_* diff --git a/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/model/SwipeDirection.java b/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/model/SwipeDirection.java index d4a2b6fc1e..644fce3d02 100644 --- a/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/model/SwipeDirection.java +++ b/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/model/SwipeDirection.java @@ -17,6 +17,8 @@ package org.vividus.bdd.mobileapp.model; import org.openqa.selenium.Dimension; +import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; import org.vividus.bdd.mobileapp.configuration.MobileApplicationConfiguration; public enum SwipeDirection @@ -24,60 +26,68 @@ public enum SwipeDirection UP { @Override - public SwipeCoordinates calculateCoordinates(Dimension dimension, + public SwipeCoordinates calculateCoordinates(Rectangle swipeArea, MobileApplicationConfiguration mobileApplicationConfiguration) { - int indent = dimension.getHeight() / VERTICAL_INDENT_COEFFICIENT; - return createCoordinates(dimension.getHeight() - indent, indent, dimension.getWidth(), - mobileApplicationConfiguration.getSwipeVerticalXPosition()); + int indent = swipeArea.getHeight() / VERTICAL_INDENT_COEFFICIENT; + return createCoordinates(swipeArea.getHeight() - indent, indent, swipeArea.getWidth(), + mobileApplicationConfiguration.getSwipeVerticalXPosition(), swipeArea.getPoint()); } }, DOWN { @Override - public SwipeCoordinates calculateCoordinates(Dimension dimension, + public SwipeCoordinates calculateCoordinates(Rectangle swipeArea, MobileApplicationConfiguration mobileApplicationConfiguration) { - int indent = dimension.getHeight() / VERTICAL_INDENT_COEFFICIENT; - return createCoordinates(indent, dimension.getHeight() - indent, dimension.getWidth(), - mobileApplicationConfiguration.getSwipeVerticalXPosition()); + int indent = swipeArea.getHeight() / VERTICAL_INDENT_COEFFICIENT; + return createCoordinates(indent, swipeArea.getHeight() - indent, swipeArea.getWidth(), + mobileApplicationConfiguration.getSwipeVerticalXPosition(), swipeArea.getPoint()); } }, LEFT { @Override - public SwipeCoordinates calculateCoordinates(Dimension dimension, + public SwipeCoordinates calculateCoordinates(Rectangle swipeArea, MobileApplicationConfiguration mobileApplicationConfiguration) { - int indent = dimension.getWidth() / HORIZONTAL_INDENT_COEFFICIENT; - int y = calculateCoordinate(dimension.getHeight(), + int indent = swipeArea.getWidth() / HORIZONTAL_INDENT_COEFFICIENT; + int y = calculateCoordinate(swipeArea.getHeight(), mobileApplicationConfiguration.getSwipeHorizontalYPosition()); - return new SwipeCoordinates(dimension.getWidth() - indent, y, indent, y); + return createAdjustedCoordinates(swipeArea.getWidth() - indent, y, indent, y, swipeArea.getPoint()); } }, RIGHT { @Override - public SwipeCoordinates calculateCoordinates(Dimension dimension, + public SwipeCoordinates calculateCoordinates(Rectangle swipeArea, MobileApplicationConfiguration mobileApplicationConfiguration) { + Dimension dimension = swipeArea.getDimension(); + Point point = swipeArea.getPoint(); int indent = dimension.getWidth() / HORIZONTAL_INDENT_COEFFICIENT; int y = calculateCoordinate(dimension.getHeight(), mobileApplicationConfiguration.getSwipeHorizontalYPosition()); - return new SwipeCoordinates(indent, y, dimension.getWidth() - indent, y); + return createAdjustedCoordinates(indent, y, dimension.getWidth() - indent, y, point); } }; private static final int VERTICAL_INDENT_COEFFICIENT = 5; private static final int HORIZONTAL_INDENT_COEFFICIENT = 8; - public abstract SwipeCoordinates calculateCoordinates(Dimension dimension, + public abstract SwipeCoordinates calculateCoordinates(Rectangle swipeArea, MobileApplicationConfiguration mobileApplicationConfiguration); - public static SwipeCoordinates createCoordinates(int startY, int endY, int width, int xOffsetPercentage) + public static SwipeCoordinates createCoordinates(int startY, int endY, int width, int xOffsetPercentage, + Point point) { int x = calculateCoordinate(width, xOffsetPercentage); - return new SwipeCoordinates(x, startY, x, endY); + return createAdjustedCoordinates(x, startY, x, endY, point); + } + + private static SwipeCoordinates createAdjustedCoordinates(int startX, int startY, int endX, int endY, Point point) + { + return new SwipeCoordinates(startX + point.x, startY + point.y, endX + point.getX(), endY + point.getY()); } @SuppressWarnings("MagicNumber") diff --git a/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/steps/TouchSteps.java b/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/steps/TouchSteps.java index f9bc6507fc..d0972de645 100644 --- a/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/steps/TouchSteps.java +++ b/vividus-plugin-mobile-app/src/main/java/org/vividus/bdd/mobileapp/steps/TouchSteps.java @@ -20,8 +20,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.function.Supplier; import org.jbehave.core.annotations.When; +import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; +import org.openqa.selenium.SearchContext; import org.openqa.selenium.WebElement; import org.vividus.bdd.mobileapp.model.SwipeDirection; import org.vividus.bdd.monitor.TakeScreenshotOnFailure; @@ -31,6 +35,7 @@ import org.vividus.selenium.manager.GenericWebDriverManager; import org.vividus.ui.action.ISearchActions; import org.vividus.ui.action.search.Locator; +import org.vividus.ui.context.IUiContext; @TakeScreenshotOnFailure public class TouchSteps @@ -42,14 +47,16 @@ public class TouchSteps private final IBaseValidations baseValidations; private final ISearchActions searchActions; private final GenericWebDriverManager genericWebDriverManager; + private final IUiContext uiContext; public TouchSteps(TouchActions touchActions, IBaseValidations baseValidations, - ISearchActions searchActions, GenericWebDriverManager genericWebDriverManager) + ISearchActions searchActions, GenericWebDriverManager genericWebDriverManager, IUiContext uiContext) { this.touchActions = touchActions; this.baseValidations = baseValidations; this.searchActions = searchActions; this.genericWebDriverManager = genericWebDriverManager; + this.uiContext = uiContext; } /** @@ -89,6 +96,8 @@ public void tapByLocator(Locator locator) /** * Swipes to element in direction direction with duration duration + * The step takes into account current context. If you need to perform swipe on the element, + * you need to switch the context to this element. * @param direction direction to swipe, either UP or DOWN * @param locator locator to find an element * @param swipeDuration swipe duration in ISO 8601 format @@ -97,44 +106,54 @@ public void tapByLocator(Locator locator) public void swipeToElement(SwipeDirection direction, Locator locator, Duration swipeDuration) { locator.getSearchParameters().setWaitForElement(false); - + Supplier swipeArea = createSwipeArea(); List elements = new ArrayList<>(searchActions.findElements(locator)); if (elements.isEmpty()) { - touchActions.swipeUntil(direction, swipeDuration, () -> + touchActions.swipeUntil(direction, swipeDuration, swipeArea.get(), () -> { elements.addAll(searchActions.findElements(locator)); return !elements.isEmpty(); }); } - if (baseValidations.assertElementsNumber(String.format("The element by locator %s exists", locator), elements, ComparisonRule.EQUAL_TO, 1) && (SwipeDirection.UP == direction || SwipeDirection.DOWN == direction)) { - adjustVerticalPosition(elements.get(0), swipeDuration); + adjustVerticalPosition(elements.get(0), swipeArea.get(), swipeDuration); + } + } + + private Supplier createSwipeArea() + { + SearchContext searchContext = uiContext.getSearchContext(); + if (searchContext instanceof WebElement) + { + WebElement contextElement = (WebElement) searchContext; + return contextElement::getRect; } + return () -> new Rectangle(new Point(0, 0), genericWebDriverManager.getSize()); } - private void adjustVerticalPosition(WebElement element, Duration swipeDuration) + private void adjustVerticalPosition(WebElement element, Rectangle swipeArea, Duration swipeDuration) { - int windowSizeHeight = genericWebDriverManager.getSize().getHeight(); - int windowCenterY = windowSizeHeight / 2; + int swipeAreaSizeHeight = swipeArea.getHeight(); + int swipeAreaCenterY = swipeAreaSizeHeight / 2; int elementTopCoordinateY = element.getLocation().getY(); - int bottomVisibilityIndent = (int) (VISIBILITY_BOTTOM_INDENT_COEFFICIENT * windowSizeHeight); - int visibilityY = windowSizeHeight - bottomVisibilityIndent; + int bottomVisibilityIndent = (int) (VISIBILITY_BOTTOM_INDENT_COEFFICIENT * swipeAreaSizeHeight); + int visibilityY = swipeAreaSizeHeight - bottomVisibilityIndent; if (elementTopCoordinateY > visibilityY) { - touchActions.performVerticalSwipe(windowCenterY, windowCenterY - (elementTopCoordinateY - visibilityY), - swipeDuration); + touchActions.performVerticalSwipe(swipeAreaCenterY, + swipeAreaCenterY - (elementTopCoordinateY - visibilityY), swipeArea, swipeDuration); return; } - int topVisibilityIndent = (int) (VISIBILITY_TOP_INDENT_COEFFICIENT * windowSizeHeight); + int topVisibilityIndent = (int) (VISIBILITY_TOP_INDENT_COEFFICIENT * swipeAreaSizeHeight); if (elementTopCoordinateY < topVisibilityIndent) { - touchActions.performVerticalSwipe(windowCenterY, - windowCenterY + topVisibilityIndent - elementTopCoordinateY, swipeDuration); + touchActions.performVerticalSwipe(swipeAreaCenterY, + swipeAreaCenterY + topVisibilityIndent - elementTopCoordinateY, swipeArea, swipeDuration); } } diff --git a/vividus-plugin-mobile-app/src/main/java/org/vividus/mobileapp/action/TouchActions.java b/vividus-plugin-mobile-app/src/main/java/org/vividus/mobileapp/action/TouchActions.java index f69dc775b7..5f37d20fce 100644 --- a/vividus-plugin-mobile-app/src/main/java/org/vividus/mobileapp/action/TouchActions.java +++ b/vividus-plugin-mobile-app/src/main/java/org/vividus/mobileapp/action/TouchActions.java @@ -29,6 +29,7 @@ import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebElement; import org.vividus.bdd.mobileapp.configuration.MobileApplicationConfiguration; @@ -131,11 +132,13 @@ private TouchAction buildTapAction(WebElement element, BiConsumerthe end of mobile scroll view is reached *
  • the swipe limit is exceeded
  • * - * @param direction direction to swipe, either UP or DOWN + * @param direction direction to swipe, either UP or DOWN * @param swipeDuration duration between a pointer moves from the start to the end of the swipe coordinates + * @param swipeArea the area to execute the swipe * @param stopCondition condition to stop swiping */ - public void swipeUntil(SwipeDirection direction, Duration swipeDuration, BooleanSupplier stopCondition) + public void swipeUntil(SwipeDirection direction, Duration swipeDuration, Rectangle swipeArea, + BooleanSupplier stopCondition) { /* * mobile:scroll @@ -156,8 +159,7 @@ public void swipeUntil(SwipeDirection direction, Duration swipeDuration, Boolean Duration stabilizationDuration = mobileApplicationConfiguration.getSwipeStabilizationDuration(); int swipeLimit = mobileApplicationConfiguration.getSwipeLimit(); BufferedImage previousFrame = null; - SwipeCoordinates swipeCoordinates = direction.calculateCoordinates(genericWebDriverManager.getSize(), - mobileApplicationConfiguration); + SwipeCoordinates swipeCoordinates = direction.calculateCoordinates(swipeArea, mobileApplicationConfiguration); for (int count = 0; count <= swipeLimit; count++) { swipe(swipeCoordinates, swipeDuration); @@ -185,14 +187,15 @@ public void swipeUntil(SwipeDirection direction, Duration swipeDuration, Boolean /** * Performs vertical swipe from startY to endY with swipeDuration * - * @param startY start Y coordinate - * @param endY end Y coordinate + * @param startY start Y coordinate + * @param endY end Y coordinate + * @param swipeArea the area to execute the swipe * @param swipeDuration swipe duration in ISO 8601 format */ - public void performVerticalSwipe(int startY, int endY, Duration swipeDuration) + public void performVerticalSwipe(int startY, int endY, Rectangle swipeArea, Duration swipeDuration) { - swipe(SwipeDirection.createCoordinates(startY, endY, genericWebDriverManager.getSize().getWidth(), - mobileApplicationConfiguration.getSwipeVerticalXPosition()), swipeDuration); + swipe(SwipeDirection.createCoordinates(startY, endY, swipeArea.getWidth(), + mobileApplicationConfiguration.getSwipeVerticalXPosition(), swipeArea.getPoint()), swipeDuration); } private BufferedImage takeScreenshot() diff --git a/vividus-plugin-mobile-app/src/test/java/io/appium/java_client/TouchActionsTests.java b/vividus-plugin-mobile-app/src/test/java/io/appium/java_client/TouchActionsTests.java index 89a78f0557..11b1666be0 100644 --- a/vividus-plugin-mobile-app/src/test/java/io/appium/java_client/TouchActionsTests.java +++ b/vividus-plugin-mobile-app/src/test/java/io/appium/java_client/TouchActionsTests.java @@ -48,6 +48,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; import org.openqa.selenium.remote.RemoteWebElement; import org.vividus.bdd.mobileapp.configuration.MobileApplicationConfiguration; import org.vividus.bdd.mobileapp.model.SwipeDirection; @@ -78,6 +79,7 @@ class TouchActionsTests private static final String WHITE_IMAGE = "white.png"; private static final String ELEMENT_ID = "elementId"; private static final Dimension DIMENSION = new Dimension(600, 800); + private static final Rectangle SWIPE_AREA = new Rectangle(new Point(0, 0), DIMENSION); @Spy private final MobileApplicationConfiguration mobileApplicationConfiguration = new MobileApplicationConfiguration(Duration.ZERO, 5, 50, 0); @@ -181,7 +183,7 @@ void shouldSwipeUntilConditionIsTrue() throws IOException when(screenshotTaker.takeViewportScreenshot()).thenReturn(getImage(BLACK_IMAGE)) .thenReturn(getImage(WHITE_IMAGE)); - touchActions.swipeUntil(SwipeDirection.UP, DURATION, stopCondition); + touchActions.swipeUntil(SwipeDirection.UP, DURATION, SWIPE_AREA, stopCondition); verifySwipe(3); verifyConfiguration(); @@ -200,7 +202,7 @@ void shouldNotExceedSwipeLimit() throws IOException .thenReturn(getImage(WHITE_IMAGE)); IllegalStateException exception = assertThrows(IllegalStateException.class, - () -> touchActions.swipeUntil(SwipeDirection.UP, DURATION, stopCondition)); + () -> touchActions.swipeUntil(SwipeDirection.UP, DURATION, SWIPE_AREA, stopCondition)); assertEquals("Swiping is stopped due to exceeded swipe limit '5'", exception.getMessage()); verifySwipe(6); @@ -217,7 +219,7 @@ void shouldStopSwipeOnceEndOfPageIsReached() throws IOException .thenReturn(getImage(BLACK_IMAGE)) .thenReturn(getImage(BLACK_IMAGE)); - touchActions.swipeUntil(SwipeDirection.UP, DURATION, stopCondition); + touchActions.swipeUntil(SwipeDirection.UP, DURATION, SWIPE_AREA, stopCondition); verifySwipe(4); verifyConfiguration(); @@ -233,7 +235,7 @@ void shouldWrapIOException() throws IOException doThrow(exception).when(screenshotTaker).takeViewportScreenshot(); UncheckedIOException wrapper = assertThrows(UncheckedIOException.class, - () -> touchActions.swipeUntil(SwipeDirection.UP, DURATION, stopCondition)); + () -> touchActions.swipeUntil(SwipeDirection.UP, DURATION, SWIPE_AREA, stopCondition)); assertEquals(exception, wrapper.getCause()); verifySwipe(1); @@ -243,8 +245,7 @@ void shouldWrapIOException() throws IOException @Test void shouldPerformVerticalSwipe() { - when(genericWebDriverManager.getSize()).thenReturn(DIMENSION); - touchActions.performVerticalSwipe(640, 160, DURATION); + touchActions.performVerticalSwipe(640, 160, SWIPE_AREA, DURATION); verifySwipe(1); } diff --git a/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/model/SwipeDirectionTests.java b/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/model/SwipeDirectionTests.java index 6cad146744..029e93c85a 100644 --- a/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/model/SwipeDirectionTests.java +++ b/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/model/SwipeDirectionTests.java @@ -24,40 +24,52 @@ import org.junit.jupiter.params.provider.CsvSource; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; import org.vividus.bdd.mobileapp.configuration.MobileApplicationConfiguration; class SwipeDirectionTests { @CsvSource({ - "UP, 1436, 358, 50, 540", - "DOWN, 358 , 1436, 0, 1", - "DOWN, 358 , 1436, 100, 1079" + "UP, 1436, 358, 0, 0, 50, 540", + "DOWN, 358 , 1436, 0, 0, 0, 1", + "DOWN, 358 , 1436, 0, 0, 100, 1079", + "UP, 1446, 368, 10, 10, 50, 550", + "DOWN, 368 , 1446, 10, 10, 0, 11", + "DOWN, 368 , 1446, 10, 10, 100, 1089" }) @ParameterizedTest - void shouldCalculateCoordinates(SwipeDirection direction, int fromY, int toY, int xPercentage, int x) + void shouldCalculateCoordinates(SwipeDirection direction, int fromY, int toY, int pointX, int pointY, + int xPercentage, int x) { Dimension dimension = new Dimension(1080, 1794); + Point point = new Point(pointX, pointY); + Rectangle swipeArea = new Rectangle(point, dimension); MobileApplicationConfiguration configuration = mock(MobileApplicationConfiguration.class); when(configuration.getSwipeVerticalXPosition()).thenReturn(xPercentage); - SwipeCoordinates coordinates = direction.calculateCoordinates(dimension, configuration); + SwipeCoordinates coordinates = direction.calculateCoordinates(swipeArea, configuration); assertPoint(coordinates.getStart(), x, fromY); assertPoint(coordinates.getEnd(), x, toY); } @CsvSource({ - "LEFT, 945, 135, 50, 897", - "RIGHT, 135 , 945, 0, 1", - "RIGHT, 135 , 945, 100, 1793" + "LEFT, 945, 135, 0, 0, 50, 897", + "RIGHT, 135 , 945, 0, 0, 0, 1", + "RIGHT, 135 , 945, 0, 0, 100, 1793", + "LEFT, 955, 145, 10, 10, 50, 907", + "RIGHT, 145 , 955, 10, 10, 0, 11", + "RIGHT, 145 , 955, 10, 10, 100, 1803" }) @ParameterizedTest - void shouldCalculateCoordinatesForHorizontalSwipe(SwipeDirection direction, int fromX, int toX, int yPercentage, - int y) + void shouldCalculateCoordinatesForHorizontalSwipe(SwipeDirection direction, int fromX, int toX, + int pointX, int pointY, int yPercentage, int y) { Dimension dimension = new Dimension(1080, 1794); + Point point = new Point(pointX, pointY); + Rectangle swipeArea = new Rectangle(point, dimension); MobileApplicationConfiguration configuration = mock(MobileApplicationConfiguration.class); when(configuration.getSwipeHorizontalYPosition()).thenReturn(yPercentage); - SwipeCoordinates coordinates = direction.calculateCoordinates(dimension, configuration); + SwipeCoordinates coordinates = direction.calculateCoordinates(swipeArea, configuration); assertPoint(coordinates.getStart(), fromX, y); assertPoint(coordinates.getEnd(), toX, y); diff --git a/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/steps/TouchStepsTests.java b/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/steps/TouchStepsTests.java index 5bfaf2a4f8..3e205ba73e 100644 --- a/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/steps/TouchStepsTests.java +++ b/vividus-plugin-mobile-app/src/test/java/org/vividus/bdd/mobileapp/steps/TouchStepsTests.java @@ -17,6 +17,7 @@ package org.vividus.bdd.mobileapp.steps; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -42,6 +43,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; import org.openqa.selenium.WebElement; import org.vividus.bdd.mobileapp.model.SwipeDirection; import org.vividus.bdd.steps.ComparisonRule; @@ -52,10 +54,13 @@ import org.vividus.ui.action.ISearchActions; import org.vividus.ui.action.search.Locator; import org.vividus.ui.action.search.SearchParameters; +import org.vividus.ui.context.IUiContext; @ExtendWith(MockitoExtension.class) class TouchStepsTests { + private static final Dimension DIMENSION = new Dimension(0, 1184); + private static final String ELEMENT_TO_TAP = "The element to tap"; @Mock private IBaseValidations baseValidations; @@ -64,6 +69,7 @@ class TouchStepsTests @Mock private Locator locator; @Mock private GenericWebDriverManager genericWebDriverManager; @Mock private IWebDriverProvider webDriverProvider; + @Mock private IUiContext uiContext; @InjectMocks private TouchSteps touchSteps; @AfterEach @@ -122,36 +128,74 @@ void shouldSwipeToElement(int elementY, int endY) .thenReturn(List.of(element)); doAnswer(a -> { - BooleanSupplier condition = a.getArgument(2, BooleanSupplier.class); + BooleanSupplier condition = a.getArgument(3, BooleanSupplier.class); condition.getAsBoolean(); condition.getAsBoolean(); return null; - }).when(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO), + }).when(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO), any(Rectangle.class), any(BooleanSupplier.class)); touchSteps.swipeToElement(SwipeDirection.UP, locator, Duration.ZERO); verifyNoMoreInteractions(parameters); - verify(touchActions).performVerticalSwipe(592, endY, Duration.ZERO); + verify(touchActions).performVerticalSwipe(eq(592), eq(endY), argThat(sa -> + DIMENSION.equals(sa.getDimension()) && sa.getPoint().equals(new Point(0, 0))), eq(Duration.ZERO)); + } + + @Test + void shouldSwipeToElementUsingContextElement() + { + WebElement element = mock(WebElement.class); + mockAssertElementsNumber(List.of(element), true); + when(element.getLocation()).thenReturn(new Point(-1, 138)); + WebElement searchContext = mock(WebElement.class); + Point point = new Point(10, 10); + Dimension contextDimension = new Dimension(1920, 1080); + when(searchContext.getRect()).thenReturn(new Rectangle(point, contextDimension)); + when(uiContext.getSearchContext()).thenReturn(searchContext); + + when(searchActions.findElements(locator)).thenReturn(new ArrayList<>()) + .thenReturn(List.of()) + .thenReturn(List.of(element)); + doAnswer(a -> + { + BooleanSupplier condition = a.getArgument(3, BooleanSupplier.class); + condition.getAsBoolean(); + condition.getAsBoolean(); + return null; + }).when(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO), argThat(sa -> + contextDimension.equals(sa.getDimension()) && sa.getPoint().equals(point)), + any(BooleanSupplier.class)); + SearchParameters parameters = initSwipeMocks(); + + touchSteps.swipeToElement(SwipeDirection.UP, locator, Duration.ZERO); + + verifyNoMoreInteractions(parameters); + verify(touchActions).performVerticalSwipe(eq(540), eq(564), argThat(sa -> + contextDimension.equals(sa.getDimension()) && sa.getPoint().equals(point)), eq(Duration.ZERO)); } @Test void shouldSwipeToElementToTryToFindItButThatDoesntExist() { + mockScreenSize(); mockAssertElementsNumber(List.of(), false); initSwipeMocks(); when(searchActions.findElements(locator)).thenReturn(List.of()); doAnswer(a -> { - BooleanSupplier condition = a.getArgument(2, BooleanSupplier.class); + BooleanSupplier condition = a.getArgument(3, BooleanSupplier.class); condition.getAsBoolean(); return null; - }).when(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO), - any(BooleanSupplier.class)); + }).when(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO), argThat(sa -> + DIMENSION.equals(sa.getDimension()) && sa.getPoint().equals(new Point(0, 0))), any(BooleanSupplier.class)); touchSteps.swipeToElement(SwipeDirection.UP, locator, Duration.ZERO); - verifyNoInteractions(genericWebDriverManager); + verify(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO), + argThat(sa -> DIMENSION.equals(sa.getDimension()) && sa.getPoint().equals(new Point(0, 0))), + any(BooleanSupplier.class)); + verifyNoMoreInteractions(touchActions); } @ParameterizedTest @@ -159,12 +203,11 @@ void shouldSwipeToElementToTryToFindItButThatDoesntExist() void shouldNotSwipeToElementIfItAlreadyExists(SwipeDirection swipeDireciton) { mockScreenSize(); - SearchParameters parameters = initSwipeMocks(); WebElement element = mock(WebElement.class); when(element.getLocation()).thenReturn(new Point(-1, 500)); mockAssertElementsNumber(List.of(element), true); - when(searchActions.findElements(locator)).thenReturn(List.of(element)); + SearchParameters parameters = initSwipeMocks(); touchSteps.swipeToElement(swipeDireciton, locator, Duration.ZERO); @@ -201,8 +244,6 @@ private void mockAssertElementsNumber(List elements, boolean result) private void mockScreenSize() { - Dimension dimension = mock(Dimension.class); - when(dimension.getHeight()).thenReturn(1184); - when(genericWebDriverManager.getSize()).thenReturn(dimension); + when(genericWebDriverManager.getSize()).thenReturn(DIMENSION); } } diff --git a/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/NativeHeaderAwareCoordsProviderTests.java b/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/NativeHeaderAwareCoordsProviderTests.java index 8facabc06d..1d1bd534f0 100644 --- a/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/NativeHeaderAwareCoordsProviderTests.java +++ b/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/NativeHeaderAwareCoordsProviderTests.java @@ -17,6 +17,7 @@ package org.vividus.selenium.mobileapp.screenshot; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -25,12 +26,13 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; import org.openqa.selenium.WebElement; import org.vividus.selenium.mobileapp.MobileAppWebDriverManager; -import org.vividus.ui.context.IUiContext; +import org.vividus.ui.context.UiContext; import ru.yandex.qatools.ashot.coordinates.Coords; @@ -39,7 +41,7 @@ class NativeHeaderAwareCoordsProviderTests { @Mock private MobileAppWebDriverManager driverManager; @Mock private WebElement webElement; - @Mock private IUiContext uiContext; + @Spy private UiContext uiContext; @InjectMocks private NativeHeaderAwareCoordsProvider coordsProvider; @@ -49,6 +51,7 @@ void shoudProvideAdjustedWithNativeHeaderHeightCoordinates() when(driverManager.getStatusBarSize()).thenReturn(100); when(webElement.getLocation()).thenReturn(new Point(0, 234)); when(webElement.getSize()).thenReturn(new Dimension(1, 1)); + doReturn(null).when(uiContext).getSearchContext(); Coords coords = coordsProvider.ofElement(null, webElement); Assertions.assertAll(() -> assertEquals(0, coords.getX()), () -> assertEquals(134, coords.getY()), @@ -64,7 +67,7 @@ void shouldAdjustElementCoordsToTheCurrentSearchContext() when(contextElement.getSize()).thenReturn(new Dimension(100, 50)); when(webElement.getLocation()).thenReturn(new Point(5, 15)); when(webElement.getSize()).thenReturn(new Dimension(150, 30)); - when(uiContext.getSearchContext()).thenReturn(contextElement); + doReturn(contextElement).when(uiContext).getSearchContext(); Coords coords = coordsProvider.ofElement(null, webElement); Assertions.assertAll(() -> assertEquals(0, coords.getX()), () -> assertEquals(5, coords.getY()), @@ -78,7 +81,7 @@ void shouldNotAdjustCoordsForTheCurrentSearchContext() WebElement contextElement = mock(WebElement.class); when(contextElement.getLocation()).thenReturn(new Point(10, 10)); when(contextElement.getSize()).thenReturn(new Dimension(100, 50)); - when(uiContext.getSearchContext()).thenReturn(contextElement); + doReturn(contextElement).when(uiContext).getSearchContext(); Coords coords = coordsProvider.ofElement(null, contextElement); Assertions.assertAll( () -> assertEquals(10, coords.getX()), diff --git a/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/android.table b/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/android.table index 1e269d4f85..714a9e9f0d 100644 --- a/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/android.table +++ b/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/android.table @@ -17,3 +17,4 @@ |action |COMPARE_AGAINST | |scrollViewXpath |//android.widget.ScrollView | |carouselViewXpath |//android.widget.TextView[@text='Carousel'] | +|swipeableAreaXpath |//android.widget.HorizontalScrollView | diff --git a/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/ios.table b/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/ios.table index 5b8af7ccea..a34e41a812 100644 --- a/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/ios.table +++ b/vividus-tests/src/main/resources/data/tables/system/mobile_app/locators/ios.table @@ -17,3 +17,4 @@ |action |COMPARE_AGAINST | |scrollViewXpath |//XCUIElementTypeScrollView | |carouselViewXpath |//XCUIElementTypeButton[@name='Carousel'] | +|swipeableAreaXpath |(//XCUIElementTypeScrollView)[2] | diff --git a/vividus-tests/src/main/resources/story/system/mobile_app/MobileAppStepsTests.story b/vividus-tests/src/main/resources/story/system/mobile_app/MobileAppStepsTests.story index 5224dd16c8..6d789ac04e 100644 --- a/vividus-tests/src/main/resources/story/system/mobile_app/MobileAppStepsTests.story +++ b/vividus-tests/src/main/resources/story/system/mobile_app/MobileAppStepsTests.story @@ -227,6 +227,13 @@ Then number of elements found by `accessibilityId()` When I swipe RIGHT to element located `accessibilityId()` with duration PT1S Then number of elements found by `accessibilityId()` is = `1` Then number of elements found by `accessibilityId()` is = `0` +When I change context to element located `xpath()` +When I swipe LEFT to element located `accessibilityId()` with duration PT1S +Then number of elements found by `accessibilityId()` is = `0` +Then number of elements found by `accessibilityId()` is = `1` +When I swipe RIGHT to element located `accessibilityId()` with duration PT1S +Then number of elements found by `accessibilityId()` is = `1` +Then number of elements found by `accessibilityId()` is = `0` Examples: |firstItemAccessibilityId|secondItemAccessibilityId|