diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index d599ee5e75..927834039a 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -242,8 +242,8 @@ jobs: if [[ -n $SAUCELABS_USER && -n $SAUCELABS_KEY ]]; then declare -a profiles=( ipad ) for profile in "${profiles[@]}"; do - ./gradlew :vividus-tests:debugStories -Pvividus.configuration.environments=system/saucelabs \ - -Pvividus.configuration.suites=grid \ + ./gradlew :vividus-tests:debugStories -Pvividus.configuration.environments=system/saucelabs/${profile} \ + -Pvividus.configuration.suites=system/${profile} \ -Pvividus.configuration.profiles=saucelabs/web,web/tablet/${profile} \ -Pvividus.selenium.grid.username=${SAUCELABS_USER} \ -Pvividus.selenium.grid.password=${SAUCELABS_KEY} diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/jackson/databind/ui/web/LocatorDeserializer.java b/vividus-extension-selenium/src/main/java/org/vividus/jackson/databind/ui/LocatorDeserializer.java similarity index 96% rename from vividus-plugin-web-app/src/main/java/org/vividus/jackson/databind/ui/web/LocatorDeserializer.java rename to vividus-extension-selenium/src/main/java/org/vividus/jackson/databind/ui/LocatorDeserializer.java index b96bfc168f..7bf1d1e232 100644 --- a/vividus-plugin-web-app/src/main/java/org/vividus/jackson/databind/ui/web/LocatorDeserializer.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/jackson/databind/ui/LocatorDeserializer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.vividus.jackson.databind.ui.web; +package org.vividus.jackson.databind.ui; import java.io.IOException; diff --git a/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAdjustingCoordsProvider.java b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAdjustingCoordsProvider.java deleted file mode 100644 index 1256d66097..0000000000 --- a/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAdjustingCoordsProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2019-2021 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.selenium.screenshot; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebElement; -import org.vividus.ui.context.IUiContext; - -import ru.yandex.qatools.ashot.coordinates.Coords; -import ru.yandex.qatools.ashot.coordinates.WebDriverCoordsProvider; - -public abstract class AbstractAdjustingCoordsProvider extends WebDriverCoordsProvider -{ - private static final long serialVersionUID = -7145089672020971479L; - private final transient IUiContext uiContext; - - protected AbstractAdjustingCoordsProvider(IUiContext uiContext) - { - this.uiContext = uiContext; - } - - protected Coords adjustToSearchContext(Coords coords) - { - SearchContext searchContext = uiContext.getSearchContext(); - if (searchContext instanceof WebElement) - { - Coords searchContextCoords = getCoords((WebElement) searchContext); - Coords intersected = coords.intersection(searchContextCoords); - intersected.x = intersected.x - searchContextCoords.x; - intersected.y = intersected.y - searchContextCoords.y; - return intersected; - } - return coords; - } - - protected abstract Coords getCoords(WebElement element); - - protected IUiContext getUiContext() - { - return uiContext; - } -} diff --git a/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAshotFactory.java b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAshotFactory.java index 60a024616c..2af9a38e2f 100644 --- a/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAshotFactory.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/AbstractAshotFactory.java @@ -19,6 +19,7 @@ import static ru.yandex.qatools.ashot.shooting.ShootingStrategies.cutting; import java.util.Map; +import java.util.Optional; import java.util.function.BiFunction; import javax.inject.Inject; @@ -27,6 +28,7 @@ import org.vividus.selenium.screenshot.strategies.ScreenshotShootingStrategy; import org.vividus.ui.screenshot.ScreenshotParameters; +import ru.yandex.qatools.ashot.shooting.ElementCroppingDecorator; import ru.yandex.qatools.ashot.shooting.ShootingStrategies; import ru.yandex.qatools.ashot.shooting.ShootingStrategy; import ru.yandex.qatools.ashot.shooting.cutter.CutStrategy; @@ -37,6 +39,13 @@ public abstract class AbstractAshotFactory imple private Map strategies; private String screenshotShootingStrategy; + private final ScreenshotCropper screenshotCropper; + + protected AbstractAshotFactory(ScreenshotCropper screenshotCropper) + { + this.screenshotCropper = screenshotCropper; + } + protected ShootingStrategy decorateWithFixedCutStrategy(ShootingStrategy original, int headerToCut, int footerToCut) { return decorateWithCutStrategy(original, headerToCut, footerToCut, FixedCutStrategy::new); @@ -50,6 +59,13 @@ protected ShootingStrategy decorateWithCutStrategy(ShootingStrategy original, in : original; } + protected ShootingStrategy decorateWithCropping(ShootingStrategy strategy, + Optional screenshotParameters) + { + return new ElementCroppingDecorator(strategy, screenshotCropper, + screenshotParameters.map(ScreenshotParameters::getIgnoreStrategies).orElse(Map.of())); + } + protected ScreenshotShootingStrategy getStrategyBy(String strategyName) { ScreenshotShootingStrategy strategy = strategies.get(strategyName); diff --git a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/IgnoreStrategy.java b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/IgnoreStrategy.java similarity index 96% rename from vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/IgnoreStrategy.java rename to vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/IgnoreStrategy.java index 0dbc1fc48e..628f77f6ef 100644 --- a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/IgnoreStrategy.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/IgnoreStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.vividus.visual.screenshot; +package org.vividus.selenium.screenshot; import java.awt.Color; import java.awt.Graphics2D; diff --git a/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/ScreenshotCropper.java b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/ScreenshotCropper.java new file mode 100644 index 0000000000..606e78cc59 --- /dev/null +++ b/vividus-extension-selenium/src/main/java/org/vividus/selenium/screenshot/ScreenshotCropper.java @@ -0,0 +1,98 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.selenium.screenshot; + +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.openqa.selenium.WebDriver; +import org.vividus.selenium.IWebDriverProvider; +import org.vividus.ui.action.ISearchActions; +import org.vividus.ui.action.search.Locator; + +import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; + +public class ScreenshotCropper +{ + private final ScreenshotDebugger screenshotDebugger; + private final ISearchActions searchActions; + private final CoordsProvider coordsProvider; + private final IWebDriverProvider webDriverProvider; + + public ScreenshotCropper(ScreenshotDebugger screenshotDebugger, ISearchActions searchActions, + CoordsProvider coordsProvider, IWebDriverProvider webDriverProvider) + { + this.screenshotDebugger = screenshotDebugger; + this.searchActions = searchActions; + this.coordsProvider = coordsProvider; + this.webDriverProvider = webDriverProvider; + } + + public BufferedImage crop(BufferedImage image, Optional contextCoords, + Map> ignoreStrategies, int topAdjustment) + { + BufferedImage outputImage = image; + WebDriver webDriver = webDriverProvider.get(); + + for (IgnoreStrategy strategy : List.of(IgnoreStrategy.ELEMENT, IgnoreStrategy.AREA)) + { + Set ignore = Optional.ofNullable(ignoreStrategies.get(strategy)).orElse(Set.of()).stream() + .map(searchActions::findElements) + .flatMap(Collection::stream) + .collect(Collectors.collectingAndThen( + Collectors.toList(), + webElementsToIgnore -> coordsProvider.ofElements(webDriver, webElementsToIgnore) + )); + if (!ignore.isEmpty()) + { + Point adjustment = calculateAdjustment(contextCoords, topAdjustment); + ignore.forEach(c -> + { + c.x += adjustment.x; + c.y += adjustment.y; + }); + + outputImage = strategy.crop(outputImage, ignore); + screenshotDebugger.debug(this.getClass(), "cropped_by_" + strategy, outputImage); + } + } + + return outputImage; + } + + protected Point calculateAdjustment(Optional contextCoords, int topAdjustment) + { + return new Point(0, -topAdjustment); + } + + protected CoordsProvider getCoordsProvider() + { + return coordsProvider; + } + + protected IWebDriverProvider getWebDriverProvider() + { + return webDriverProvider; + } +} diff --git a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactory.java b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactory.java index f18779ce7e..54fcbb1c63 100644 --- a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactory.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactory.java @@ -16,31 +16,41 @@ package org.vividus.ui.screenshot; +import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.BinaryOperator; -import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.Validate; +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; import org.vividus.util.property.PropertyMappedCollection; -public abstract class AbstractScreenshotParametersFactory - implements ScreenshotParametersFactory +public abstract class AbstractScreenshotParametersFactory implements ScreenshotParametersFactory { private PropertyMappedCollection screenshotConfigurations; private String shootingStrategy; + private Map> ignoreStrategies; + + protected Optional getDefaultConfiguration() + { + return screenshotConfigurations.getNullable(shootingStrategy); + } protected Optional getScreenshotConfiguration(Optional screenshotConfiguration, BinaryOperator merger) { - Optional defaultConfiguration = screenshotConfigurations.getNullable(shootingStrategy); + Optional defaultConfiguration = getDefaultConfiguration(); if (screenshotConfiguration.isEmpty()) { return defaultConfiguration; } - else if (defaultConfiguration.isPresent()) - { - return Optional.of(merger.apply(screenshotConfiguration.get(), defaultConfiguration.get())); - } - return screenshotConfiguration; + return defaultConfiguration.map(c -> merger.apply(screenshotConfiguration.get(), c)) + .or(() -> screenshotConfiguration); } protected int ensureValidCutSize(int value, String key) @@ -49,15 +59,46 @@ protected int ensureValidCutSize(int value, String key) return value; } - protected R createWithBaseConfiguration(ScreenshotConfiguration configuration, - Supplier parametersFactory) + protected P createWithBaseConfiguration(ScreenshotConfiguration configuration) { - R parameters = parametersFactory.get(); + Map> stepIgnores = Map.of( + IgnoreStrategy.ELEMENT, configuration.getElementsToIgnore(), + IgnoreStrategy.AREA, configuration.getAreasToIgnore() + ); + + return createWithBaseConfiguration(configuration, stepIgnores); + } + + protected P createWithBaseConfiguration(ScreenshotConfiguration configuration, + Map> stepIgnores) + { + P parameters = createScreenshotParameters(); parameters.setShootingStrategy(configuration.getShootingStrategy()); parameters.setNativeFooterToCut(ensureValidCutSize(configuration.getNativeFooterToCut(), "native footer")); + + Map> ignores = new EnumMap<>(IgnoreStrategy.class); + + for (Map.Entry> ignoreStrategy : ignoreStrategies.entrySet()) + { + IgnoreStrategy cropStrategy = ignoreStrategy.getKey(); + Set ignore = Stream.concat( + getLocatorsStream(ignoreStrategy.getValue()), + getLocatorsStream(stepIgnores.get(cropStrategy))) + .collect(Collectors.toSet()); + ignores.put(cropStrategy, ignore); + } + parameters.setIgnoreStrategies(ignores); + return parameters; } + protected abstract P createScreenshotParameters(); + + private Stream getLocatorsStream(Set locatorsSet) + { + return Optional.ofNullable(locatorsSet).stream().flatMap(Collection::stream); + } + public void setShootingStrategy(String shootingStrategy) { this.shootingStrategy = shootingStrategy; @@ -67,4 +108,9 @@ public void setScreenshotConfigurations(PropertyMappedCollection screenshotCo { this.screenshotConfigurations = screenshotConfigurations; } + + public void setIgnoreStrategies(Map> ignoreStrategies) + { + this.ignoreStrategies = ignoreStrategies; + } } diff --git a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotConfiguration.java b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotConfiguration.java index c1b19ccac2..81df471fd5 100644 --- a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotConfiguration.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotConfiguration.java @@ -17,11 +17,16 @@ package org.vividus.ui.screenshot; import java.util.Optional; +import java.util.Set; + +import org.vividus.ui.action.search.Locator; public class ScreenshotConfiguration { private int nativeFooterToCut; private Optional shootingStrategy = Optional.empty(); + private Set elementsToIgnore = Set.of(); + private Set areasToIgnore = Set.of(); public int getNativeFooterToCut() { @@ -42,4 +47,24 @@ public void setShootingStrategy(Optional shootingStrategy) { this.shootingStrategy = shootingStrategy; } + + public Set getElementsToIgnore() + { + return elementsToIgnore; + } + + public void setElementsToIgnore(Set elementsToIgnore) + { + this.elementsToIgnore = elementsToIgnore; + } + + public Set getAreasToIgnore() + { + return areasToIgnore; + } + + public void setAreasToIgnore(Set areasToIgnore) + { + this.areasToIgnore = areasToIgnore; + } } diff --git a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParameters.java b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParameters.java index 5bae2c0cf3..af5559cb73 100644 --- a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParameters.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParameters.java @@ -16,12 +16,18 @@ package org.vividus.ui.screenshot; +import java.util.Map; import java.util.Optional; +import java.util.Set; + +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; public class ScreenshotParameters { private int nativeFooterToCut; private Optional shootingStrategy = Optional.empty(); + private Map> ignoreStrategies; public int getNativeFooterToCut() { @@ -42,4 +48,14 @@ public void setShootingStrategy(Optional shootingStrategy) { this.shootingStrategy = shootingStrategy; } + + public Map> getIgnoreStrategies() + { + return ignoreStrategies; + } + + public void setIgnoreStrategies(Map> ignoreStrategies) + { + this.ignoreStrategies = ignoreStrategies; + } } diff --git a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParametersFactory.java b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParametersFactory.java index 2d864fba42..fd8e509247 100644 --- a/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParametersFactory.java +++ b/vividus-extension-selenium/src/main/java/org/vividus/ui/screenshot/ScreenshotParametersFactory.java @@ -16,9 +16,16 @@ package org.vividus.ui.screenshot; +import java.util.Map; import java.util.Optional; +import java.util.Set; + +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; public interface ScreenshotParametersFactory { Optional create(Optional screenshotConfiguration); + + Optional create(Map> ignores); } diff --git a/vividus-extension-selenium/src/main/java/ru/yandex/qatools/ashot/shooting/ElementCroppingDecorator.java b/vividus-extension-selenium/src/main/java/ru/yandex/qatools/ashot/shooting/ElementCroppingDecorator.java new file mode 100644 index 0000000000..972071b4f6 --- /dev/null +++ b/vividus-extension-selenium/src/main/java/ru/yandex/qatools/ashot/shooting/ElementCroppingDecorator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 ru.yandex.qatools.ashot.shooting; + +import java.awt.image.BufferedImage; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.openqa.selenium.WebDriver; +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.selenium.screenshot.ScreenshotCropper; +import org.vividus.ui.action.search.Locator; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import ru.yandex.qatools.ashot.coordinates.Coords; + +public class ElementCroppingDecorator extends ShootingDecorator +{ + private static final long serialVersionUID = 1088965678314008274L; + + private final transient ScreenshotCropper screenshotCropper; + @SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED") + private final transient Map> ignoreStrategies; + + public ElementCroppingDecorator(ShootingStrategy shootingStrategy, ScreenshotCropper screenshotCropper, + Map> ignoreStrategies) + { + super(shootingStrategy); + this.screenshotCropper = screenshotCropper; + this.ignoreStrategies = ignoreStrategies; + } + + @Override + public BufferedImage getScreenshot(WebDriver webDriver) + { + BufferedImage image = getShootingStrategy().getScreenshot(webDriver); + return screenshotCropper.crop(image, Optional.empty(), ignoreStrategies, 0); + } + + @Override + public BufferedImage getScreenshot(WebDriver webDriver, Set coords) + { + Coords originalCoords = coords.iterator().next(); + Coords contextCoords = new Coords(originalCoords); + int contextY = contextCoords.y; + BufferedImage image = getShootingStrategy().getScreenshot(webDriver, coords); + Set preparedCoords = prepareCoords(Set.of(contextCoords)); + return screenshotCropper.crop(image, Optional.of(originalCoords), ignoreStrategies, + contextY - preparedCoords.iterator().next().y); + } + + @Override + public Set prepareCoords(Set coordsSet) + { + return getShootingStrategy().prepareCoords(coordsSet); + } +} diff --git a/vividus-extension-selenium/src/main/resources/vividus-extension/spring.xml b/vividus-extension-selenium/src/main/resources/vividus-extension/spring.xml index 0824cb89ce..7abe9d5445 100644 --- a/vividus-extension-selenium/src/main/resources/vividus-extension/spring.xml +++ b/vividus-extension-selenium/src/main/resources/vividus-extension/spring.xml @@ -9,6 +9,7 @@ http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" default-lazy-init="true" profile="web,mobile_app"> + @@ -158,6 +159,15 @@ + + + + + + + + + diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/jackson/databind/ui/web/LocatorDeserializerTests.java b/vividus-extension-selenium/src/test/java/org/vividus/jackson/databind/ui/LocatorDeserializerTests.java similarity index 97% rename from vividus-plugin-web-app/src/test/java/org/vividus/jackson/databind/ui/web/LocatorDeserializerTests.java rename to vividus-extension-selenium/src/test/java/org/vividus/jackson/databind/ui/LocatorDeserializerTests.java index 7ca4298d06..dc9120e700 100644 --- a/vividus-plugin-web-app/src/test/java/org/vividus/jackson/databind/ui/web/LocatorDeserializerTests.java +++ b/vividus-extension-selenium/src/test/java/org/vividus/jackson/databind/ui/LocatorDeserializerTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.vividus.jackson.databind.ui.web; +package org.vividus.jackson.databind.ui; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; diff --git a/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAdjustingCoordsProviderTests.java b/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAdjustingCoordsProviderTests.java deleted file mode 100644 index caa397fb36..0000000000 --- a/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAdjustingCoordsProviderTests.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2019-2021 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.selenium.screenshot; - -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.function.Supplier; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.WebElement; -import org.vividus.ui.context.IUiContext; - -import ru.yandex.qatools.ashot.coordinates.Coords; - -@ExtendWith(MockitoExtension.class) -class AbstractAdjustingCoordsProviderTests -{ - @Mock private IUiContext uiContext; - - @Test - void shouldAdjustCoordsToTheCurrentSearchContext() - { - WebElement contextElement = mock(WebElement.class); - Coords webElementCoords = new Coords(5, 15, 150, 30); - Coords searchContextCoords = new Coords(10, 10, 100, 50); - when(uiContext.getSearchContext()).thenReturn(contextElement); - Coords coords = new TestCoordsProvider(uiContext, - () -> searchContextCoords).adjustToSearchContext(webElementCoords); - assertAll(() -> assertEquals(0, coords.getX()), - () -> assertEquals(5, coords.getY()), - () -> assertEquals(100, coords.getWidth()), - () -> assertEquals(30, coords.getHeight())); - } - - @Test - void shouldReturnAsIsIfTheContextIsNotSet() - { - Coords webElementCoords = new Coords(5, 15, 150, 30); - assertSame(webElementCoords, new TestCoordsProvider(uiContext, () -> - { - throw new IllegalStateException("will not run"); - }).adjustToSearchContext(webElementCoords)); - } - - @Test - void shouldExposeUIContext() - { - assertSame(uiContext, new TestCoordsProvider(uiContext, null).getUiContext()); - } - - private static final class TestCoordsProvider extends AbstractAdjustingCoordsProvider - { - private static final long serialVersionUID = 6120548730279509334L; - - private final transient Supplier coordsProvider; - - private TestCoordsProvider(IUiContext uiContext, Supplier coordsProvider) - { - super(uiContext); - this.coordsProvider = coordsProvider; - } - - @Override - protected Coords getCoords(WebElement element) - { - return coordsProvider.get(); - } - } -} diff --git a/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAshotFactoryTests.java b/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAshotFactoryTests.java index c3f0ae0623..9b32130b53 100644 --- a/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAshotFactoryTests.java +++ b/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/AbstractAshotFactoryTests.java @@ -28,20 +28,28 @@ import org.apache.commons.lang3.reflect.FieldUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import org.vividus.selenium.screenshot.strategies.ScreenshotShootingStrategy; import org.vividus.ui.screenshot.ScreenshotParameters; import ru.yandex.qatools.ashot.AShot; import ru.yandex.qatools.ashot.shooting.CuttingDecorator; +import ru.yandex.qatools.ashot.shooting.ElementCroppingDecorator; import ru.yandex.qatools.ashot.shooting.ShootingStrategies; import ru.yandex.qatools.ashot.shooting.ShootingStrategy; +@ExtendWith(MockitoExtension.class) class AbstractAshotFactoryTests { private static final String DEFAULT = "default"; - private final TestAshotFactory factory = new TestAshotFactory(); + + @Mock private ScreenshotCropper screenshotCropper; + @InjectMocks private TestAshotFactory factory; @Test void shouldProvideScalingBaseStrategy() throws IllegalAccessException @@ -93,11 +101,24 @@ void shouldDecorateWithCutting(int headerToCut, int footerToCut) instanceOf(CuttingDecorator.class)); } + @Test + void shouldDecorateWithCropping() + { + var strategy = mock(ShootingStrategy.class); + assertThat(factory.decorateWithCropping(strategy, Optional.empty()), + instanceOf(ElementCroppingDecorator.class)); + } + private static final class TestAshotFactory extends AbstractAshotFactory { private static final double DPR = 101d; private ScreenshotShootingStrategy strategy; + TestAshotFactory(ScreenshotCropper screenshotCropper) + { + super(screenshotCropper); + } + @Override public AShot create(Optional screenshotParameters) { diff --git a/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/ScreenshotCropperTests.java b/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/ScreenshotCropperTests.java new file mode 100644 index 0000000000..eb4b7c1160 --- /dev/null +++ b/vividus-extension-selenium/src/test/java/org/vividus/selenium/screenshot/ScreenshotCropperTests.java @@ -0,0 +1,138 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.selenium.screenshot; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.imageio.ImageIO; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.vividus.selenium.IWebDriverProvider; +import org.vividus.ui.action.ISearchActions; +import org.vividus.ui.action.search.Locator; +import org.vividus.util.ResourceUtils; + +import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; +import ru.yandex.qatools.ashot.util.ImageTool; + +@ExtendWith(MockitoExtension.class) +class ScreenshotCropperTests +{ + private static final String ORIGINAL = "original"; + + @Mock private Locator emptyLocator; + @Mock private Locator elementLocator; + @Mock private Locator areaLocator; + @Mock private WebDriver webDriver; + + @Mock private ScreenshotDebugger screenshotDebugger; + @Mock private ISearchActions searchActions; + @Mock private CoordsProvider coordsProvider; + @Mock private IWebDriverProvider webDriverProvider; + @InjectMocks private ScreenshotCropper cropper; + + @Test + void shouldCropElementsFromImage() throws IOException + { + when(webDriverProvider.get()).thenReturn(webDriver); + WebElement element = mock(WebElement.class); + when(searchActions.findElements(elementLocator)).thenReturn(List.of(element)); + when(searchActions.findElements(emptyLocator)).thenReturn(List.of()); + when(coordsProvider.ofElements(webDriver, List.of(element))).thenReturn(Set.of(new Coords(704, 89, 272, 201))); + WebElement area = mock(WebElement.class); + when(searchActions.findElements(areaLocator)).thenReturn(List.of(area)); + when(coordsProvider.ofElements(webDriver, List.of(area))).thenReturn(Set.of(new Coords(270, 311, 1139, 52))); + + BufferedImage originalImage = loadImage(ORIGINAL); + BufferedImage actual = cropper.crop(originalImage, Optional.empty(), Map.of( + IgnoreStrategy.ELEMENT, Set.of(elementLocator, emptyLocator), + IgnoreStrategy.AREA, Set.of(areaLocator) + ), 0); + + verifyScreenshot(actual); + } + + @Test + void shouldCropNothingIfNoElementsWereFound() throws IOException + { + when(webDriverProvider.get()).thenReturn(webDriver); + when(searchActions.findElements(emptyLocator)).thenReturn(List.of()); + + BufferedImage originalImage = loadImage(ORIGINAL); + BufferedImage actual = cropper.crop(originalImage, Optional.empty(), Map.of( + IgnoreStrategy.ELEMENT, Set.of(emptyLocator) + ), 0); + + assertThat(actual, ImageTool.equalImage(originalImage)); + } + + @Test + void shouldReturnCoordsProvider() + { + assertEquals(coordsProvider, cropper.getCoordsProvider()); + } + + @Test + void shouldReturnWebDriverProvider() + { + assertEquals(webDriverProvider, cropper.getWebDriverProvider()); + } + + private void verifyScreenshot(BufferedImage actual) throws IOException + { + BufferedImage afterCropping = loadImage("after_cropping"); + assertThat(actual, ImageTool.equalImage(afterCropping)); + verify(searchActions).findElements(emptyLocator); + verify(searchActions).findElements(elementLocator); + verify(searchActions).findElements(areaLocator); + BufferedImage elementCropped = loadImage("element_cropped"); + verify(screenshotDebugger).debug(eq(ScreenshotCropper.class), eq("cropped_by_ELEMENT"), + equalTo(elementCropped)); + verify(screenshotDebugger).debug(eq(ScreenshotCropper.class), eq("cropped_by_AREA"), + equalTo(afterCropping)); + } + + private BufferedImage loadImage(String fileName) throws IOException + { + return ImageIO.read(ResourceUtils.loadFile(ScreenshotCropperTests.class, fileName + ".png")); + } + + private BufferedImage equalTo(BufferedImage expected) + { + return argThat(actual -> ImageTool.equalImage(expected).matches(actual)); + } +} diff --git a/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactoryTests.java b/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactoryTests.java index 38fa7834f9..6190024fbe 100644 --- a/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactoryTests.java +++ b/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/AbstractScreenshotParametersFactoryTests.java @@ -23,10 +23,14 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.BinaryOperator; import org.junit.jupiter.api.Test; +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; import org.vividus.util.property.PropertyMappedCollection; class AbstractScreenshotParametersFactoryTests @@ -98,15 +102,31 @@ void shouldFailOnInvalidCutSize() @Test void shouldCreateConfigurationWithBaseParameters() { + Locator stepElementLocator = mock(Locator.class); + Locator stepAreaLocator = mock(Locator.class); + ScreenshotConfiguration parameters = new ScreenshotConfiguration(); + parameters.setElementsToIgnore(Set.of(stepElementLocator)); + parameters.setAreasToIgnore(Set.of(stepAreaLocator)); parameters.setShootingStrategy(Optional.of(DEFAULT)); parameters.setNativeFooterToCut(1); - ScreenshotParameters configuration = factory.createWithBaseConfiguration(parameters, - ScreenshotParameters::new); + Locator commonElementLocator = mock(Locator.class); + Locator commonAreaLocator = mock(Locator.class); + + factory.setIgnoreStrategies(Map.of( + IgnoreStrategy.ELEMENT, Set.of(commonElementLocator), + IgnoreStrategy.AREA, Set.of(commonAreaLocator) + )); + + ScreenshotParameters configuration = factory.createWithBaseConfiguration(parameters); assertEquals(Optional.of(DEFAULT), configuration.getShootingStrategy()); assertEquals(1, configuration.getNativeFooterToCut()); + assertEquals(Map.of( + IgnoreStrategy.ELEMENT, Set.of(stepElementLocator, commonElementLocator), + IgnoreStrategy.AREA, Set.of(stepAreaLocator, commonAreaLocator) + ), configuration.getIgnoreStrategies()); } private ScreenshotConfiguration createParametersWith(int nativeFooterToCut) @@ -117,12 +137,24 @@ private ScreenshotConfiguration createParametersWith(int nativeFooterToCut) } private static final class TestScreenshotParametersFactory - extends AbstractScreenshotParametersFactory + extends AbstractScreenshotParametersFactory { @Override public Optional create(Optional screenshotConfiguration) { return Optional.empty(); } + + @Override + public Optional create(Map> ignores) + { + return Optional.empty(); + } + + @Override + protected ScreenshotParameters createScreenshotParameters() + { + return new ScreenshotParameters(); + } } } diff --git a/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotConfigurationTests.java b/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotConfigurationTests.java new file mode 100644 index 0000000000..e8570b70ff --- /dev/null +++ b/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotConfigurationTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.ui.screenshot; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.vividus.ui.action.search.Locator; + +@ExtendWith(MockitoExtension.class) +class ScreenshotConfigurationTests +{ + @Mock private Locator locator; + + @Test + void shouldSetAndGetElementToIgnore() + { + ScreenshotConfiguration config = new ScreenshotConfiguration(); + assertEquals(Set.of(), config.getElementsToIgnore()); + config.setElementsToIgnore(Set.of(locator)); + assertEquals(Set.of(locator), config.getElementsToIgnore()); + } + + @Test + void shouldSetAndGetAreaToIgnore() + { + ScreenshotConfiguration config = new ScreenshotConfiguration(); + assertEquals(Set.of(), config.getAreasToIgnore()); + config.setAreasToIgnore(Set.of(locator)); + assertEquals(Set.of(locator), config.getAreasToIgnore()); + } +} diff --git a/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotParametersTests.java b/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotParametersTests.java index 0b6e79d79a..00f0627d3d 100644 --- a/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotParametersTests.java +++ b/vividus-extension-selenium/src/test/java/org/vividus/ui/screenshot/ScreenshotParametersTests.java @@ -17,11 +17,17 @@ package org.vividus.ui.screenshot; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.mock; +import java.util.Map; import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; class ScreenshotParametersTests { @@ -33,4 +39,14 @@ void shouldProvideDefalutValues() () -> assertEquals(Optional.empty(), screenshotParameters.getShootingStrategy())); } + + @Test + void shouldGetAndSetIgnoreStrategies() + { + ScreenshotParameters screenshotParameters = new ScreenshotParameters(); + assertNull(screenshotParameters.getIgnoreStrategies()); + Locator locator = mock(Locator.class); + screenshotParameters.setIgnoreStrategies(Map.of(IgnoreStrategy.ELEMENT, Set.of(locator))); + assertEquals(Map.of(IgnoreStrategy.ELEMENT, Set.of(locator)), screenshotParameters.getIgnoreStrategies()); + } } diff --git a/vividus-extension-selenium/src/test/java/ru/yandex/qatools/ashot/shooting/ElementCroppingDecoratorTests.java b/vividus-extension-selenium/src/test/java/ru/yandex/qatools/ashot/shooting/ElementCroppingDecoratorTests.java new file mode 100644 index 0000000000..ff18f066fe --- /dev/null +++ b/vividus-extension-selenium/src/test/java/ru/yandex/qatools/ashot/shooting/ElementCroppingDecoratorTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 ru.yandex.qatools.ashot.shooting; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +import java.awt.image.BufferedImage; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openqa.selenium.WebDriver; +import org.vividus.selenium.screenshot.ScreenshotCropper; + +import ru.yandex.qatools.ashot.coordinates.Coords; + +@ExtendWith(MockitoExtension.class) +class ElementCroppingDecoratorTests +{ + @Mock private ShootingStrategy shootingStrategy; + @Mock private BufferedImage image; + @Mock private WebDriver webDriver; + @Mock private ScreenshotCropper screenshotCropper; + + private ElementCroppingDecorator decorator; + + @BeforeEach + void init() + { + decorator = new ElementCroppingDecorator(shootingStrategy, screenshotCropper, Map.of()); + } + + @Test + void shouldGetScreenshot() + { + when(shootingStrategy.getScreenshot(webDriver)).thenReturn(image); + when(screenshotCropper.crop(image, Optional.empty(), Map.of(), 0)).thenReturn(image); + + BufferedImage result = decorator.getScreenshot(webDriver); + assertEquals(image, result); + } + + @Test + void shouldPrepareCoords() + { + Coords coords = new Coords(1, 1, 1, 1); + when(shootingStrategy.prepareCoords(Set.of(coords))).thenReturn(Set.of(coords)); + assertEquals(Set.of(coords), decorator.prepareCoords(Set.of(coords))); + } + + @Test + void shouldReturnImageOfContextElement() + { + Coords contextCoords = new Coords(16, 2331, 1888, 515); + Coords preparedCoords = new Coords(16, 206, 1888, 515); + + when(shootingStrategy.getScreenshot(webDriver, Set.of(contextCoords))).thenReturn(image); + when(shootingStrategy.prepareCoords(Set.of(contextCoords))).thenReturn(Set.of(preparedCoords)); + when(screenshotCropper.crop(image, Optional.of(contextCoords), Map.of(), 2125)).thenReturn(image); + + decorator = new ElementCroppingDecorator(shootingStrategy, screenshotCropper, Map.of()); + BufferedImage screenshot = decorator.getScreenshot(webDriver, Set.of(contextCoords)); + assertEquals(image, screenshot); + } +} diff --git a/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/after_cropping.png b/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/after_cropping.png new file mode 100644 index 0000000000..d839d5ca25 Binary files /dev/null and b/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/after_cropping.png differ diff --git a/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/element_cropped.png b/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/element_cropped.png new file mode 100644 index 0000000000..5baa4b4412 Binary files /dev/null and b/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/element_cropped.png differ diff --git a/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/original.png b/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/original.png new file mode 100644 index 0000000000..9c60e45dba Binary files /dev/null and b/vividus-extension-selenium/src/test/resources/org/vividus/selenium/screenshot/original.png differ diff --git a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/AbstractVisualCheckFactory.java b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/AbstractVisualCheckFactory.java deleted file mode 100644 index 5c2f7540b8..0000000000 --- a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/AbstractVisualCheckFactory.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.visual; - -import java.util.Map; -import java.util.Optional; - -import javax.inject.Inject; - -import org.vividus.ui.screenshot.ScreenshotConfiguration; -import org.vividus.ui.screenshot.ScreenshotParametersFactory; -import org.vividus.visual.model.AbstractVisualCheck; -import org.vividus.visual.screenshot.IScreenshotIndexer; - -public abstract class AbstractVisualCheckFactory -{ - private Map indexers; - private Optional screenshotIndexer; - - private final ScreenshotParametersFactory screenshotParametersFactory; - - protected AbstractVisualCheckFactory( - ScreenshotParametersFactory screenshotParametersFactory) - { - this.screenshotParametersFactory = screenshotParametersFactory; - } - - protected String createIndexedBaseline(String baselineName) - { - return screenshotIndexer.map(indexers::get) - .map(indexer -> indexer.index(baselineName)) - .orElse(baselineName); - } - - protected void withScreenshotConfiguration(T check, Optional configuration) - { - check.setScreenshotParameters(screenshotParametersFactory.create(configuration)); - } - - public void setScreenshotIndexer(Optional screenshotIndexer) - { - this.screenshotIndexer = screenshotIndexer; - } - - @Inject - public void setIndexers(Map indexers) - { - this.indexers = indexers; - } -} diff --git a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/model/AbstractVisualCheck.java b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/model/AbstractVisualCheck.java index a7fc1d2f2f..dbf76a62d8 100644 --- a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/model/AbstractVisualCheck.java +++ b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/model/AbstractVisualCheck.java @@ -16,20 +16,15 @@ package org.vividus.visual.model; -import java.util.Map; import java.util.Optional; -import java.util.Set; import org.openqa.selenium.SearchContext; -import org.vividus.ui.action.search.Locator; import org.vividus.ui.screenshot.ScreenshotParameters; -import org.vividus.visual.screenshot.IgnoreStrategy; public abstract class AbstractVisualCheck { private String baselineName; private VisualActionType action; - private Map> elementsToIgnore = Map.of(); private Optional screenshotParameters = Optional.empty(); private SearchContext searchContext; @@ -49,16 +44,6 @@ public String getBaselineName() return baselineName; } - public Map> getElementsToIgnore() - { - return elementsToIgnore; - } - - public void setElementsToIgnore(Map> elementsToIgnore) - { - this.elementsToIgnore = elementsToIgnore; - } - public VisualActionType getAction() { return action; diff --git a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/AshotScreenshotProvider.java b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/AshotScreenshotProvider.java deleted file mode 100644 index c72d8e74ce..0000000000 --- a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/AshotScreenshotProvider.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.visual.screenshot; - -import java.awt.image.BufferedImage; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.vividus.selenium.IWebDriverProvider; -import org.vividus.selenium.screenshot.AshotScreenshotTaker; -import org.vividus.selenium.screenshot.ScreenshotDebugger; -import org.vividus.ui.action.ISearchActions; -import org.vividus.ui.action.search.Locator; -import org.vividus.ui.screenshot.ScreenshotParameters; -import org.vividus.visual.model.AbstractVisualCheck; - -import ru.yandex.qatools.ashot.Screenshot; -import ru.yandex.qatools.ashot.coordinates.Coords; -import ru.yandex.qatools.ashot.coordinates.CoordsProvider; - -public class AshotScreenshotProvider implements ScreenshotProvider -{ - private final AshotScreenshotTaker ashotScreenshotTaker; - private final ISearchActions searchActions; - private final ScreenshotDebugger screenshotDebugger; - private final CoordsProvider coordsProvider; - private final IWebDriverProvider webDriverProvider; - - private Map> ignoreStrategies; - - @SuppressWarnings({"rawtypes", "unchecked"}) - public AshotScreenshotProvider(AshotScreenshotTaker ashotScreenshotTaker, - ISearchActions searchActions, ScreenshotDebugger screenshotDebugger, CoordsProvider coordsProvider, - IWebDriverProvider webDriverProvider) - { - this.ashotScreenshotTaker = ashotScreenshotTaker; - this.searchActions = searchActions; - this.screenshotDebugger = screenshotDebugger; - this.coordsProvider = coordsProvider; - this.webDriverProvider = webDriverProvider; - } - - @Override - public Screenshot take(AbstractVisualCheck visualCheck) - { - Screenshot screenshot = ashotScreenshotTaker.takeAshotScreenshot(visualCheck.getSearchContext(), - visualCheck.getScreenshotParameters()); - BufferedImage original = screenshot.getImage(); - Map> stepLevelElementsToIgnore = visualCheck.getElementsToIgnore(); - for (Map.Entry> strategy : ignoreStrategies.entrySet()) - { - IgnoreStrategy cropStrategy = strategy.getKey(); - Set ignore = Stream.concat( - getLocatorsStream(strategy.getValue()), - getLocatorsStream(stepLevelElementsToIgnore.get(cropStrategy))) - .distinct() - .map(searchActions::findElements) - .flatMap(Collection::stream) - .map(e -> coordsProvider.ofElement(webDriverProvider.get(), e)) - .collect(Collectors.toSet()); - if (ignore.isEmpty()) - { - continue; - } - original = cropStrategy.crop(original, ignore); - screenshotDebugger.debug(this.getClass(), "cropped_by_" + cropStrategy, original); - } - screenshot.setImage(original); - return screenshot; - } - - private Stream getLocatorsStream(Set locatorsSet) - { - return Optional.ofNullable(locatorsSet).stream().flatMap(Collection::stream); - } - - public void setIgnoreStrategies(Map> ignoreStrategies) - { - this.ignoreStrategies = ignoreStrategies; - } -} diff --git a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/ScreenshotProvider.java b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/BaselineIndexer.java similarity index 51% rename from vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/ScreenshotProvider.java rename to vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/BaselineIndexer.java index 7b842a0c3c..16dbce7738 100644 --- a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/ScreenshotProvider.java +++ b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/screenshot/BaselineIndexer.java @@ -16,11 +16,24 @@ package org.vividus.visual.screenshot; -import org.vividus.visual.model.AbstractVisualCheck; +import java.util.Map; +import java.util.Optional; -import ru.yandex.qatools.ashot.Screenshot; - -public interface ScreenshotProvider +public class BaselineIndexer { - Screenshot take(AbstractVisualCheck visualCheck); + private final Map indexers; + private final Optional screenshotIndexer; + + public BaselineIndexer(Map indexers, Optional screenshotIndexer) + { + this.indexers = indexers; + this.screenshotIndexer = screenshotIndexer; + } + + public String createIndexedBaseline(String baselineName) + { + return screenshotIndexer.map(indexers::get) + .map(indexer -> indexer.index(baselineName)) + .orElse(baselineName); + } } diff --git a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/steps/AbstractVisualSteps.java b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/steps/AbstractVisualSteps.java index afe0738dbe..f494ad5db0 100644 --- a/vividus-extension-visual-testing/src/main/java/org/vividus/visual/steps/AbstractVisualSteps.java +++ b/vividus-extension-visual-testing/src/main/java/org/vividus/visual/steps/AbstractVisualSteps.java @@ -17,12 +17,19 @@ package org.vividus.visual.steps; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.vividus.reporter.event.IAttachmentPublisher; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.softassert.ISoftAssert; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.context.IUiContext; +import org.vividus.ui.screenshot.ScreenshotConfiguration; import org.vividus.ui.screenshot.ScreenshotPrecondtionMismatchException; import org.vividus.visual.model.AbstractVisualCheck; import org.vividus.visual.model.VisualActionType; @@ -30,6 +37,8 @@ public abstract class AbstractVisualSteps { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractVisualSteps.class); + private final IUiContext uiContext; private final IAttachmentPublisher attachmentPublisher; private final ISoftAssert softAssert; @@ -42,9 +51,8 @@ protected AbstractVisualSteps(IUiContext uiContext, IAttachmentPublisher attachm this.softAssert = softAssert; } - protected void execute( - Function checkResultProvider, - Supplier visualCheckFactory, String templateName) + protected void execute(Supplier visualCheckFactory, + Function checkResultProvider, String templateName) { uiContext.getOptionalSearchContext().ifPresent(searchContext -> { @@ -74,6 +82,31 @@ protected void verifyResult(VisualCheckResult result) softAssert.assertTrue("Visual check passed", passed); } + protected void patchIgnores(String sourceKey, ScreenshotConfiguration screenshotConfiguration, + Map> ignores) + { + Set elementsToIgnore = getIgnoresFromOneOf(screenshotConfiguration.getElementsToIgnore(), sourceKey, + ignores.get(IgnoreStrategy.ELEMENT)); + screenshotConfiguration.setElementsToIgnore(elementsToIgnore); + + Set areasToIgnore = getIgnoresFromOneOf(screenshotConfiguration.getAreasToIgnore(), sourceKey, + ignores.get(IgnoreStrategy.AREA)); + screenshotConfiguration.setAreasToIgnore(areasToIgnore); + } + + private Set getIgnoresFromOneOf(Set configIgnores, String sourceKey, Set source) + { + if (!source.isEmpty()) + { + Validate.isTrue(configIgnores.isEmpty(), "The elements and areas to ignore must be passed " + + "either through screenshot configuration or %s", sourceKey); + LOGGER.atWarn().addArgument(sourceKey).log("The passing of elements and areas to ignore through {}" + + " is deprecated, please use screenshot configuration instead"); + return source; + } + return configIgnores; + } + protected ISoftAssert getSoftAssert() { return softAssert; diff --git a/vividus-extension-visual-testing/src/main/resources/vividus-extension/spring.xml b/vividus-extension-visual-testing/src/main/resources/vividus-extension/spring.xml index e9fb810833..2243c05a00 100644 --- a/vividus-extension-visual-testing/src/main/resources/vividus-extension/spring.xml +++ b/vividus-extension-visual-testing/src/main/resources/vividus-extension/spring.xml @@ -7,21 +7,11 @@ default-lazy-init="true"> - - - - - - - - - - - - + + + - diff --git a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/VisualCheckFactoryTests.java b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/VisualCheckFactoryTests.java deleted file mode 100644 index eb0c78f70b..0000000000 --- a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/VisualCheckFactoryTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.visual; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Map; -import java.util.Optional; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.vividus.ui.screenshot.ScreenshotConfiguration; -import org.vividus.ui.screenshot.ScreenshotParameters; -import org.vividus.ui.screenshot.ScreenshotParametersFactory; -import org.vividus.visual.model.AbstractVisualCheck; -import org.vividus.visual.screenshot.IScreenshotIndexer; - -@ExtendWith(MockitoExtension.class) -class VisualCheckFactoryTests -{ - private static final String BASELINE = "baseline"; - private static final String INDEXER = "indexer"; - - private @Mock ScreenshotParametersFactory screenshotParametersFactory; - - @InjectMocks - private VisualCheckFactory visualCheckFactory; - - @Test - void shouldReturnSameBaselineIfIndexerNameNotSet() - { - visualCheckFactory.setScreenshotIndexer(Optional.empty()); - visualCheckFactory.setIndexers(Map.of()); - assertEquals(BASELINE, visualCheckFactory.createIndexedBaseline(BASELINE)); - } - - @Test - void shouldReturnSameBaselineIfIndexerNameSetButItDoesntExist() - { - visualCheckFactory.setScreenshotIndexer(Optional.of(INDEXER)); - visualCheckFactory.setIndexers(Map.of()); - assertEquals(BASELINE, visualCheckFactory.createIndexedBaseline(BASELINE)); - } - - @Test - void shouldModifyBaselineName() - { - visualCheckFactory.setScreenshotIndexer(Optional.of(INDEXER)); - var indexer = mock(IScreenshotIndexer.class); - visualCheckFactory.setIndexers(Map.of(INDEXER, indexer)); - var indexedBaseline = "baseline-1"; - when(indexer.index(BASELINE)).thenReturn(indexedBaseline); - assertEquals(indexedBaseline, visualCheckFactory.createIndexedBaseline(BASELINE)); - } - - @Test - void shouldSetScreenshotConfiguration() - { - var visualCheck = mock(AbstractVisualCheck.class); - var parameters = Optional.of(mock(ScreenshotParameters.class)); - when(screenshotParametersFactory.create(Optional.empty())).thenReturn(parameters); - visualCheckFactory.withScreenshotConfiguration(visualCheck, Optional.empty()); - verify(visualCheck).setScreenshotParameters(parameters); - } - - private static final class VisualCheckFactory extends AbstractVisualCheckFactory - { - protected VisualCheckFactory(ScreenshotParametersFactory screenshotParametersFactory) - { - super(screenshotParametersFactory); - } - } -} diff --git a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/model/VisualCheckTests.java b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/model/VisualCheckTests.java index f56cced8f7..ba850118d6 100644 --- a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/model/VisualCheckTests.java +++ b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/model/VisualCheckTests.java @@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -import java.util.Map; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -31,7 +30,6 @@ class VisualCheckTests void shouldUseCorrectDefaultValues() { var visualCheck = new AbstractVisualCheck() { }; - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); assertEquals(Optional.empty(), visualCheck.getScreenshotParameters()); var parameters = Optional.of(mock(ScreenshotParameters.class)); visualCheck.setScreenshotParameters(parameters); diff --git a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/AshotScreenshotProviderTests.java b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/AshotScreenshotProviderTests.java deleted file mode 100644 index 9d84cc286d..0000000000 --- a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/AshotScreenshotProviderTests.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.visual.screenshot; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import javax.imageio.ImageIO; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InOrder; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.vividus.selenium.IWebDriverProvider; -import org.vividus.selenium.screenshot.AshotScreenshotTaker; -import org.vividus.selenium.screenshot.ScreenshotDebugger; -import org.vividus.ui.action.ISearchActions; -import org.vividus.ui.action.search.Locator; -import org.vividus.util.ResourceUtils; -import org.vividus.visual.model.AbstractVisualCheck; -import org.vividus.visual.model.VisualActionType; - -import ru.yandex.qatools.ashot.Screenshot; -import ru.yandex.qatools.ashot.coordinates.Coords; -import ru.yandex.qatools.ashot.coordinates.CoordsProvider; -import ru.yandex.qatools.ashot.util.ImageTool; - -@ExtendWith(MockitoExtension.class) -class AshotScreenshotProviderTests -{ - private static final String BASELINE = "baseline"; - - @Mock - private Locator aLocator; - @Mock - private Locator bLocator; - @Mock - private Locator elementLocator; - @Mock - private Locator areaLocator; - - @Mock - private AshotScreenshotTaker screenshotTaker; - @Mock(lenient = true) - private ISearchActions searchActions; - @Mock - private ScreenshotDebugger screenshotDebugger; - @Mock - private CoordsProvider coordsProvider; - @Mock - private IWebDriverProvider webDriverProvider; - - @InjectMocks - private AshotScreenshotProvider screenshotProvider; - - private static Map> createMap(IgnoreStrategy key1, - Set value1, IgnoreStrategy key2, Set value2) - { - Map> map = new LinkedHashMap<>(2); - map.put(key1, value1); - map.put(key2, value2); - return map; - } - - @Test - void shouldTakeScreenshot() - { - SearchContext searchContext = mock(SearchContext.class); - var visualCheck = mockSearchContext(searchContext); - Screenshot screenshot = mock(Screenshot.class); - when(searchActions.findElements(aLocator)).thenReturn(List.of()); - when(screenshotTaker.takeAshotScreenshot(searchContext, Optional.empty())).thenReturn(screenshot); - screenshotProvider.setIgnoreStrategies(Map.of(IgnoreStrategy.AREA, Set.of(aLocator))); - assertSame(screenshot, screenshotProvider.take(visualCheck)); - verifyNoInteractions(screenshotDebugger); - } - - private AbstractVisualCheck mockSearchContext(SearchContext searchContext) - { - var visualCheck = new AbstractVisualCheck(BASELINE, VisualActionType.ESTABLISH) { }; - visualCheck.setSearchContext(searchContext); - return visualCheck; - } - - @Test - void shouldTakeScreenshotAndProcessIgnoredElements() throws IOException - { - Map> strategies = createMap(IgnoreStrategy.ELEMENT, - Set.of(elementLocator, aLocator), IgnoreStrategy.AREA, Set.of(bLocator)); - Map> stepLevelStrategies = Map.of(IgnoreStrategy.ELEMENT, Set.of(aLocator), - IgnoreStrategy.AREA, Set.of(bLocator, areaLocator)); - - SearchContext searchContext = mock(SearchContext.class); - var visualCheck = mockSearchContext(searchContext); - visualCheck.setElementsToIgnore(stepLevelStrategies); - screenshotProvider.setIgnoreStrategies(strategies); - Screenshot screenshot = new Screenshot(loadImage("original")); - WebDriver driver = mock(WebDriver.class); - when(webDriverProvider.get()).thenReturn(driver); - WebElement element = mock(WebElement.class); - when(searchActions.findElements(elementLocator)).thenReturn(List.of(element)); - when(coordsProvider.ofElement(driver, element)).thenReturn(new Coords(704, 89, 272, 201)); - WebElement area = mock(WebElement.class); - when(searchActions.findElements(areaLocator)).thenReturn(List.of(area)); - when(coordsProvider.ofElement(driver, area)).thenReturn(new Coords(270, 311, 1139, 52)); - when(screenshotTaker.takeAshotScreenshot(searchContext, Optional.empty())).thenReturn(screenshot); - - Screenshot actual = screenshotProvider.take(visualCheck); - - verifyScreenshot(screenshot, actual); - } - - private void verifyScreenshot(Screenshot screenshot, Screenshot actual) throws IOException - { - assertSame(actual, screenshot); - BufferedImage afterCropping = loadImage("after_cropping"); - assertThat(actual.getImage(), ImageTool.equalImage(afterCropping)); - verify(searchActions).findElements(aLocator); - verify(searchActions).findElements(bLocator); - verify(searchActions).findElements(elementLocator); - verify(searchActions).findElements(areaLocator); - BufferedImage elementCropped = loadImage("element_cropped"); - InOrder ordered = Mockito.inOrder(screenshotDebugger); - ordered.verify(screenshotDebugger).debug(eq(AshotScreenshotProvider.class), eq("cropped_by_ELEMENT"), - equalTo(elementCropped)); - ordered.verify(screenshotDebugger).debug(eq(AshotScreenshotProvider.class), eq("cropped_by_AREA"), - equalTo(afterCropping)); - } - - private BufferedImage equalTo(BufferedImage expected) - { - return argThat(actual -> ImageTool.equalImage(expected).matches(actual)); - } - - private BufferedImage loadImage(String fileName) throws IOException - { - return ImageIO.read(ResourceUtils.loadFile(AshotScreenshotProviderTests.class, "/" + fileName + ".png")); - } -} diff --git a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/BaselineIndexerTests.java b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/BaselineIndexerTests.java new file mode 100644 index 0000000000..d5a23db438 --- /dev/null +++ b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/BaselineIndexerTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.visual.screenshot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class BaselineIndexerTests +{ + private static final String BASELINE = "baseline"; + private static final String INDEXER = "indexer"; + + private BaselineIndexer baselineIndexer; + + @Test + void shouldReturnSameBaselineIfIndexerNameNotSet() + { + baselineIndexer = new BaselineIndexer(Map.of(), Optional.of(INDEXER)); + assertEquals(BASELINE, baselineIndexer.createIndexedBaseline(BASELINE)); + } + + @Test + void shouldReturnSameBaselineIfIndexerNameSetButItDoesntExist() + { + baselineIndexer = new BaselineIndexer(Map.of(), Optional.empty()); + assertEquals(BASELINE, baselineIndexer.createIndexedBaseline(BASELINE)); + } + + @Test + void shouldModifyBaselineName() + { + var indexer = mock(IScreenshotIndexer.class); + baselineIndexer = new BaselineIndexer(Map.of(INDEXER, indexer), Optional.of(INDEXER)); + var indexedBaseline = "baseline-1"; + when(indexer.index(BASELINE)).thenReturn(indexedBaseline); + assertEquals(indexedBaseline, baselineIndexer.createIndexedBaseline(BASELINE)); + } +} diff --git a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/IgnoreStrategyTests.java b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/IgnoreStrategyTests.java index 04bc3f2bd2..fd5801cb4b 100644 --- a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/IgnoreStrategyTests.java +++ b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/screenshot/IgnoreStrategyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test; import org.mockito.InOrder; import org.mockito.Mockito; +import org.vividus.selenium.screenshot.IgnoreStrategy; import ru.yandex.qatools.ashot.coordinates.Coords; diff --git a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/steps/VisualStepsTests.java b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/steps/VisualStepsTests.java index a43304c9bb..ed391b34b8 100644 --- a/vividus-extension-visual-testing/src/test/java/org/vividus/visual/steps/VisualStepsTests.java +++ b/vividus-extension-visual-testing/src/test/java/org/vividus/visual/steps/VisualStepsTests.java @@ -16,46 +16,66 @@ package org.vividus.visual.steps; +import static com.github.valfirst.slf4jtest.LoggingEvent.warn; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; +import com.github.valfirst.slf4jtest.LoggingEvent; +import com.github.valfirst.slf4jtest.TestLogger; +import com.github.valfirst.slf4jtest.TestLoggerFactory; +import com.github.valfirst.slf4jtest.TestLoggerFactoryExtension; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.SearchContext; import org.vividus.reporter.event.IAttachmentPublisher; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.softassert.ISoftAssert; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.context.IUiContext; +import org.vividus.ui.screenshot.ScreenshotConfiguration; import org.vividus.ui.screenshot.ScreenshotPrecondtionMismatchException; import org.vividus.visual.model.AbstractVisualCheck; import org.vividus.visual.model.VisualActionType; import org.vividus.visual.model.VisualCheckResult; -@ExtendWith(MockitoExtension.class) +@ExtendWith({ MockitoExtension.class, TestLoggerFactoryExtension.class }) class VisualStepsTests { private static final String TEMPLATE = "template"; + private static final String SOURCE_KEY = "source-key"; + + private static final LoggingEvent WARNING_MESSAGE = warn("The passing of elements and areas to ignore through {}" + + " is deprecated, please use screenshot configuration instead", SOURCE_KEY); @Mock private IUiContext uiContext; @Mock private IAttachmentPublisher attachmentPublisher; @Mock private ISoftAssert softAssert; @InjectMocks private TestVisualSteps visualSteps; + private final TestLogger testLogger = TestLoggerFactory.getTestLogger(AbstractVisualSteps.class); + @SuppressWarnings("unchecked") @Test void shouldRecordAssertionWhenContextIsNull() @@ -63,19 +83,19 @@ void shouldRecordAssertionWhenContextIsNull() Function checkResultProvider = mock(Function.class); Supplier visualCheckFactory = mock(Supplier.class); when(uiContext.getOptionalSearchContext()).thenReturn(Optional.empty()); - visualSteps.execute(checkResultProvider, visualCheckFactory, TEMPLATE); + visualSteps.execute(visualCheckFactory, checkResultProvider, TEMPLATE); verifyNoInteractions(visualCheckFactory, checkResultProvider, attachmentPublisher); } @Test void shouldNotPublishAttachmentWhenResultIsNull() { - SearchContext searchContext = mock(SearchContext.class); - AbstractVisualCheck visualCheck = mock(AbstractVisualCheck.class); + var searchContext = mock(SearchContext.class); + var visualCheck = mock(AbstractVisualCheck.class); when(uiContext.getOptionalSearchContext()).thenReturn(Optional.of(searchContext)); - Function checkResultProvider = check -> null; - Supplier visualCheckFactory = () -> visualCheck; - visualSteps.execute(checkResultProvider, visualCheckFactory, TEMPLATE); + var checkResultProvider = (Function) check -> null; + var visualCheckFactory = (Supplier) () -> visualCheck; + visualSteps.execute(visualCheckFactory, checkResultProvider, TEMPLATE); verifyNoInteractions(attachmentPublisher); verify(visualCheck).setSearchContext(searchContext); } @@ -84,16 +104,16 @@ void shouldNotPublishAttachmentWhenResultIsNull() @CsvSource({"true, COMPARE_AGAINST", "false, CHECK_INEQUALITY_AGAINST"}) void shouldPublishAttachment(boolean passed, VisualActionType action) { - SearchContext searchContext = mock(SearchContext.class); - AbstractVisualCheck visualCheck = mock(AbstractVisualCheck.class); - VisualCheckResult visualCheckResult = mock(VisualCheckResult.class); + var searchContext = mock(SearchContext.class); + var visualCheck = mock(AbstractVisualCheck.class); + var visualCheckResult = mock(VisualCheckResult.class); when(visualCheckResult.getActionType()).thenReturn(action); when(uiContext.getOptionalSearchContext()).thenReturn(Optional.of(searchContext)); - Function checkResultProvider = check -> visualCheckResult; - Supplier visualCheckFactory = () -> visualCheck; + var checkResultProvider = (Function) check -> visualCheckResult; + var visualCheckFactory = (Supplier) () -> visualCheck; when(visualCheckResult.isPassed()).thenReturn(passed); - visualSteps.execute(checkResultProvider, visualCheckFactory, TEMPLATE); - InOrder ordered = Mockito.inOrder(attachmentPublisher, visualCheckResult, softAssert); + visualSteps.execute(visualCheckFactory, checkResultProvider, TEMPLATE); + var ordered = Mockito.inOrder(attachmentPublisher, visualCheckResult, softAssert); ordered.verify(attachmentPublisher).publishAttachment(TEMPLATE, Map.of("result", visualCheckResult), "Visual comparison"); ordered.verify(softAssert).assertTrue("Visual check passed", true); @@ -110,19 +130,66 @@ void shouldReturnsSoftAssert() @Test void shouldRecordInvalidVisualCheckPreconditionException() { - SearchContext searchContext = mock(SearchContext.class); - ScreenshotPrecondtionMismatchException exception = mock(ScreenshotPrecondtionMismatchException.class); + var searchContext = mock(SearchContext.class); + var exception = mock(ScreenshotPrecondtionMismatchException.class); Supplier visualCheckFactory = mock(Supplier.class); doThrow(exception).when(visualCheckFactory).get(); Function checkResultProvider = mock(Function.class); when(uiContext.getOptionalSearchContext()).thenReturn(Optional.of(searchContext)); - visualSteps.execute(checkResultProvider, visualCheckFactory, TEMPLATE); + visualSteps.execute(visualCheckFactory, checkResultProvider, TEMPLATE); verify(softAssert).recordFailedAssertion(exception); verifyNoInteractions(attachmentPublisher, checkResultProvider); } + @Test + void shouldFailIfBothSourcesAreNotEmpty() + { + var locator = mock(Locator.class); + var screenshotConfiguration = new ScreenshotConfiguration(); + screenshotConfiguration.setAreasToIgnore(Set.of(locator)); + screenshotConfiguration.setElementsToIgnore(Set.of(locator)); + Map> ignores = Map.of( + IgnoreStrategy.AREA, Set.of(locator), + IgnoreStrategy.ELEMENT, Set.of(locator) + ); + var thrown = assertThrows(IllegalArgumentException.class, + () -> visualSteps.patchIgnores(SOURCE_KEY, screenshotConfiguration, ignores)); + assertEquals("The elements and areas to ignore must be passed either through screenshot configuration or " + + SOURCE_KEY, thrown.getMessage()); + } + + @Test + void shouldNotPatchIgnores() + { + var locator = mock(Locator.class); + var screenshotConfiguration = new ScreenshotConfiguration(); + screenshotConfiguration.setAreasToIgnore(Set.of(locator)); + screenshotConfiguration.setElementsToIgnore(Set.of(locator)); + visualSteps.patchIgnores(SOURCE_KEY, screenshotConfiguration, Map.of( + IgnoreStrategy.AREA, Set.of(), + IgnoreStrategy.ELEMENT, Set.of() + )); + assertEquals(screenshotConfiguration.getElementsToIgnore(), Set.of(locator)); + assertEquals(screenshotConfiguration.getAreasToIgnore(), Set.of(locator)); + assertThat(testLogger.getLoggingEvents(), equalTo(List.of())); + } + + @Test + void shouldPatchIgnores() + { + var locator = mock(Locator.class); + var screenshotConfiguration = new ScreenshotConfiguration(); + visualSteps.patchIgnores(SOURCE_KEY, screenshotConfiguration, Map.of( + IgnoreStrategy.AREA, Set.of(locator), + IgnoreStrategy.ELEMENT, Set.of(locator) + )); + assertEquals(screenshotConfiguration.getElementsToIgnore(), Set.of(locator)); + assertEquals(screenshotConfiguration.getAreasToIgnore(), Set.of(locator)); + assertThat(testLogger.getLoggingEvents(), equalTo(List.of(WARNING_MESSAGE, WARNING_MESSAGE))); + } + private static final class TestVisualSteps extends AbstractVisualSteps { private TestVisualSteps(IUiContext uiContext, IAttachmentPublisher attachmentPublisher, ISoftAssert softAssert) diff --git a/vividus-plugin-applitools/build.gradle b/vividus-plugin-applitools/build.gradle index fada998c88..595b2f92fd 100644 --- a/vividus-plugin-applitools/build.gradle +++ b/vividus-plugin-applitools/build.gradle @@ -9,7 +9,6 @@ dependencies { implementation project(':vividus-soft-assert') implementation project(':vividus-util') - implementation(group: 'javax.inject', name: 'javax.inject', version: versions.javaxInject) implementation(group: 'com.applitools', name: 'eyes-images-java3', version: '3.213.0') implementation(group: 'org.slf4j', name: 'slf4j-api', version: versions.slf4j) diff --git a/vividus-plugin-applitools/src/main/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverter.java b/vividus-plugin-applitools/src/main/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverter.java index 78bc7ae9b8..3a6c64d812 100644 --- a/vividus-plugin-applitools/src/main/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverter.java +++ b/vividus-plugin-applitools/src/main/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,7 +47,6 @@ public List convertValue(ExamplesTable toConvert, Type ty checkNotNull(o.getAction(), "action"); }) .map(visualCheckFactory::unite) - .peek(ApplitoolsVisualCheck::buildIgnores) .collect(Collectors.toList()); } diff --git a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/VisualTestingSteps.java b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/VisualTestingSteps.java index eb41344ee3..d8f611381b 100644 --- a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/VisualTestingSteps.java +++ b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/VisualTestingSteps.java @@ -17,12 +17,16 @@ package org.vividus.visual.eyes; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Supplier; import org.jbehave.core.annotations.When; import org.vividus.reporter.event.IAttachmentPublisher; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.softassert.ISoftAssert; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.context.IUiContext; import org.vividus.ui.screenshot.ScreenshotConfiguration; import org.vividus.ui.screenshot.ScreenshotParameters; @@ -183,11 +187,27 @@ public void performCheck(List applitoolsConfigurations, .forEach(visualCheck -> runApplitoolsTest(visualCheck, Optional.of(screenshotConfiguration))); } - private void runApplitoolsTest(ApplitoolsVisualCheck visualCheck, Optional configuration) + private void runApplitoolsTest(ApplitoolsVisualCheck visualCheck, + Optional screenshotConfiguration) { runApplitoolsTest(() -> { - Optional screenshotParameters = screenshotParametersFactory.create(configuration); + Map> ignores = Map.of( + IgnoreStrategy.AREA, visualCheck.getAreasToIgnore(), + IgnoreStrategy.ELEMENT, visualCheck.getElementsToIgnore() + ); + + Optional screenshotParameters; + if (screenshotConfiguration.isPresent()) + { + patchIgnores("applitools configuration", screenshotConfiguration.get(), ignores); + screenshotParameters = screenshotParametersFactory.create(screenshotConfiguration); + } + else + { + screenshotParameters = screenshotParametersFactory.create(ignores); + } + visualCheck.setScreenshotParameters(screenshotParameters); return visualCheck; }); @@ -195,6 +215,6 @@ private void runApplitoolsTest(ApplitoolsVisualCheck visualCheck, Optional applitoolsVisualCheckSupplier) { - execute(visualTestingService::run, applitoolsVisualCheckSupplier, "applitools-visual-comparison.ftl"); + execute(applitoolsVisualCheckSupplier, visualTestingService::run, "applitools-visual-comparison.ftl"); } } diff --git a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactory.java b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactory.java index 2a39c5130f..d6a231c840 100644 --- a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactory.java +++ b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactory.java @@ -23,13 +23,18 @@ import com.applitools.eyes.MatchLevel; +import org.vividus.ui.screenshot.ScreenshotConfiguration; +import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.ui.screenshot.ScreenshotParametersFactory; -import org.vividus.visual.AbstractVisualCheckFactory; import org.vividus.visual.eyes.model.ApplitoolsVisualCheck; import org.vividus.visual.model.VisualActionType; +import org.vividus.visual.screenshot.BaselineIndexer; -public class ApplitoolsVisualCheckFactory extends AbstractVisualCheckFactory +public class ApplitoolsVisualCheckFactory { + private final ScreenshotParametersFactory screenshotParametersFactory; + private final BaselineIndexer baselineIndexer; + private String executeApiKey; private String readApiKey; private String hostApp; @@ -40,17 +45,21 @@ public class ApplitoolsVisualCheckFactory extends AbstractVisualCheckFactory screenshotParameters = screenshotParametersFactory.create(Optional.empty()); + + ApplitoolsVisualCheck check = new ApplitoolsVisualCheck(batchName, + baselineIndexer.createIndexedBaseline(baselineName), action); + check.setScreenshotParameters(screenshotParameters); check.setExecuteApiKey(executeApiKey); check.setReadApiKey(readApiKey); check.setBaselineEnvName(baselineEnvName); diff --git a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ImageEyesFactory.java b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ImageEyesFactory.java index e8d51f2943..3c6212e506 100644 --- a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ImageEyesFactory.java +++ b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/factory/ImageEyesFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.inject.Named; - import com.applitools.eyes.BatchInfo; import com.applitools.eyes.LogHandler; import com.applitools.eyes.RectangleSize; @@ -29,7 +27,6 @@ import org.vividus.visual.eyes.model.ApplitoolsVisualCheck; import org.vividus.visual.model.VisualActionType; -@Named public class ImageEyesFactory { private final LogHandler logHandler; diff --git a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheck.java b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheck.java index fde6985acc..0e7d8f3167 100644 --- a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheck.java +++ b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheck.java @@ -17,7 +17,6 @@ package org.vividus.visual.eyes.model; import java.net.URI; -import java.util.Map; import java.util.Set; import com.applitools.eyes.MatchLevel; @@ -25,7 +24,6 @@ import org.vividus.ui.action.search.Locator; import org.vividus.visual.model.AbstractVisualCheck; import org.vividus.visual.model.VisualActionType; -import org.vividus.visual.screenshot.IgnoreStrategy; public class ApplitoolsVisualCheck extends AbstractVisualCheck { @@ -53,11 +51,6 @@ public ApplitoolsVisualCheck(String batchName, String baselineName, VisualAction this.batchName = batchName; } - public void buildIgnores() - { - setElementsToIgnore(Map.of(IgnoreStrategy.AREA, areasToIgnore, IgnoreStrategy.ELEMENT, elementsToIgnore)); - } - public String getExecuteApiKey() { return executeApiKey; @@ -162,4 +155,14 @@ public void setAreasToIgnore(Set areasToIgnore) { this.areasToIgnore = areasToIgnore; } + + public Set getElementsToIgnore() + { + return elementsToIgnore; + } + + public Set getAreasToIgnore() + { + return areasToIgnore; + } } diff --git a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/service/ImageVisualTestingService.java b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/service/ImageVisualTestingService.java index af59bb402b..fe19b55cc1 100644 --- a/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/service/ImageVisualTestingService.java +++ b/vividus-plugin-applitools/src/main/java/org/vividus/visual/eyes/service/ImageVisualTestingService.java @@ -20,8 +20,6 @@ import java.net.URI; import java.util.Base64; -import javax.inject.Named; - import com.applitools.eyes.StepInfo; import com.applitools.eyes.StepInfo.ApiUrls; import com.applitools.eyes.TestResults; @@ -33,25 +31,27 @@ import org.slf4j.LoggerFactory; import org.vividus.http.client.HttpResponse; import org.vividus.http.client.IHttpClient; +import org.vividus.selenium.screenshot.AshotScreenshotTaker; +import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.visual.eyes.factory.ImageEyesFactory; import org.vividus.visual.eyes.model.ApplitoolsVisualCheck; import org.vividus.visual.eyes.model.ApplitoolsVisualCheckResult; -import org.vividus.visual.screenshot.ScreenshotProvider; -@Named +import ru.yandex.qatools.ashot.Screenshot; + public class ImageVisualTestingService implements VisualTestingService { private static final Logger LOGGER = LoggerFactory.getLogger(ImageVisualTestingService.class); private final ImageEyesFactory eyesFactory; - private final ScreenshotProvider screenshotProvider; + private final AshotScreenshotTaker ashotScreenshotTaker; private final IHttpClient httpClient; - public ImageVisualTestingService(ImageEyesFactory eyesFactory, ScreenshotProvider screenshotProvider, - @Named("eyesHttpClient") IHttpClient httpClient) + public ImageVisualTestingService(ImageEyesFactory eyesFactory, + AshotScreenshotTaker ashotScreenshotTaker, IHttpClient httpClient) { this.eyesFactory = eyesFactory; - this.screenshotProvider = screenshotProvider; + this.ashotScreenshotTaker = ashotScreenshotTaker; this.httpClient = httpClient; } @@ -63,7 +63,9 @@ public ApplitoolsVisualCheckResult run(ApplitoolsVisualCheck applitoolsVisualChe try { eyes.open(applitoolsVisualCheck.getAppName(), applitoolsVisualCheck.getBaselineName()); - eyes.checkImage(screenshotProvider.take(applitoolsVisualCheck).getImage()); + Screenshot screenshot = ashotScreenshotTaker.takeAshotScreenshot(applitoolsVisualCheck.getSearchContext(), + applitoolsVisualCheck.getScreenshotParameters()); + eyes.checkImage(screenshot.getImage()); } finally { diff --git a/vividus-plugin-applitools/src/main/resources/spring.xml b/vividus-plugin-applitools/src/main/resources/spring.xml index 048d49cc97..59450404c8 100644 --- a/vividus-plugin-applitools/src/main/resources/spring.xml +++ b/vividus-plugin-applitools/src/main/resources/spring.xml @@ -1,25 +1,20 @@ - - - - + + @@ -53,6 +48,14 @@ + + + + + + + + diff --git a/vividus-plugin-applitools/src/test/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverterTests.java b/vividus-plugin-applitools/src/test/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverterTests.java index aa52d79b6d..b1d9568b74 100644 --- a/vividus-plugin-applitools/src/test/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverterTests.java +++ b/vividus-plugin-applitools/src/test/java/org/vividus/converter/ExamplesTableToApplitoolsVisualChecksConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,7 +62,6 @@ void shouldConvertExamplesTableIntoApplitoolsVisualChecks() when(applitoolsVisualCheckFactory.unite(visualCheck)).thenReturn(visualCheck); assertEquals(checks, converter.convertValue(examplesTable, null)); verify(applitoolsVisualCheckFactory, times(2)).unite(visualCheck); - verify(visualCheck, times(2)).buildIgnores(); } private ExamplesTable mockExamplesTable(List checks) diff --git a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/VisualTestingStepsTests.java b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/VisualTestingStepsTests.java index 83fa72cbed..9f3632d2e0 100644 --- a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/VisualTestingStepsTests.java +++ b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/VisualTestingStepsTests.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -32,7 +33,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.SearchContext; import org.vividus.reporter.event.IAttachmentPublisher; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.softassert.ISoftAssert; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.context.IUiContext; import org.vividus.ui.screenshot.ScreenshotConfiguration; import org.vividus.ui.screenshot.ScreenshotParametersFactory; @@ -103,4 +106,22 @@ void shouldRunApplitoolsVisualCheckWithCustomConfiguration() verifyVisualCheck(result, 2); verify(check, times(2)).setScreenshotParameters(Optional.of(screenshotParameters)); } + + @Test + void shouldRunApplitoolsVisualCheckUsingApplitoolsConfiguration() + { + ApplitoolsVisualCheck check = mock(ApplitoolsVisualCheck.class); + ApplitoolsVisualCheckResult result = mock(ApplitoolsVisualCheckResult.class); + when(visualTestingService.run(check)).thenReturn(result); + WebScreenshotParameters screenshotParameters = mock(WebScreenshotParameters.class); + Locator locator = mock(Locator.class); + when(check.getElementsToIgnore()).thenReturn(Set.of(locator)); + when(check.getAreasToIgnore()).thenReturn(Set.of(locator)); + when(screenshotParametersFactory + .create(Map.of(IgnoreStrategy.AREA, Set.of(locator), IgnoreStrategy.ELEMENT, Set.of(locator)))) + .thenReturn(Optional.of(screenshotParameters)); + visualTestingSteps.performCheck(List.of(check)); + verifyVisualCheck(result, 1); + verify(check).setScreenshotParameters(Optional.of(screenshotParameters)); + } } diff --git a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactoryTests.java b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactoryTests.java index 954d5b8131..b833f1c0c6 100644 --- a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactoryTests.java +++ b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/factory/ApplitoolsVisualCheckFactoryTests.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.when; import java.net.URI; -import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; @@ -41,6 +40,7 @@ import org.vividus.ui.screenshot.ScreenshotParametersFactory; import org.vividus.visual.eyes.model.ApplitoolsVisualCheck; import org.vividus.visual.model.VisualActionType; +import org.vividus.visual.screenshot.BaselineIndexer; @ExtendWith(MockitoExtension.class) class ApplitoolsVisualCheckFactoryTests @@ -67,11 +67,9 @@ class ApplitoolsVisualCheckFactoryTests private static final String BASELINE_ENV_NAME = "baselineEnvName"; - @Mock - private ScreenshotParametersFactory screenshotParametersFactory; - - @InjectMocks - private ApplitoolsVisualCheckFactory factory; + @Mock private ScreenshotParametersFactory screenshotParametersFactory; + @Mock private BaselineIndexer baselineIndexer; + @InjectMocks private ApplitoolsVisualCheckFactory factory; @BeforeEach void setUp() @@ -84,13 +82,12 @@ void setUp() factory.setReadApiKey(READ_API_KEY); factory.setServerUri(SERVER_URI); factory.setViewportSize(VIEWPORT_SIZE); - factory.setScreenshotIndexer(Optional.empty()); - factory.setIndexers(Map.of()); } @Test void shouldCreateApplitoolsVisualCheckAndSetDefaultProperties() { + when(baselineIndexer.createIndexedBaseline(BASELINE)).thenReturn(BASELINE); var screenshotParameters = mock(ScreenshotParameters.class); when(screenshotParametersFactory.create(Optional.empty())).thenReturn(Optional.of(screenshotParameters)); var applitoolsVisualCheck = factory.create(BATCH_NAME, BASELINE, ACTION); diff --git a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheckTests.java b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheckTests.java index edff0b51ee..353ea05318 100644 --- a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheckTests.java +++ b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/model/ApplitoolsVisualCheckTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.Map; import java.util.Set; import org.junit.jupiter.api.Test; import org.vividus.ui.action.search.Locator; import org.vividus.ui.web.action.search.WebLocatorType; -import org.vividus.visual.screenshot.IgnoreStrategy; class ApplitoolsVisualCheckTests { @@ -33,20 +31,18 @@ class ApplitoolsVisualCheckTests @Test void shouldUseEmptySetsAsDefaultIgnores() { - visualCheck.buildIgnores(); - assertEquals(Map.of(IgnoreStrategy.AREA, Set.of(), IgnoreStrategy.ELEMENT, Set.of()), - visualCheck.getElementsToIgnore()); + assertEquals(Set.of(), visualCheck.getElementsToIgnore()); + assertEquals(Set.of(), visualCheck.getAreasToIgnore()); } @Test void shouldFillElementsToIgnoreWithValues() { - Set element = Set.of(new Locator(WebLocatorType.ID, "element")); - Set area = Set.of(new Locator(WebLocatorType.ID, "area")); - visualCheck.setElementsToIgnore(element); - visualCheck.setAreasToIgnore(area); - visualCheck.buildIgnores(); - assertEquals(Map.of(IgnoreStrategy.AREA, area, IgnoreStrategy.ELEMENT, element), - visualCheck.getElementsToIgnore()); + Set elements = Set.of(new Locator(WebLocatorType.ID, "element")); + Set areas = Set.of(new Locator(WebLocatorType.ID, "area")); + visualCheck.setElementsToIgnore(elements); + visualCheck.setAreasToIgnore(areas); + assertEquals(elements, visualCheck.getElementsToIgnore()); + assertEquals(areas, visualCheck.getAreasToIgnore()); } } diff --git a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/service/ImageVisualTestingServiceTests.java b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/service/ImageVisualTestingServiceTests.java index 5589b0121f..d8beb9424b 100644 --- a/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/service/ImageVisualTestingServiceTests.java +++ b/vividus-plugin-applitools/src/test/java/org/vividus/visual/eyes/service/ImageVisualTestingServiceTests.java @@ -53,11 +53,12 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.vividus.http.client.HttpResponse; import org.vividus.http.client.IHttpClient; +import org.vividus.selenium.screenshot.AshotScreenshotTaker; +import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.visual.eyes.factory.ImageEyesFactory; import org.vividus.visual.eyes.model.ApplitoolsVisualCheck; import org.vividus.visual.eyes.model.ApplitoolsVisualCheckResult; import org.vividus.visual.model.VisualActionType; -import org.vividus.visual.screenshot.ScreenshotProvider; import ru.yandex.qatools.ashot.Screenshot; @@ -85,11 +86,12 @@ class ImageVisualTestingServiceTests private static final String BATCH_NAME = "batchName"; private final ImageEyesFactory eyesFactory = mock(ImageEyesFactory.class); - private final ScreenshotProvider screenshotProvider = mock(ScreenshotProvider.class); + @SuppressWarnings("unchecked") + private final AshotScreenshotTaker ashotScreenshotTaker = mock(AshotScreenshotTaker.class); private final IHttpClient httpClient = mock(IHttpClient.class); @InjectMocks private final ImageVisualTestingService imageVisualTestingService - = new ImageVisualTestingService(eyesFactory, screenshotProvider, httpClient); + = new ImageVisualTestingService(eyesFactory, ashotScreenshotTaker, httpClient); @Test void shouldRunVisualTestAndPublishResults() throws IOException @@ -204,7 +206,8 @@ void shouldLogWarningWhenUrlUnauthorized() throws IOException private BufferedImage mockScreenshot(ApplitoolsVisualCheck applitoolsVisualCheck) { Screenshot screenshot = mock(Screenshot.class); - when(screenshotProvider.take(applitoolsVisualCheck)).thenReturn(screenshot); + when(ashotScreenshotTaker.takeAshotScreenshot(applitoolsVisualCheck.getSearchContext(), + applitoolsVisualCheck.getScreenshotParameters())).thenReturn(screenshot); BufferedImage image = mock(BufferedImage.class); when(screenshot.getImage()).thenReturn(image); return image; diff --git a/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactory.java b/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactory.java index 031ee8c774..16cca32fab 100644 --- a/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactory.java +++ b/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactory.java @@ -24,6 +24,7 @@ import org.vividus.selenium.mobileapp.MobileAppWebDriverManager; import org.vividus.selenium.mobileapp.screenshot.util.CoordsUtils; import org.vividus.selenium.screenshot.AbstractAshotFactory; +import org.vividus.selenium.screenshot.ScreenshotCropper; import org.vividus.ui.screenshot.ScreenshotParameters; import ru.yandex.qatools.ashot.AShot; @@ -36,8 +37,10 @@ public class MobileAppAshotFactory extends AbstractAshotFactory screenshotParameters) } int nativeFooterToCut = screenshotParameters.map(ScreenshotParameters::getNativeFooterToCut).orElse(0); strategy = decorateWithFixedCutStrategy(strategy, statusBarSize, nativeFooterToCut); + + strategy = decorateWithCropping(strategy, screenshotParameters); + return new AShot().shootingStrategy(strategy).coordsProvider(coordsProvider); } diff --git a/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProvider.java b/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProvider.java index 3a8af04302..13e686b44a 100644 --- a/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProvider.java +++ b/vividus-plugin-mobile-app/src/main/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProvider.java @@ -20,38 +20,58 @@ import org.openqa.selenium.WebElement; import org.vividus.selenium.mobileapp.MobileAppWebDriverManager; import org.vividus.selenium.mobileapp.screenshot.util.CoordsUtils; -import org.vividus.selenium.screenshot.AbstractAdjustingCoordsProvider; import org.vividus.ui.context.IUiContext; import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.WebDriverCoordsProvider; -public class MobileAppCoordsProvider extends AbstractAdjustingCoordsProvider +public class MobileAppCoordsProvider extends WebDriverCoordsProvider { private static final long serialVersionUID = 2966521618709606533L; private final transient MobileAppWebDriverManager mobileAppWebDriverManager; + private final transient IUiContext uiContext; private final boolean downscale; public MobileAppCoordsProvider(boolean downscale, MobileAppWebDriverManager mobileAppWebDriverManager, IUiContext uiContext) { - super(uiContext); this.mobileAppWebDriverManager = mobileAppWebDriverManager; + this.uiContext = uiContext; this.downscale = downscale; } @Override public Coords ofElement(WebDriver driver, WebElement element) { - Coords coords = getCoords(element); - coords = element.equals(getUiContext().getSearchContext()) ? coords : adjustToSearchContext(coords); - return downscale ? coords : adjustToDpr(coords); + Coords coords = super.ofElement(null, element); + Coords barSizeAdjustedCoords = cutBarSize(coords); + + if (downscale) + { + return barSizeAdjustedCoords; + } + + return uiContext.getOptionalSearchContext() + .filter(context -> !context.equals(element) && context instanceof WebElement) + .map(WebElement.class::cast) + .map(context -> super.ofElement(null, context)) + .map(contextCoords -> + { + Coords adjustedContext = adjustToDpr(cutBarSize(contextCoords)); + + coords.width = adjustToDpr(coords.width); + coords.height = adjustToDpr(coords.height); + coords.x = adjustedContext.x + adjustToDpr(coords.x - contextCoords.x); + coords.y = adjustedContext.y + adjustToDpr(coords.y - contextCoords.y); + + return coords; + }) + .orElseGet(() -> adjustToDpr(barSizeAdjustedCoords)); } - @Override - protected Coords getCoords(WebElement element) + private Coords cutBarSize(Coords coords) { - Coords coords = super.ofElement(null, element); return new Coords(coords.x, coords.y - mobileAppWebDriverManager.getStatusBarSize(), coords.width, coords.height); } @@ -61,4 +81,10 @@ private Coords adjustToDpr(Coords coords) double dpr = mobileAppWebDriverManager.getDpr(); return CoordsUtils.scale(coords, dpr); } + + private int adjustToDpr(int value) + { + double dpr = mobileAppWebDriverManager.getDpr(); + return CoordsUtils.scale(value, dpr); + } } diff --git a/vividus-plugin-mobile-app/src/main/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactory.java b/vividus-plugin-mobile-app/src/main/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactory.java index b4a26ab3bb..b4eddd5075 100644 --- a/vividus-plugin-mobile-app/src/main/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactory.java +++ b/vividus-plugin-mobile-app/src/main/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactory.java @@ -16,19 +16,43 @@ package org.vividus.ui.mobileapp.screenshot; +import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.function.BinaryOperator; +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.screenshot.AbstractScreenshotParametersFactory; import org.vividus.ui.screenshot.ScreenshotConfiguration; import org.vividus.ui.screenshot.ScreenshotParameters; public class MobileAppScreenshotParametersFactory - extends AbstractScreenshotParametersFactory + extends AbstractScreenshotParametersFactory { @Override public Optional create(Optional screenshotConfiguration) { - return getScreenshotConfiguration(screenshotConfiguration, (p, b) -> + return getScreenshotConfiguration(screenshotConfiguration, getConfigurationMerger()) + .map(this::createWithBaseConfiguration); + } + + @Override + public Optional create(Map> ignores) + { + ScreenshotConfiguration configuration = getDefaultConfiguration().orElseGet(ScreenshotConfiguration::new); + return Optional.of(createWithBaseConfiguration(configuration, ignores)); + } + + @Override + protected ScreenshotParameters createScreenshotParameters() + { + return new ScreenshotParameters(); + } + + private BinaryOperator getConfigurationMerger() + { + return (p, b) -> { if (p.getNativeFooterToCut() == 0) { @@ -39,6 +63,6 @@ public Optional create(Optional s p.setShootingStrategy(b.getShootingStrategy()); } return p; - }).map(config -> createWithBaseConfiguration(config, ScreenshotParameters::new)); + }; } } diff --git a/vividus-plugin-mobile-app/src/main/resources/spring.xml b/vividus-plugin-mobile-app/src/main/resources/spring.xml index 06d32ff012..d0983d6169 100644 --- a/vividus-plugin-mobile-app/src/main/resources/spring.xml +++ b/vividus-plugin-mobile-app/src/main/resources/spring.xml @@ -35,7 +35,7 @@ - + @@ -104,7 +104,10 @@ - + + + diff --git a/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactoryTests.java b/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactoryTests.java index b2d5f13d97..e057a95a6d 100644 --- a/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactoryTests.java +++ b/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppAshotFactoryTests.java @@ -39,6 +39,7 @@ import ru.yandex.qatools.ashot.AShot; import ru.yandex.qatools.ashot.coordinates.CoordsProvider; import ru.yandex.qatools.ashot.shooting.CuttingDecorator; +import ru.yandex.qatools.ashot.shooting.ElementCroppingDecorator; import ru.yandex.qatools.ashot.shooting.ShootingStrategy; import ru.yandex.qatools.ashot.shooting.cutter.CutStrategy; @@ -50,9 +51,12 @@ class MobileAppAshotFactoryTests private static final String DIMPLE = "dimple"; private static final String SIMPLE = "SIMPLE"; - @Mock private MobileAppWebDriverManager mobileAppWebDriverManager; - @Mock private CoordsProvider coordsProvider; - @InjectMocks private MobileAppAshotFactory ashotFactory; + @Mock + private MobileAppWebDriverManager mobileAppWebDriverManager; + @Mock + private CoordsProvider coordsProvider; + @InjectMocks + private MobileAppAshotFactory ashotFactory; @Test void shouldProvideDpr() @@ -63,16 +67,16 @@ void shouldProvideDpr() @SuppressWarnings("unchecked") @ParameterizedTest - @CsvSource({ - "true, 1, ru.yandex.qatools.ashot.shooting.ScalingDecorator", - "false, 2, ru.yandex.qatools.ashot.shooting.SimpleShootingStrategy" - }) + @CsvSource({ "true, 1, ru.yandex.qatools.ashot.shooting.ScalingDecorator", + "false, 2, ru.yandex.qatools.ashot.shooting.SimpleShootingStrategy" }) void shouldCreateAshotWithTheMergedConfiguration(boolean downscale, int headerToCut, Class strategyType) throws IllegalAccessException { mockAshotConfiguration(DIMPLE, downscale); AShot aShot = ashotFactory.create(createConfigurationWith(10, Optional.of(SIMPLE))); - CuttingDecorator strategy = (CuttingDecorator) FieldUtils.readField(aShot, SHOOTING_STRATEGY, true); + ElementCroppingDecorator croppingDecorator = (ElementCroppingDecorator) FieldUtils.readField(aShot, + SHOOTING_STRATEGY, true); + CuttingDecorator strategy = (CuttingDecorator) FieldUtils.readField(croppingDecorator, SHOOTING_STRATEGY, true); ShootingStrategy baseStrategy = (ShootingStrategy) FieldUtils.readField(strategy, SHOOTING_STRATEGY, true); CutStrategy cutStrategy = (CutStrategy) FieldUtils.readField(strategy, CUT_STRATEGY, true); assertEquals(strategyType, baseStrategy.getClass()); @@ -85,7 +89,8 @@ void shouldCreateAshotWithTheMergedConfiguration(boolean downscale, int headerTo private void mockAshotConfiguration(String defaultStrategy, boolean downscale) { ashotFactory.setDownscale(downscale); - ashotFactory.setStrategies(Map.of(SIMPLE, new SimpleScreenshotShootingStrategy(), DIMPLE, s -> { + ashotFactory.setStrategies(Map.of(SIMPLE, new SimpleScreenshotShootingStrategy(), DIMPLE, s -> + { throw new IllegalStateException(); })); when(mobileAppWebDriverManager.getDpr()).thenReturn(2d); diff --git a/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProviderTests.java b/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProviderTests.java index 2500b545bc..3a4abcb44e 100644 --- a/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProviderTests.java +++ b/vividus-plugin-mobile-app/src/test/java/org/vividus/selenium/mobileapp/screenshot/MobileAppCoordsProviderTests.java @@ -17,11 +17,11 @@ 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.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Assertions; @@ -31,14 +31,13 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; 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.WebDriver; import org.openqa.selenium.WebElement; import org.vividus.selenium.mobileapp.MobileAppWebDriverManager; -import org.vividus.ui.context.UiContext; +import org.vividus.ui.context.IUiContext; import ru.yandex.qatools.ashot.coordinates.Coords; @@ -49,8 +48,8 @@ class MobileAppCoordsProviderTests private static final Dimension DIMENSION = new Dimension(1, 1); @Mock private MobileAppWebDriverManager driverManager; + @Mock private IUiContext uiContext; @Mock private WebElement webElement; - @Spy private UiContext uiContext; @Test void shouldProvideAdjustedWithNativeHeaderHeightCoordinates() @@ -59,7 +58,6 @@ void shouldProvideAdjustedWithNativeHeaderHeightCoordinates() when(driverManager.getStatusBarSize()).thenReturn(100); when(webElement.getLocation()).thenReturn(new Point(0, 234)); when(webElement.getSize()).thenReturn(DIMENSION); - doReturn(null).when(uiContext).getSearchContext(); Coords coords = coordsProvider.ofElement(null, webElement); Assertions.assertAll(() -> assertEquals(0, coords.getX()), () -> assertEquals(134, coords.getY()), @@ -67,23 +65,6 @@ void shouldProvideAdjustedWithNativeHeaderHeightCoordinates() () -> assertEquals(1, coords.getHeight())); } - @Test - void shouldAdjustElementCoordsToTheCurrentSearchContext() - { - MobileAppCoordsProvider coordsProvider = new MobileAppCoordsProvider(true, driverManager, uiContext); - WebElement contextElement = mock(WebElement.class); - when(contextElement.getLocation()).thenReturn(POINT); - when(contextElement.getSize()).thenReturn(new Dimension(100, 50)); - when(webElement.getLocation()).thenReturn(new Point(5, 15)); - when(webElement.getSize()).thenReturn(new Dimension(150, 30)); - doReturn(contextElement).when(uiContext).getSearchContext(); - Coords coords = coordsProvider.ofElement(null, webElement); - Assertions.assertAll(() -> assertEquals(0, coords.getX()), - () -> assertEquals(5, coords.getY()), - () -> assertEquals(100, coords.getWidth()), - () -> assertEquals(30, coords.getHeight())); - } - @Test void shouldNotAdjustCoordsForTheCurrentSearchContext() { @@ -91,7 +72,6 @@ void shouldNotAdjustCoordsForTheCurrentSearchContext() WebElement contextElement = mock(WebElement.class); when(contextElement.getLocation()).thenReturn(POINT); when(contextElement.getSize()).thenReturn(new Dimension(100, 50)); - doReturn(contextElement).when(uiContext).getSearchContext(); Coords coords = coordsProvider.ofElement(null, contextElement); Assertions.assertAll( () -> assertEquals(10, coords.getX()), @@ -109,13 +89,72 @@ void testCoordsIsMultipliedWithDpr(boolean downscale, Coords expectedCoords) WebElement element = mock(WebElement.class); when(element.getLocation()).thenReturn(POINT); when(element.getSize()).thenReturn(DIMENSION); - doReturn(element).when(uiContext).getSearchContext(); lenient().when(driverManager.getDpr()).thenReturn(2.0); WebDriver driver = mock(WebDriver.class); assertEquals(expectedCoords, coordsDecorator.ofElement(driver, element)); } + @Test + void shouldScaleElementCoordsRelativelyToContextCoords() + { + WebElement contextElement = mock(WebElement.class); + mockCoords(contextElement, 0, 138, 768, 1046); + when(uiContext.getOptionalSearchContext()).thenReturn(Optional.of(contextElement)); + WebElement element = mock(WebElement.class); + mockCoords(element, 0, 215, 768, 78); + when(driverManager.getStatusBarSize()).thenReturn(48); + when(driverManager.getDpr()).thenReturn(1.0810810327529907d); + + MobileAppCoordsProvider coordsDecorator = new MobileAppCoordsProvider(false, driverManager, uiContext); + Coords coords = coordsDecorator.ofElement(null, element); + Assertions.assertAll( + () -> assertEquals(0, coords.getX()), + () -> assertEquals(182, coords.getY()), + () -> assertEquals(831, coords.getWidth()), + () -> assertEquals(85, coords.getHeight())); + } + + @Test + void shouldNotAdjustCoordsForTheWebDriverSearchContext() + { + MobileAppCoordsProvider coordsDecorator = new MobileAppCoordsProvider(false, driverManager, uiContext); + WebElement element = mock(WebElement.class); + when(element.getLocation()).thenReturn(POINT); + when(element.getSize()).thenReturn(DIMENSION); + lenient().when(driverManager.getDpr()).thenReturn(2.0); + WebDriver webDriver = mock(WebDriver.class); + when(uiContext.getOptionalSearchContext()).thenReturn(Optional.of(webDriver)); + + assertEquals(new Coords(20, 20, 2, 2), coordsDecorator.ofElement(webDriver, element)); + } + + @Test + void shouldNotAdjustCoordsIfElementIsSearchContextElement() + { + MobileAppCoordsProvider coordsDecorator = new MobileAppCoordsProvider(false, driverManager, uiContext); + WebElement element = mock(WebElement.class); + when(element.getLocation()).thenReturn(POINT); + when(element.getSize()).thenReturn(DIMENSION); + lenient().when(driverManager.getDpr()).thenReturn(2.0); + when(uiContext.getOptionalSearchContext()).thenReturn(Optional.of(element)); + + WebDriver driver = mock(WebDriver.class); + assertEquals(new Coords(20, 20, 2, 2), coordsDecorator.ofElement(driver, element)); + } + + private void mockCoords(WebElement element, int x, int y, int w, int h) + { + Point point = mock(Point.class); + when(element.getLocation()).thenReturn(point); + when(point.getX()).thenReturn(x); + when(point.getY()).thenReturn(y); + Dimension dimension = mock(Dimension.class); + when(element.getSize()).thenReturn(dimension); + when(dimension.getWidth()).thenReturn(w); + when(dimension.getHeight()).thenReturn(h); + } + static Stream coordsSource() { return Stream.of(Arguments.of(true, new Coords(10, 10, 1, 1)), diff --git a/vividus-plugin-mobile-app/src/test/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactoryTests.java b/vividus-plugin-mobile-app/src/test/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactoryTests.java index a56c75411a..c86c03ad5a 100644 --- a/vividus-plugin-mobile-app/src/test/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactoryTests.java +++ b/vividus-plugin-mobile-app/src/test/java/org/vividus/ui/mobileapp/screenshot/MobileAppScreenshotParametersFactoryTests.java @@ -19,17 +19,22 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.Mockito.mock; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; +import org.vividus.selenium.screenshot.IgnoreStrategy; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.screenshot.ScreenshotConfiguration; import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.util.property.PropertyMappedCollection; @@ -59,6 +64,7 @@ void shouldCreateScreenshotConfiguration(int defaultFooter, Optional def defaultConfiguration.setNativeFooterToCut(defaultFooter); defaultConfiguration.setShootingStrategy(defaultStrategy); factory.setShootingStrategy(SIMPLE); + factory.setIgnoreStrategies(Map.of()); factory.setScreenshotConfigurations(new PropertyMappedCollection<>(Map.of(SIMPLE, defaultConfiguration))); ScreenshotConfiguration parameters = new ScreenshotConfiguration(); @@ -70,4 +76,24 @@ void shouldCreateScreenshotConfiguration(int defaultFooter, Optional def assertEquals(Optional.of(SIMPLE), configuration.getShootingStrategy()); assertEquals(TEN, configuration.getNativeFooterToCut()); } + + @Test + void shouldCreateScreenshotConfigurationWithIgnores() + { + ScreenshotConfiguration defaultConfiguration = new ScreenshotConfiguration(); + factory.setShootingStrategy(SIMPLE); + factory.setIgnoreStrategies(Map.of(IgnoreStrategy.ELEMENT, Set.of(), IgnoreStrategy.AREA, Set.of())); + factory.setScreenshotConfigurations(new PropertyMappedCollection<>(Map.of(SIMPLE, defaultConfiguration))); + + Locator locator = mock(Locator.class); + Map> ignores = Map.of( + IgnoreStrategy.ELEMENT, Set.of(locator), + IgnoreStrategy.AREA, Set.of(locator) + ); + Optional createdConfiguration = factory.create(ignores); + assertTrue(createdConfiguration.isPresent()); + + ScreenshotParameters configuration = createdConfiguration.get(); + assertEquals(ignores, configuration.getIgnoreStrategies()); + } } diff --git a/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualCheckFactory.java b/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualCheckFactory.java deleted file mode 100644 index b857ac01b9..0000000000 --- a/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualCheckFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.visual; - -import java.util.Optional; -import java.util.function.BiFunction; - -import org.vividus.ui.screenshot.ScreenshotConfiguration; -import org.vividus.ui.screenshot.ScreenshotParametersFactory; -import org.vividus.visual.model.VisualActionType; -import org.vividus.visual.model.VisualCheck; - -public class VisualCheckFactory extends AbstractVisualCheckFactory -{ - public VisualCheckFactory(ScreenshotParametersFactory screenshotParametersFactory) - { - super(screenshotParametersFactory); - } - - public VisualCheck create(String baselineName, VisualActionType actionType) - { - return create(baselineName, actionType, Optional.empty()); - } - - public VisualCheck create(String baselineName, VisualActionType actionType, - BiFunction checkFactory) - { - String indexedBaselineName = createIndexedBaseline(baselineName); - VisualCheck check = checkFactory.apply(indexedBaselineName, actionType); - withScreenshotConfiguration(check, Optional.empty()); - return check; - } - - public VisualCheck create(String baselineName, VisualActionType actionType, - Optional parameters) - { - String indexedBaselineName = createIndexedBaseline(baselineName); - VisualCheck check = new VisualCheck(indexedBaselineName, actionType); - withScreenshotConfiguration(check, parameters); - return check; - } -} diff --git a/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualSteps.java b/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualSteps.java index 12d78c4e92..bb144dc74a 100644 --- a/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualSteps.java +++ b/vividus-plugin-visual/src/main/java/org/vividus/visual/VisualSteps.java @@ -22,6 +22,7 @@ import java.util.Optional; import java.util.OptionalDouble; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -29,20 +30,25 @@ import com.google.gson.reflect.TypeToken; +import org.apache.commons.lang3.Validate; import org.jbehave.core.annotations.When; import org.jbehave.core.model.ExamplesTable; +import org.jbehave.core.steps.ConvertedParameters; import org.jbehave.core.steps.Parameters; import org.vividus.reporter.event.IAttachmentPublisher; import org.vividus.resource.ResourceLoadException; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.softassert.ISoftAssert; import org.vividus.ui.action.search.Locator; import org.vividus.ui.context.IUiContext; import org.vividus.ui.screenshot.ScreenshotConfiguration; +import org.vividus.ui.screenshot.ScreenshotParameters; +import org.vividus.ui.screenshot.ScreenshotParametersFactory; import org.vividus.visual.engine.IVisualTestingEngine; import org.vividus.visual.model.VisualActionType; import org.vividus.visual.model.VisualCheck; import org.vividus.visual.model.VisualCheckResult; -import org.vividus.visual.screenshot.IgnoreStrategy; +import org.vividus.visual.screenshot.BaselineIndexer; import org.vividus.visual.steps.AbstractVisualSteps; public class VisualSteps extends AbstractVisualSteps @@ -53,14 +59,18 @@ public class VisualSteps extends AbstractVisualSteps private static final String REQUIRED_DIFF_PERCENTAGE_COLUMN_NAME = "REQUIRED_DIFF_PERCENTAGE"; private final IVisualTestingEngine visualTestingEngine; - private final VisualCheckFactory visualCheckFactory; + private final ScreenshotParametersFactory screenshotParametersFactory; + private final BaselineIndexer baselineIndexer; public VisualSteps(IUiContext uiContext, IAttachmentPublisher attachmentPublisher, - IVisualTestingEngine visualTestingEngine, ISoftAssert softAssert, VisualCheckFactory visualCheckFactory) + IVisualTestingEngine visualTestingEngine, ISoftAssert softAssert, + ScreenshotParametersFactory screenshotParametersFactory, + BaselineIndexer baselineIndexer) { super(uiContext, attachmentPublisher, softAssert); this.visualTestingEngine = visualTestingEngine; - this.visualCheckFactory = visualCheckFactory; + this.screenshotParametersFactory = screenshotParametersFactory; + this.baselineIndexer = baselineIndexer; } /** @@ -72,7 +82,7 @@ public VisualSteps(IUiContext uiContext, IAttachmentPublisher attachmentPublishe @When("I $actionType baseline with name `$name`") public void runVisualTests(VisualActionType actionType, String name) { - performVisualAction(() -> visualCheckFactory.create(name, actionType)); + performVisualAction(name, actionType, Optional.empty(), Optional.empty()); } /** @@ -85,16 +95,7 @@ public void runVisualTests(VisualActionType actionType, String name) @When(value = "I $actionType baseline with name `$name` using repository `$repository`", priority = 1) public void runVisualTests(VisualActionType actionType, String name, String repository) { - performVisualAction(withRepository(() -> visualCheckFactory.create(name, actionType), repository)); - } - - private Supplier withRepository(Supplier visualCheckProvider, String repository) - { - return () -> { - VisualCheck visualCheck = visualCheckProvider.get(); - visualCheck.setBaselineRepository(Optional.of(repository)); - return visualCheck; - }; + performVisualAction(name, actionType, Optional.of(repository), Optional.empty()); } /** @@ -111,7 +112,7 @@ private Supplier withRepository(Supplier visualCheckPr public void runVisualTests(VisualActionType actionType, String name, ScreenshotConfiguration screenshotConfiguration) { - performVisualAction(() -> visualCheckFactory.create(name, actionType, Optional.of(screenshotConfiguration))); + performVisualAction(name, actionType, Optional.empty(), Optional.of(screenshotConfiguration)); } /** @@ -130,25 +131,7 @@ public void runVisualTests(VisualActionType actionType, String name, public void runVisualTests(VisualActionType actionType, String name, String repository, ScreenshotConfiguration screenshotConfiguration) { - performVisualAction(withRepository(() -> visualCheckFactory.create(name, actionType, - Optional.of(screenshotConfiguration)), repository)); - } - - private void performVisualAction(Supplier visualCheckFactory) - { - execute(check -> { - try - { - return check.getAction() == VisualActionType.ESTABLISH - ? visualTestingEngine.establish(check) - : visualTestingEngine.compareAgainst(check); - } - catch (IOException | ResourceLoadException e) - { - getSoftAssert().recordFailedAssertion(e); - } - return null; - }, visualCheckFactory, "visual-comparison.ftl"); + performVisualAction(name, actionType, Optional.of(repository), Optional.of(screenshotConfiguration)); } /** @@ -164,7 +147,7 @@ private void performVisualAction(Supplier visualCheckFactory) @When("I $actionType baseline with name `$name` ignoring:$checkSettings") public void runVisualTests(VisualActionType actionType, String name, ExamplesTable checkSettings) { - runVisualTests(() -> visualCheckFactory.create(name, actionType), checkSettings); + performVisualAction(checkSettings, name, actionType, Optional.empty(), Optional.empty()); } /** @@ -183,7 +166,7 @@ public void runVisualTests(VisualActionType actionType, String name, ExamplesTab priority = 1) public void runVisualTests(VisualActionType actionType, String name, String repository, ExamplesTable checkSettings) { - runVisualTests(withRepository(() -> visualCheckFactory.create(name, actionType), repository), checkSettings); + performVisualAction(checkSettings, name, actionType, Optional.of(repository), Optional.empty()); } /** @@ -206,8 +189,7 @@ public void runVisualTests(VisualActionType actionType, String name, String repo public void runVisualTests(VisualActionType actionType, String name, ExamplesTable checkSettings, ScreenshotConfiguration screenshotConfiguration) { - runVisualTests(() -> visualCheckFactory.create(name, actionType, Optional.of(screenshotConfiguration)), - checkSettings); + performVisualAction(checkSettings, name, actionType, Optional.empty(), Optional.of(screenshotConfiguration)); } /** @@ -231,55 +213,95 @@ public void runVisualTests(VisualActionType actionType, String name, ExamplesTab public void runVisualTests(VisualActionType actionType, String name, String repository, ExamplesTable checkSettings, ScreenshotConfiguration screenshotConfiguration) { - runVisualTests( - withRepository(() -> visualCheckFactory.create(name, actionType, Optional.of(screenshotConfiguration)), - repository), checkSettings); + performVisualAction(checkSettings, name, actionType, Optional.of(repository), + Optional.of(screenshotConfiguration)); } - private void runVisualTests(Supplier visualCheckFactory, ExamplesTable checkSettings) + private void performVisualAction(ExamplesTable checkSettingsTable, String baselineName, VisualActionType actionType, + Optional baselineRepository, Optional screenshotConfiguration) { - int rowsSize = checkSettings.getRows().size(); - if (rowsSize != 1) - { - throw new IllegalArgumentException("Only one row of locators to ignore supported, actual: " - + rowsSize); - } - Parameters rowAsParameters = checkSettings.getRowAsParameters(0); - Map> toIgnore = Stream.of(IgnoreStrategy.values()) - .collect(Collectors.toMap(Function.identity(), - s -> getLocatorsSet(rowAsParameters, s))); + int rowsSize = checkSettingsTable.getRows().size(); + Validate.isTrue(rowsSize == 1, "Only one row of locators to ignore supported, actual: %s", rowsSize); + Parameters checkSettings = checkSettingsTable.getRowAsParameters(0); + + performVisualAction(baselineName, actionType, baselineRepository, screenshotConfiguration, checkSettings); + } + + private void performVisualAction(String baselineName, VisualActionType actionType, + Optional baselineRepository, Optional screenshotConfiguration) + { + performVisualAction(baselineName, actionType, baselineRepository, screenshotConfiguration, + new ConvertedParameters(Map.of(), null)); + } + + private void performVisualAction(String baselineName, VisualActionType actionType, + Optional baselineRepository, Optional screenshotConfiguration, + Parameters checkSettings) + { + Supplier visualCheckFactory = () -> { + Map> ignores = getIgnores(checkSettings); - performVisualAction(() -> { - VisualCheck visualCheck = visualCheckFactory.get(); - visualCheck.setElementsToIgnore(toIgnore); - setDiffPercentage(visualCheck, rowAsParameters); + Optional screenshotParameters; + if (screenshotConfiguration.isPresent()) + { + patchIgnores("ignores table", screenshotConfiguration.get(), ignores); + screenshotParameters = screenshotParametersFactory.create(screenshotConfiguration); + } + else + { + screenshotParameters = screenshotParametersFactory.create(ignores); + } + String indexedBaselineName = baselineIndexer.createIndexedBaseline(baselineName); + + VisualCheck visualCheck = new VisualCheck(indexedBaselineName, actionType); + visualCheck.setScreenshotParameters(screenshotParameters); + visualCheck.setBaselineRepository(baselineRepository); + setDiffPercentage(visualCheck, checkSettings); return visualCheck; - }); + }; + Function checkResultProvider = check -> { + try + { + return check.getAction() == VisualActionType.ESTABLISH + ? visualTestingEngine.establish(check) + : visualTestingEngine.compareAgainst(check); + } + catch (IOException | ResourceLoadException e) + { + getSoftAssert().recordFailedAssertion(e); + } + return null; + }; + execute(visualCheckFactory, checkResultProvider, "visual-comparison.ftl"); + } + + private Map> getIgnores(Parameters checkParameters) + { + return Stream.of(IgnoreStrategy.values()).collect(Collectors.toMap(Function.identity(), + s -> checkParameters.valueAs(s.name(), SET_BY, Set.of()))); } private void setDiffPercentage(VisualCheck visualCheck, Parameters rowAsParameters) { if (visualCheck.getAction() == VisualActionType.CHECK_INEQUALITY_AGAINST) { - visualCheck.setRequiredDiffPercentage(getParameter(rowAsParameters, REQUIRED_DIFF_PERCENTAGE_COLUMN_NAME)); + configureThresholdIfPresent(rowAsParameters, REQUIRED_DIFF_PERCENTAGE_COLUMN_NAME, + visualCheck::setRequiredDiffPercentage); } else { - visualCheck.setAcceptableDiffPercentage(getParameter(rowAsParameters, - ACCEPTABLE_DIFF_PERCENTAGE_COLUMN_NAME)); + configureThresholdIfPresent(rowAsParameters, ACCEPTABLE_DIFF_PERCENTAGE_COLUMN_NAME, + visualCheck::setAcceptableDiffPercentage); } } - private OptionalDouble getParameter(Parameters rowAsParameters, String paramterName) - { - return rowAsParameters.values().containsKey(paramterName) - ? OptionalDouble.of(rowAsParameters.valueAs(paramterName, Double.TYPE)) - : OptionalDouble.empty(); - } - - private Set getLocatorsSet(Parameters rowAsParameters, IgnoreStrategy s) + private void configureThresholdIfPresent(Parameters rowAsParameters, String parameterName, + Consumer thresholdSetter) { - return rowAsParameters.valueAs(s.name(), SET_BY, Set.of()); + if (rowAsParameters.values().containsKey(parameterName)) + { + thresholdSetter.accept(OptionalDouble.of(rowAsParameters.valueAs(parameterName, Double.TYPE))); + } } @Override diff --git a/vividus-plugin-visual/src/main/java/org/vividus/visual/engine/VisualTestingEngine.java b/vividus-plugin-visual/src/main/java/org/vividus/visual/engine/VisualTestingEngine.java index b0f0848d3d..46a81dfff3 100644 --- a/vividus-plugin-visual/src/main/java/org/vividus/visual/engine/VisualTestingEngine.java +++ b/vividus-plugin-visual/src/main/java/org/vividus/visual/engine/VisualTestingEngine.java @@ -26,10 +26,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.vividus.selenium.screenshot.AshotScreenshotTaker; +import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.visual.model.VisualActionType; import org.vividus.visual.model.VisualCheck; import org.vividus.visual.model.VisualCheckResult; -import org.vividus.visual.screenshot.ScreenshotProvider; import ru.yandex.qatools.ashot.Screenshot; import ru.yandex.qatools.ashot.comparison.ImageDiff; @@ -42,7 +43,7 @@ public class VisualTestingEngine implements IVisualTestingEngine private static final int ONE_HUNDRED = 100; private static final int SCALE = 3; - private final ScreenshotProvider screenshotProvider; + private final AshotScreenshotTaker ashotScreenshotTaker; private final DiffMarkupPolicyFactory diffMarkupPolicyFactory; private final Map baselineRepositories; @@ -51,10 +52,10 @@ public class VisualTestingEngine implements IVisualTestingEngine private boolean overrideBaselines; private String baselineRepository; - public VisualTestingEngine(ScreenshotProvider screenshotProvider, DiffMarkupPolicyFactory diffMarkupPolicyFactory, - Map baselineRepositories) + public VisualTestingEngine(AshotScreenshotTaker ashotScreenshotTaker, + DiffMarkupPolicyFactory diffMarkupPolicyFactory, Map baselineRepositories) { - this.screenshotProvider = screenshotProvider; + this.ashotScreenshotTaker = ashotScreenshotTaker; this.diffMarkupPolicyFactory = diffMarkupPolicyFactory; this.baselineRepositories = baselineRepositories; } @@ -71,7 +72,8 @@ public VisualCheckResult establish(VisualCheck visualCheck) throws IOException private Screenshot getCheckpointScreenshot(VisualCheck visualCheck) { - return screenshotProvider.take(visualCheck); + return ashotScreenshotTaker.takeAshotScreenshot(visualCheck.getSearchContext(), + visualCheck.getScreenshotParameters()); } @Override diff --git a/vividus-plugin-visual/src/main/resources/spring.xml b/vividus-plugin-visual/src/main/resources/spring.xml index c44e8b1581..724597d84b 100644 --- a/vividus-plugin-visual/src/main/resources/spring.xml +++ b/vividus-plugin-visual/src/main/resources/spring.xml @@ -6,9 +6,12 @@ http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" default-lazy-init="true" profile="web,mobile_app"> - + + + + diff --git a/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualCheckFactoryTests.java b/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualCheckFactoryTests.java deleted file mode 100644 index 3f60cb29c4..0000000000 --- a/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualCheckFactoryTests.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed 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 - * - * https://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 org.vividus.visual; - -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Map; -import java.util.Optional; -import java.util.OptionalDouble; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.vividus.ui.screenshot.ScreenshotConfiguration; -import org.vividus.ui.screenshot.ScreenshotParameters; -import org.vividus.ui.screenshot.ScreenshotParametersFactory; -import org.vividus.visual.model.VisualActionType; -import org.vividus.visual.model.VisualCheck; -import org.vividus.visual.screenshot.IScreenshotIndexer; - -@ExtendWith(MockitoExtension.class) -class VisualCheckFactoryTests -{ - private static final String NAME = "name"; - private static final String INDEXED_NAME = NAME + " [0]"; - - @Mock private ScreenshotParametersFactory screenshotParametersFactory; - @InjectMocks private VisualCheckFactory visualCheckFactory; - - @Test - void shouldCreateVisualCheckWithoutIndexedBaseline() - { - visualCheckFactory.setScreenshotIndexer(Optional.empty()); - visualCheckFactory.setIndexers(Map.of()); - VisualCheck check = visualCheckFactory.create(NAME, VisualActionType.COMPARE_AGAINST); - assertAll( - () -> assertEquals(NAME, check.getBaselineName()), - () -> assertEquals(VisualActionType.COMPARE_AGAINST, check.getAction()), - () -> assertEquals(OptionalDouble.empty(), check.getAcceptableDiffPercentage()), - () -> assertEquals(Map.of(), check.getElementsToIgnore()), - () -> assertEquals(Optional.empty(), check.getScreenshotParameters())); - } - - @Test - void shouldCreateVisualCheckFromInputFactoryWithIndexedBaseline() - { - mockIndexer(); - VisualCheck check = visualCheckFactory.create(NAME, VisualActionType.COMPARE_AGAINST, VisualCheck::new); - assertAll( - () -> assertEquals(INDEXED_NAME, check.getBaselineName()), - () -> assertEquals(VisualActionType.COMPARE_AGAINST, check.getAction()) - ); - } - - @Test - void shouldCreateVisualCheckWithIndexedBaseline() - { - mockIndexer(); - VisualCheck check = visualCheckFactory.create(NAME, VisualActionType.COMPARE_AGAINST); - assertAll( - () -> assertEquals(INDEXED_NAME, check.getBaselineName()), - () -> assertEquals(VisualActionType.COMPARE_AGAINST, check.getAction()), - () -> assertEquals(OptionalDouble.empty(), check.getAcceptableDiffPercentage()), - () -> assertEquals(Map.of(), check.getElementsToIgnore()), - () -> assertEquals(Optional.empty(), check.getScreenshotParameters())); - } - - private void mockIndexer() - { - visualCheckFactory.setScreenshotIndexer(Optional.of(NAME)); - IScreenshotIndexer indexer = mock(IScreenshotIndexer.class); - visualCheckFactory.setIndexers(Map.of(NAME, indexer)); - when(indexer.index(NAME)).thenReturn(INDEXED_NAME); - } - - @Test - void shouldCreateVisualCheckWithScreenshotConfiguration() - { - visualCheckFactory.setScreenshotIndexer(Optional.empty()); - visualCheckFactory.setIndexers(Map.of()); - ScreenshotConfiguration screenshotConfiguration = mock(ScreenshotConfiguration.class); - ScreenshotParameters screenshotParameters = mock(ScreenshotParameters.class); - when(screenshotParametersFactory.create(Optional.of(screenshotConfiguration))) - .thenReturn(Optional.of(screenshotParameters)); - VisualCheck check = visualCheckFactory.create(NAME, VisualActionType.COMPARE_AGAINST, - Optional.of(screenshotConfiguration)); - assertAll( - () -> assertEquals(NAME, check.getBaselineName()), - () -> assertEquals(VisualActionType.COMPARE_AGAINST, check.getAction()), - () -> assertEquals(OptionalDouble.empty(), check.getAcceptableDiffPercentage()), - () -> assertEquals(Map.of(), check.getElementsToIgnore()), - () -> assertEquals(Optional.of(screenshotParameters), check.getScreenshotParameters())); - } -} diff --git a/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualStepsTests.java b/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualStepsTests.java index 060ef3c849..810ec8ffc3 100644 --- a/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualStepsTests.java +++ b/vividus-plugin-visual/src/test/java/org/vividus/visual/VisualStepsTests.java @@ -49,23 +49,27 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.SearchContext; import org.vividus.reporter.event.IAttachmentPublisher; import org.vividus.resource.ResourceLoadException; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.softassert.ISoftAssert; import org.vividus.ui.action.search.Locator; import org.vividus.ui.context.IUiContext; import org.vividus.ui.screenshot.ScreenshotConfiguration; +import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.ui.screenshot.ScreenshotParametersFactory; import org.vividus.ui.web.action.search.WebLocatorType; import org.vividus.visual.engine.IVisualTestingEngine; import org.vividus.visual.model.VisualActionType; import org.vividus.visual.model.VisualCheck; import org.vividus.visual.model.VisualCheckResult; -import org.vividus.visual.screenshot.IgnoreStrategy; +import org.vividus.visual.screenshot.BaselineIndexer; @ExtendWith(MockitoExtension.class) class VisualStepsTests @@ -91,46 +95,43 @@ class VisualStepsTests @Mock private ISoftAssert softAssert; @Mock private IAttachmentPublisher attachmentPublisher; @Mock private VisualCheckResult visualCheckResult; - @Mock private VisualCheckFactory visualCheckFactory; @Mock private IUiContext uiContext; + @Mock private BaselineIndexer baselineIndexer; + @Captor private ArgumentCaptor visualCheckCaptor; @InjectMocks private VisualSteps visualSteps; - private VisualCheckFactory factory; - @BeforeEach void init() { - factory = new VisualCheckFactory(screenshotParametersFactory); + lenient().when(baselineIndexer.createIndexedBaseline(BASELINE)).thenReturn(BASELINE); lenient().when(screenshotParametersFactory.create(Optional.empty())).thenReturn(Optional.empty()); - factory.setScreenshotIndexer(Optional.empty()); - factory.setIndexers(Map.of()); + lenient().when(screenshotParametersFactory.create(Map.of())).thenReturn(Optional.empty()); } @ParameterizedTest @CsvSource({"COMPARE_AGAINST", "CHECK_INEQUALITY_AGAINST"}) void shouldAssertCheckResultForCompareAgainstActionAndPublishAttachment(VisualActionType action) throws IOException { - VisualCheck visualCheck = mockVisualCheckFactory(action); mockUiContext(); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(action, BASELINE); + validateVisualCheck(visualCheckCaptor.getValue(), action); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); verifyCheckResultPublish(); } @Test void shouldPerformVisualCheckWithBaselineRepository() throws IOException { - VisualCheck visualCheck = mockVisualCheckFactory(VisualActionType.ESTABLISH); mockUiContext(); - when(visualTestingEngine.establish(visualCheck)).thenReturn(visualCheckResult); + when(visualTestingEngine.establish(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(VisualActionType.ESTABLISH, BASELINE, FILESYSTEM); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); + VisualCheck visualCheck = visualCheckCaptor.getValue(); assertEquals(Optional.of(FILESYSTEM), visualCheck.getBaselineRepository()); + validateVisualCheck(visualCheck, VisualActionType.ESTABLISH); verifyCheckResultPublish(); } @@ -146,14 +147,13 @@ void shouldPerformVisualCheckWithCustomConfiguration() throws IOException VisualActionType compareAgainst = VisualActionType.COMPARE_AGAINST; mockUiContext(); ScreenshotConfiguration screenshotConfiguration = mock(ScreenshotConfiguration.class); - VisualCheck visualCheck = factory.create(BASELINE, compareAgainst); - when(visualCheckFactory.create(BASELINE, compareAgainst, Optional.of(screenshotConfiguration))) - .thenReturn(visualCheck); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + Optional screenshotParameters = Optional.of(mock(ScreenshotParameters.class)); + when(screenshotParametersFactory.create(Optional.of(screenshotConfiguration))).thenReturn(screenshotParameters); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(compareAgainst, BASELINE, screenshotConfiguration); + validateVisualCheck(visualCheckCaptor.getValue(), compareAgainst); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); verifyCheckResultPublish(); } @@ -163,29 +163,28 @@ void shouldPerformVisualCheckWithCustomConfigurationAndBaselineRepository() thro VisualActionType compareAgainst = VisualActionType.COMPARE_AGAINST; mockUiContext(); ScreenshotConfiguration screenshotConfiguration = mock(ScreenshotConfiguration.class); - VisualCheck visualCheck = factory.create(BASELINE, compareAgainst); - when(visualCheckFactory.create(BASELINE, compareAgainst, Optional.of(screenshotConfiguration))) - .thenReturn(visualCheck); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + Optional screenshotParameters = Optional.of(mock(ScreenshotParameters.class)); + when(screenshotParametersFactory.create(Optional.of(screenshotConfiguration))).thenReturn(screenshotParameters); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(compareAgainst, BASELINE, FILESYSTEM, screenshotConfiguration); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); + VisualCheck visualCheck = visualCheckCaptor.getValue(); assertEquals(Optional.of(FILESYSTEM), visualCheck.getBaselineRepository()); + validateVisualCheck(visualCheck, compareAgainst); verifyCheckResultPublish(); } @Test void shouldRecordFailedAssertionInCaseOfMissingBaseline() throws IOException { - VisualCheck visualCheck = mockVisualCheckFactory(VisualActionType.COMPARE_AGAINST); mockUiContext(); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); when(visualCheckResult.getBaselineName()).thenReturn(BASELINE); visualSteps.runVisualTests(VisualActionType.COMPARE_AGAINST, BASELINE); verify(softAssert, never()).assertTrue(VISUAL_CHECK_PASSED, false); verify(softAssert).recordFailedAssertion("Unable to find baseline with name: baseline"); - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); + validateVisualCheck(visualCheckCaptor.getValue(), VisualActionType.COMPARE_AGAINST); verifyCheckResultPublish(); } @@ -214,14 +213,17 @@ void shouldAssertCheckResultAndUseStepLevelSettings(VisualActionType actionType, Set elementsToIgnore = Set.of(A_LOCATOR); Set areasToIgnore = Set.of(DIV_LOCATOR); mockRow(row, elementsToIgnore, areasToIgnore, 50, columnName); - VisualCheck visualCheck = mockVisualCheckFactory(actionType); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + Map> ignores = Map.of(IgnoreStrategy.ELEMENT, elementsToIgnore, + IgnoreStrategy.AREA, areasToIgnore); + Optional screenshotParameters = Optional.of(mock(ScreenshotParameters.class)); + when(screenshotParametersFactory.create(ignores)).thenReturn(screenshotParameters); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(actionType, BASELINE, table); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); + VisualCheck visualCheck = visualCheckCaptor.getValue(); assertEquals(OptionalDouble.of(50), diffValueExtractor.apply(visualCheck)); - assertEquals(Map.of(IgnoreStrategy.ELEMENT, elementsToIgnore, IgnoreStrategy.AREA, areasToIgnore), - visualCheck.getElementsToIgnore()); + validateVisualCheck(visualCheck, actionType); verifyCheckResultPublish(); } @@ -236,15 +238,19 @@ void shouldAssertCheckResultUsingBaselineRepositoryAndUseStepLevelSettings() thr Set elementsToIgnore = Set.of(A_LOCATOR); Set areasToIgnore = Set.of(DIV_LOCATOR); mockRow(row, elementsToIgnore, areasToIgnore, 50, ACCEPTABLE_DIFF_PERCENTAGE); - VisualCheck visualCheck = mockVisualCheckFactory(VisualActionType.COMPARE_AGAINST); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + Map> ignores = Map.of(IgnoreStrategy.ELEMENT, elementsToIgnore, + IgnoreStrategy.AREA, areasToIgnore); + Optional screenshotParameters = Optional.of(mock(ScreenshotParameters.class)); + when(screenshotParametersFactory.create(ignores)).thenReturn(screenshotParameters); + + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(VisualActionType.COMPARE_AGAINST, BASELINE, FILESYSTEM, table); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); + VisualCheck visualCheck = visualCheckCaptor.getValue(); assertEquals(OptionalDouble.of(50), visualCheck.getAcceptableDiffPercentage()); assertEquals(Optional.of(FILESYSTEM), visualCheck.getBaselineRepository()); - assertEquals(Map.of(IgnoreStrategy.ELEMENT, elementsToIgnore, IgnoreStrategy.AREA, areasToIgnore), - visualCheck.getElementsToIgnore()); + validateVisualCheck(visualCheck, VisualActionType.COMPARE_AGAINST); verifyCheckResultPublish(); } @@ -260,17 +266,16 @@ void shouldRunVisualTestWithStepLevelExclusionsAndCustomScreenshotConfiguration( Set areasToIgnore = Set.of(DIV_LOCATOR); mockRow(row, elementsToIgnore, areasToIgnore); ScreenshotConfiguration screenshotConfiguration = mock(ScreenshotConfiguration.class); + Optional screenshotParameters = Optional.of(mock(ScreenshotParameters.class)); + when(screenshotParametersFactory.create(Optional.of(screenshotConfiguration))).thenReturn(screenshotParameters); VisualActionType compareAgainst = VisualActionType.COMPARE_AGAINST; - VisualCheck visualCheck = factory.create(BASELINE, compareAgainst); - when(visualCheckFactory.create(BASELINE, compareAgainst, Optional.of(screenshotConfiguration))) - .thenReturn(visualCheck); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(compareAgainst, BASELINE, table, screenshotConfiguration); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); + VisualCheck visualCheck = visualCheckCaptor.getValue(); assertEquals(OptionalDouble.empty(), visualCheck.getRequiredDiffPercentage()); - assertEquals(Map.of(IgnoreStrategy.ELEMENT, elementsToIgnore, IgnoreStrategy.AREA, areasToIgnore), - visualCheck.getElementsToIgnore()); + validateVisualCheck(visualCheck, compareAgainst); verifyCheckResultPublish(); } @@ -287,18 +292,17 @@ void shouldRunVisualTestWithBaselineRepositoryAndStepLevelExclusionsAndCustomScr Set areasToIgnore = Set.of(DIV_LOCATOR); mockRow(row, elementsToIgnore, areasToIgnore); ScreenshotConfiguration screenshotConfiguration = mock(ScreenshotConfiguration.class); + Optional screenshotParameters = Optional.of(mock(ScreenshotParameters.class)); + when(screenshotParametersFactory.create(Optional.of(screenshotConfiguration))).thenReturn(screenshotParameters); VisualActionType compareAgainst = VisualActionType.COMPARE_AGAINST; - VisualCheck visualCheck = factory.create(BASELINE, compareAgainst); - when(visualCheckFactory.create(BASELINE, compareAgainst, Optional.of(screenshotConfiguration))) - .thenReturn(visualCheck); - when(visualTestingEngine.compareAgainst(visualCheck)).thenReturn(visualCheckResult); + when(visualTestingEngine.compareAgainst(visualCheckCaptor.capture())).thenReturn(visualCheckResult); mockCheckResult(); visualSteps.runVisualTests(compareAgainst, BASELINE, FILESYSTEM, table, screenshotConfiguration); verify(softAssert).assertTrue(VISUAL_CHECK_PASSED, false); + VisualCheck visualCheck = visualCheckCaptor.getValue(); assertEquals(OptionalDouble.empty(), visualCheck.getRequiredDiffPercentage()); assertEquals(Optional.of(FILESYSTEM), visualCheck.getBaselineRepository()); - assertEquals(Map.of(IgnoreStrategy.ELEMENT, elementsToIgnore, IgnoreStrategy.AREA, areasToIgnore), - visualCheck.getElementsToIgnore()); + validateVisualCheck(visualCheck, compareAgainst); verifyCheckResultPublish(); } @@ -307,13 +311,6 @@ private void mockCheckResult() when(visualCheckResult.getBaseline()).thenReturn(StringUtils.EMPTY); } - private VisualCheck mockVisualCheckFactory(VisualActionType actionType) - { - VisualCheck visualCheck = factory.create(BASELINE, actionType); - when(visualCheckFactory.create(BASELINE, actionType)).thenReturn(visualCheck); - return visualCheck; - } - @Test void shouldThrowExceptionIfTableHasMoreThanOneRow() { @@ -353,13 +350,12 @@ private static void mockGettingValue(Parameters row, String name, Set r void shouldNotAssertResultForEstablishAction() throws IOException { mockUiContext(); - VisualCheck visualCheck = mockVisualCheckFactory(VisualActionType.ESTABLISH); - when(visualTestingEngine.establish(visualCheck)).thenReturn(visualCheckResult); + when(visualTestingEngine.establish(visualCheckCaptor.capture())).thenReturn(visualCheckResult); when(visualCheckResult.getActionType()).thenReturn(VisualActionType.ESTABLISH); visualSteps.runVisualTests(VisualActionType.ESTABLISH, BASELINE); verifyNoMoreInteractions(softAssert); verifyCheckResultPublish(); - assertEquals(Map.of(), visualCheck.getElementsToIgnore()); + validateVisualCheck(visualCheckCaptor.getValue(), VisualActionType.ESTABLISH); } @Test @@ -367,7 +363,7 @@ void shouldDoNothingOnMissingSearchContext() { when(uiContext.getOptionalSearchContext()).thenReturn(Optional.empty()); visualSteps.runVisualTests(VisualActionType.ESTABLISH, BASELINE); - verifyNoInteractions(visualCheckFactory, visualTestingEngine, attachmentPublisher); + verifyNoInteractions(visualTestingEngine, attachmentPublisher); } static Stream exceptionsToCatch() @@ -385,12 +381,18 @@ void shouldRecordExceptions(Exception exception) throws IOException private void shouldRecordException(Exception exception) throws IOException { - VisualCheck visualCheck = mockVisualCheckFactory(VisualActionType.ESTABLISH); - when(visualTestingEngine.establish(visualCheck)).thenThrow(exception); + when(visualTestingEngine.establish(visualCheckCaptor.capture())).thenThrow(exception); visualSteps.runVisualTests(VisualActionType.ESTABLISH, BASELINE); verify(softAssert).recordFailedAssertion(exception); verifyNoInteractions(attachmentPublisher); verifyNoMoreInteractions(softAssert); + validateVisualCheck(visualCheckCaptor.getValue(), VisualActionType.ESTABLISH); + } + + private void validateVisualCheck(VisualCheck visualCheck, VisualActionType type) + { + assertEquals(BASELINE, visualCheck.getBaselineName()); + assertEquals(type, visualCheck.getAction()); } private void verifyCheckResultPublish() diff --git a/vividus-plugin-visual/src/test/java/org/vividus/visual/engine/VisualTestingEngineTests.java b/vividus-plugin-visual/src/test/java/org/vividus/visual/engine/VisualTestingEngineTests.java index 851a8a2f02..94ebd78358 100644 --- a/vividus-plugin-visual/src/test/java/org/vividus/visual/engine/VisualTestingEngineTests.java +++ b/vividus-plugin-visual/src/test/java/org/vividus/visual/engine/VisualTestingEngineTests.java @@ -48,7 +48,6 @@ import com.github.valfirst.slf4jtest.TestLoggerFactoryExtension; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -56,14 +55,12 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import org.vividus.ui.screenshot.ScreenshotConfiguration; -import org.vividus.ui.screenshot.ScreenshotParametersFactory; +import org.vividus.selenium.screenshot.AshotScreenshotTaker; +import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.util.ResourceUtils; -import org.vividus.visual.VisualCheckFactory; import org.vividus.visual.model.VisualActionType; import org.vividus.visual.model.VisualCheck; import org.vividus.visual.model.VisualCheckResult; -import org.vividus.visual.screenshot.ScreenshotProvider; import ru.yandex.qatools.ashot.Screenshot; @@ -91,24 +88,12 @@ class VisualTestingEngineTests private final TestLogger testLogger = TestLoggerFactory.getTestLogger(VisualTestingEngine.class); - @Mock private ScreenshotParametersFactory screenshotParametersFactory; @Mock private BaselineRepository baselineRepository; - @Mock private ScreenshotProvider screenshotProvider; + @Mock private AshotScreenshotTaker ashotScreenshotTaker; @Spy private DiffMarkupPolicyFactory diffMarkupPolicyFactory; private VisualTestingEngine visualTestingEngine; - private VisualCheckFactory factory; - - @BeforeEach - void init() - { - factory = new VisualCheckFactory(screenshotParametersFactory); - when(screenshotParametersFactory.create(Optional.empty())).thenReturn(Optional.empty()); - factory.setScreenshotIndexer(Optional.empty()); - factory.setIndexers(Map.of()); - } - void initObjectUnderTest() { initObjectUnderTest(Map.of(FILESYSTEM, baselineRepository)); @@ -116,7 +101,7 @@ void initObjectUnderTest() void initObjectUnderTest(Map baselineRepositories) { - visualTestingEngine = new VisualTestingEngine(screenshotProvider, diffMarkupPolicyFactory, + visualTestingEngine = new VisualTestingEngine(ashotScreenshotTaker, diffMarkupPolicyFactory, baselineRepositories); visualTestingEngine.setAcceptableDiffPercentage(0.0d); visualTestingEngine.setBaselineRepository(FILESYSTEM); @@ -142,7 +127,9 @@ void shouldReturnOnlyCheckpointForEstablishAction() throws IOException private VisualCheck createVisualCheck(VisualActionType actionType) { - return factory.create(BASELINE, actionType); + VisualCheck check = new VisualCheck(BASELINE, actionType); + check.setScreenshotParameters(Optional.empty()); + return check; } @ParameterizedTest @@ -201,7 +188,7 @@ void shouldReturnVisualCheckResultWithBaselineAndCheckpointUsingAcceptableDiffPe { initObjectUnderTest(); when(baselineRepository.getBaseline(BASELINE)).thenReturn(Optional.of(new Screenshot(loadImage(BASELINE)))); - VisualCheck visualCheck = factory.create(BASELINE, VisualActionType.COMPARE_AGAINST); + VisualCheck visualCheck = createVisualCheck(VisualActionType.COMPARE_AGAINST); visualCheck.setAcceptableDiffPercentage(OptionalDouble.of(50)); mockGetCheckpointScreenshot(visualCheck); VisualCheckResult checkResult = visualTestingEngine.compareAgainst(visualCheck); @@ -313,7 +300,8 @@ private BufferedImage mockGetCheckpointScreenshot(VisualCheck visualCheck, Strin { BufferedImage image = loadImage(imageName); Screenshot screenshot = new Screenshot(image); - when(screenshotProvider.take(visualCheck)).thenReturn(screenshot); + when(ashotScreenshotTaker.takeAshotScreenshot(visualCheck.getSearchContext(), + visualCheck.getScreenshotParameters())).thenReturn(screenshot); return image; } diff --git a/vividus-plugin-visual/src/test/java/org/vividus/visual/model/VisualCheckTests.java b/vividus-plugin-visual/src/test/java/org/vividus/visual/model/VisualCheckTests.java index 739f8e9f2c..3f5f929255 100644 --- a/vividus-plugin-visual/src/test/java/org/vividus/visual/model/VisualCheckTests.java +++ b/vividus-plugin-visual/src/test/java/org/vividus/visual/model/VisualCheckTests.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.Map; import java.util.Optional; import java.util.OptionalDouble; @@ -36,7 +35,6 @@ void shouldHaveDefaultParameters() Assertions.assertAll( () -> assertEquals(OptionalDouble.empty(), visualCheck.getAcceptableDiffPercentage()), () -> assertEquals(OptionalDouble.empty(), visualCheck.getRequiredDiffPercentage()), - () -> assertEquals(Map.of(), visualCheck.getElementsToIgnore()), () -> assertEquals(Optional.empty(), visualCheck.getScreenshotParameters())); } diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/ScrollBarHidingCoordsProviderDecorator.java b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/ScrollBarHidingCoordsProviderDecorator.java new file mode 100644 index 0000000000..e22130f24f --- /dev/null +++ b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/ScrollBarHidingCoordsProviderDecorator.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.selenium.screenshot; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; + +public class ScrollBarHidingCoordsProviderDecorator extends CoordsProvider +{ + private static final long serialVersionUID = -4309766535331129861L; + + private final CoordsProvider coordsProvider; + private final transient IScrollbarHandler scrollbarHandler; + + public ScrollBarHidingCoordsProviderDecorator(CoordsProvider coordsProvider, IScrollbarHandler scrollbarHandler) + { + this.coordsProvider = coordsProvider; + this.scrollbarHandler = scrollbarHandler; + } + + @Override + public Coords ofElement(WebDriver driver, WebElement element) + { + return scrollbarHandler.performActionWithHiddenScrollbars(() -> coordsProvider.ofElement(driver, element)); + } +} diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAshotFactory.java b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAshotFactory.java index 393ac3cfdf..43a2c484c9 100644 --- a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAshotFactory.java +++ b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAshotFactory.java @@ -18,6 +18,7 @@ import java.util.Optional; +import org.openqa.selenium.WebElement; import org.vividus.selenium.screenshot.strategies.AdjustingScrollableElementAwareViewportPastingDecorator; import org.vividus.selenium.screenshot.strategies.AdjustingViewportPastingDecorator; import org.vividus.selenium.screenshot.strategies.ScreenshotShootingStrategy; @@ -28,7 +29,9 @@ import org.vividus.ui.web.screenshot.WebScreenshotParameters; import ru.yandex.qatools.ashot.AShot; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; import ru.yandex.qatools.ashot.shooting.DebuggingViewportPastingDecorator; +import ru.yandex.qatools.ashot.shooting.ScrollbarHidingDecorator; import ru.yandex.qatools.ashot.shooting.ShootingStrategy; public class WebAshotFactory extends AbstractAshotFactory @@ -37,9 +40,10 @@ public class WebAshotFactory extends AbstractAshotFactory scrollableElement) + { + return new ScrollbarHidingDecorator(strategy, scrollableElement, scrollbarHandler); + } + private AShot createAShot(String screenshotShootingStrategyName) { ScreenshotShootingStrategy configured = getStrategyBy(screenshotShootingStrategyName); ShootingStrategy baseShootingStrategy = getBaseShootingStrategy(); ShootingStrategy shootingStrategy = configured.getDecoratedShootingStrategy(baseShootingStrategy); - return new ScrollbarHidingAshot(Optional.empty(), scrollbarHandler).shootingStrategy(shootingStrategy) - .coordsProvider(configured instanceof SimpleScreenshotShootingStrategy - ? CeilingJsCoordsProvider.getSimple(javascriptActions) - : CeilingJsCoordsProvider.getScrollAdjusted(javascriptActions)); + shootingStrategy = decorateWithScrollbarHiding(shootingStrategy, Optional.empty()); + CoordsProvider coordsProvider = configured instanceof SimpleScreenshotShootingStrategy + ? CeilingJsCoordsProvider.getSimple(javascriptActions) + : CeilingJsCoordsProvider.getScrollAdjusted(javascriptActions); + return new AShot().shootingStrategy(shootingStrategy) + .coordsProvider(new ScrollBarHidingCoordsProviderDecorator(coordsProvider, scrollbarHandler)); } @Override diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAdjustingCoordsProvider.java b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebCoordsProvider.java similarity index 79% rename from vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAdjustingCoordsProvider.java rename to vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebCoordsProvider.java index 203a885fe9..fbff7585f3 100644 --- a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebAdjustingCoordsProvider.java +++ b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebCoordsProvider.java @@ -20,22 +20,19 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.vividus.selenium.manager.IWebDriverManager; -import org.vividus.ui.context.IUiContext; import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.WebDriverCoordsProvider; -public class WebAdjustingCoordsProvider extends AbstractAdjustingCoordsProvider +public class WebCoordsProvider extends WebDriverCoordsProvider { private static final long serialVersionUID = 3963826455192835938L; private final transient IWebDriverManager webDriverManager; - private final transient IScrollbarHandler scrollbarHandler; - public WebAdjustingCoordsProvider(IWebDriverManager webDriverManager, IScrollbarHandler scrollbarHandler, - IUiContext uiContext) + public WebCoordsProvider(IWebDriverManager webDriverManager, IScrollbarHandler scrollbarHandler) { - super(uiContext); this.webDriverManager = webDriverManager; this.scrollbarHandler = scrollbarHandler; } @@ -50,16 +47,10 @@ public Coords ofElement(WebDriver driver, WebElement element) { coords.y += Math.toIntExact(getYOffset(driver)); } - return adjustToSearchContext(coords); + return coords; }); } - @Override - protected Coords getCoords(WebElement webElement) - { - return super.ofElement(null, webElement); - } - private long getYOffset(WebDriver webDriver) { return executeScript(webDriver, "return pageYOffset"); diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebScreenshotCropper.java b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebScreenshotCropper.java new file mode 100644 index 0000000000..1a86677d60 --- /dev/null +++ b/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/WebScreenshotCropper.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.selenium.screenshot; + +import java.awt.Point; +import java.util.Optional; + +import org.openqa.selenium.WebElement; +import org.vividus.selenium.IWebDriverProvider; +import org.vividus.ui.action.ISearchActions; +import org.vividus.ui.context.IUiContext; + +import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; + +public class WebScreenshotCropper extends ScreenshotCropper +{ + private final IUiContext uiContext; + + public WebScreenshotCropper(ScreenshotDebugger screenshotDebugger, ISearchActions searchActions, + CoordsProvider coordsProvider, IWebDriverProvider webDriverProvider, IUiContext uiContext) + { + super(screenshotDebugger, searchActions, coordsProvider, webDriverProvider); + this.uiContext = uiContext; + } + + @Override + protected Point calculateAdjustment(Optional contextCoords, int topAdjustment) + { + if (contextCoords.isEmpty()) + { + return super.calculateAdjustment(contextCoords, topAdjustment); + } + + /** + * This shift in x and y coords should be removed after the following issue is resolved: + * https://github.com/vividus-framework/vividus/issues/2883 + */ + WebElement context = uiContext.getSearchContext(WebElement.class).get(); + Coords currentContextCoords = getCoordsProvider().ofElement(getWebDriverProvider().get(), context); + Coords targetContextCoords = contextCoords.get(); + + int yShift = targetContextCoords.y - currentContextCoords.y; + int xShift = targetContextCoords.x - currentContextCoords.x; + + return new Point(xShift, yShift - topAdjustment); + } +} diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactory.java b/vividus-plugin-web-app/src/main/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactory.java index c0c56e2324..7361ba8755 100644 --- a/vividus-plugin-web-app/src/main/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactory.java +++ b/vividus-plugin-web-app/src/main/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactory.java @@ -16,15 +16,20 @@ package org.vividus.ui.web.screenshot; +import java.util.Map; import java.util.Optional; +import java.util.Set; import org.openqa.selenium.WebElement; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.ui.action.ISearchActions; +import org.vividus.ui.action.search.Locator; import org.vividus.ui.screenshot.AbstractScreenshotParametersFactory; import org.vividus.ui.screenshot.ScreenshotParameters; import org.vividus.ui.screenshot.ScreenshotPrecondtionMismatchException; -public class WebScreenshotParametersFactory extends AbstractScreenshotParametersFactory +public class WebScreenshotParametersFactory + extends AbstractScreenshotParametersFactory { private final ISearchActions searchActions; @@ -36,29 +41,43 @@ public WebScreenshotParametersFactory(ISearchActions searchActions) @Override public Optional create(Optional screenshotConfiguration) { - return getScreenshotConfiguration(screenshotConfiguration, (c, b) -> c).map(config -> - { - WebScreenshotParameters parameters = createWithBaseConfiguration(config, - WebScreenshotParameters::new); - parameters.setNativeHeaderToCut(ensureValidCutSize(config.getNativeHeaderToCut(), "native header")); + return getScreenshotConfiguration(screenshotConfiguration, (c, b) -> c).map( + cfg -> configure(cfg, createWithBaseConfiguration(cfg))); + } - WebCutOptions webCutOptions = new WebCutOptions( - ensureValidCutSize(config.getWebHeaderToCut(), "web header"), - ensureValidCutSize(config.getWebFooterToCut(), "web footer") - ); - parameters.setWebCutOptions(webCutOptions); + @Override + public Optional create(Map> ignores) + { + WebScreenshotConfiguration configuration = getDefaultConfiguration().orElseGet(WebScreenshotConfiguration::new); + return Optional.of(configure(configuration, createWithBaseConfiguration(configuration, ignores))); + } - config.getScrollableElement().ifPresent(locator -> - { - WebElement scrollableElement = searchActions.findElement(locator).orElseThrow( - () -> new ScreenshotPrecondtionMismatchException("Scrollable element does not exist")); - parameters.setScrollableElement(Optional.of(scrollableElement)); - }); + @Override + protected WebScreenshotParameters createScreenshotParameters() + { + return new WebScreenshotParameters(); + } + + private ScreenshotParameters configure(WebScreenshotConfiguration config, WebScreenshotParameters parameters) + { + parameters.setNativeHeaderToCut(ensureValidCutSize(config.getNativeHeaderToCut(), "native header")); - parameters.setCoordsProvider(config.getCoordsProvider()); - parameters.setScrollTimeout(config.getScrollTimeout()); + WebCutOptions webCutOptions = new WebCutOptions( + ensureValidCutSize(config.getWebHeaderToCut(), "web header"), + ensureValidCutSize(config.getWebFooterToCut(), "web footer") + ); + parameters.setWebCutOptions(webCutOptions); - return parameters; + config.getScrollableElement().ifPresent(locator -> + { + WebElement scrollableElement = searchActions.findElement(locator).orElseThrow( + () -> new ScreenshotPrecondtionMismatchException("Scrollable element does not exist")); + parameters.setScrollableElement(Optional.of(scrollableElement)); }); + + parameters.setCoordsProvider(config.getCoordsProvider()); + parameters.setScrollTimeout(config.getScrollTimeout()); + + return parameters; } } diff --git a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/ScrollbarHidingAshot.java b/vividus-plugin-web-app/src/main/java/ru/yandex/qatools/ashot/shooting/ScrollbarHidingDecorator.java similarity index 51% rename from vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/ScrollbarHidingAshot.java rename to vividus-plugin-web-app/src/main/java/ru/yandex/qatools/ashot/shooting/ScrollbarHidingDecorator.java index 95b1a22b0c..7c810696b6 100644 --- a/vividus-plugin-web-app/src/main/java/org/vividus/selenium/screenshot/ScrollbarHidingAshot.java +++ b/vividus-plugin-web-app/src/main/java/ru/yandex/qatools/ashot/shooting/ScrollbarHidingDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,46 +14,55 @@ * limitations under the License. */ -package org.vividus.selenium.screenshot; +package ru.yandex.qatools.ashot.shooting; +import java.awt.image.BufferedImage; import java.util.Optional; +import java.util.Set; import java.util.function.Supplier; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.vividus.selenium.screenshot.IScrollbarHandler; -import ru.yandex.qatools.ashot.AShot; -import ru.yandex.qatools.ashot.Screenshot; +import ru.yandex.qatools.ashot.coordinates.Coords; -class ScrollbarHidingAshot extends AShot +public class ScrollbarHidingDecorator extends ShootingDecorator { - private static final long serialVersionUID = -3976031178886339719L; + private static final long serialVersionUID = -6146195031592698438L; private final transient Optional scrollableElement; private final transient IScrollbarHandler scrollbarHandler; - ScrollbarHidingAshot(Optional scrollableElement, + public ScrollbarHidingDecorator(ShootingStrategy shootingStrategy, Optional scrollableElement, IScrollbarHandler scrollbarHandler) { + super(shootingStrategy); this.scrollableElement = scrollableElement; this.scrollbarHandler = scrollbarHandler; } @Override - public Screenshot takeScreenshot(WebDriver driver) + public BufferedImage getScreenshot(WebDriver wd) { - return takeWithHiddentScrollbars(() -> super.takeScreenshot(driver)); + return perform(() -> getShootingStrategy().getScreenshot(wd)); } @Override - public Screenshot takeScreenshot(WebDriver driver, WebElement webElement) + public BufferedImage getScreenshot(WebDriver wd, Set coords) { - return takeWithHiddentScrollbars(() -> super.takeScreenshot(driver, webElement)); + return perform(() -> getShootingStrategy().getScreenshot(wd, coords)); } - private Screenshot takeWithHiddentScrollbars(Supplier taker) + @Override + public Set prepareCoords(Set coordsSet) + { + return getShootingStrategy().prepareCoords(coordsSet); + } + + private BufferedImage perform(Supplier bufferedImageSupplier) { - return scrollableElement.map(e -> scrollbarHandler.performActionWithHiddenScrollbars(taker, e)) - .orElseGet(() -> scrollbarHandler.performActionWithHiddenScrollbars(taker)); + return scrollableElement.map(e -> scrollbarHandler.performActionWithHiddenScrollbars(bufferedImageSupplier, e)) + .orElseGet(() -> scrollbarHandler.performActionWithHiddenScrollbars(bufferedImageSupplier)); } } diff --git a/vividus-plugin-web-app/src/main/resources/spring.xml b/vividus-plugin-web-app/src/main/resources/spring.xml index ffc77f70f4..f9165a0333 100644 --- a/vividus-plugin-web-app/src/main/resources/spring.xml +++ b/vividus-plugin-web-app/src/main/resources/spring.xml @@ -9,7 +9,6 @@ http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" default-lazy-init="true" profile="web"> - @@ -23,9 +22,9 @@ - + - + @@ -33,7 +32,10 @@ - + + + diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/ScrollBarHidingCoordsProviderDecoratorTests.java b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/ScrollBarHidingCoordsProviderDecoratorTests.java new file mode 100644 index 0000000000..25cf8e802c --- /dev/null +++ b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/ScrollBarHidingCoordsProviderDecoratorTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.selenium.screenshot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.awt.image.BufferedImage; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; + +@ExtendWith(MockitoExtension.class) +class ScrollBarHidingCoordsProviderDecoratorTests +{ + @Mock private CoordsProvider coordsProvider; + @Mock private ScrollbarHandler scrollbarHandler; + @Mock private Coords coords; + @Mock private WebDriver webDriver; + @Mock private WebElement webElement; + @Mock private BufferedImage bufferedImage; + + @Test + void shouldReturnCoordsOfElement() + { + when(scrollbarHandler.performActionWithHiddenScrollbars(argThat(s -> { + s.get(); + return true; + }))).thenReturn(coords); + ScrollBarHidingCoordsProviderDecorator decorator = new ScrollBarHidingCoordsProviderDecorator(coordsProvider, + scrollbarHandler); + Coords elementCoords = decorator.ofElement(webDriver, webElement); + assertEquals(coords, elementCoords); + verify(coordsProvider).ofElement(webDriver, webElement); + } +} diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAshotFactoryTests.java b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAshotFactoryTests.java index a1c489cffb..fed2555352 100644 --- a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAshotFactoryTests.java +++ b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAshotFactoryTests.java @@ -46,8 +46,11 @@ import org.vividus.ui.web.screenshot.WebScreenshotParameters; import ru.yandex.qatools.ashot.AShot; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; import ru.yandex.qatools.ashot.shooting.CuttingDecorator; +import ru.yandex.qatools.ashot.shooting.ElementCroppingDecorator; import ru.yandex.qatools.ashot.shooting.ScalingDecorator; +import ru.yandex.qatools.ashot.shooting.ScrollbarHidingDecorator; import ru.yandex.qatools.ashot.shooting.ShootingStrategy; import ru.yandex.qatools.ashot.shooting.cutter.CutStrategy; import ru.yandex.qatools.ashot.shooting.cutter.FixedCutStrategy; @@ -77,8 +80,10 @@ void shouldCreateAshotViaScreenshotShootingStrategyIfThereIsNoConfigurationFound webAshotFactory.setStrategies(Map.of(VIEWPORT_PASTING, new ViewportPastingScreenshotShootingStrategy())); webAshotFactory.setScreenshotShootingStrategy(VIEWPORT_PASTING); AShot aShot = webAshotFactory.create(Optional.empty()); - assertThat(FieldUtils.readField(aShot, COORDS_PROVIDER, true), is(instanceOf(CeilingJsCoordsProvider.class))); - assertThat(FieldUtils.readField(aShot, SHOOTING_STRATEGY, true), + validateCoordsProvider(aShot); + ShootingStrategy baseStrategy = (ShootingStrategy) FieldUtils.readField(aShot, SHOOTING_STRATEGY, true); + assertThat(baseStrategy, instanceOf(ScrollbarHidingDecorator.class)); + assertThat(FieldUtils.readField(baseStrategy, SHOOTING_STRATEGY, true), instanceOf(AdjustingViewportPastingDecorator.class)); } @@ -90,8 +95,10 @@ void shouldCreateAshotViaScreenshotShootingStrategyUsingStrategyFromConfiguratio WebScreenshotParameters screenshotParameters = new WebScreenshotParameters(); screenshotParameters.setShootingStrategy(Optional.of(VIEWPORT_PASTING)); AShot aShot = webAshotFactory.create(Optional.of(screenshotParameters)); - assertThat(FieldUtils.readField(aShot, COORDS_PROVIDER, true), is(instanceOf(CeilingJsCoordsProvider.class))); - assertThat(FieldUtils.readField(aShot, SHOOTING_STRATEGY, true), + validateCoordsProvider(aShot); + ShootingStrategy baseStrategy = (ShootingStrategy) FieldUtils.readField(aShot, SHOOTING_STRATEGY, true); + assertThat(baseStrategy, instanceOf(ScrollbarHidingDecorator.class)); + assertThat(FieldUtils.readField(baseStrategy, SHOOTING_STRATEGY, true), instanceOf(AdjustingViewportPastingDecorator.class)); } @@ -101,8 +108,11 @@ void shouldCreateAshotViaWithSimpleCoords() throws IllegalAccessException webAshotFactory.setStrategies(Map.of(SIMPLE, new SimpleScreenshotShootingStrategy())); webAshotFactory.setScreenshotShootingStrategy(SIMPLE); AShot aShot = webAshotFactory.create(Optional.empty()); - assertThat(FieldUtils.readField(aShot, COORDS_PROVIDER, true), is(instanceOf(CeilingJsCoordsProvider.class))); - assertThat(FieldUtils.readField(aShot, SHOOTING_STRATEGY, true), instanceOf(ViewportShootingStrategy.class)); + validateCoordsProvider(aShot); + ShootingStrategy baseStrategy = (ShootingStrategy) FieldUtils.readField(aShot, SHOOTING_STRATEGY, true); + assertThat(baseStrategy, instanceOf(ScrollbarHidingDecorator.class)); + assertThat(FieldUtils.readField(baseStrategy, SHOOTING_STRATEGY, true), + instanceOf(ViewportShootingStrategy.class)); } @Test @@ -119,9 +129,16 @@ void shouldCreateAshotWithCuttingStrategiesForNativeWebHeadersFooters() throws I AShot aShot = webAshotFactory.create(Optional.of(screenshotParameters)); - assertThat(FieldUtils.readField(aShot, COORDS_PROVIDER, true), is(instanceOf(CeilingJsCoordsProvider.class))); - ShootingStrategy viewportPastingDecorator = getShootingStrategy(aShot); - assertThat(viewportPastingDecorator, is(instanceOf(AdjustingViewportPastingDecorator.class))); + validateCoordsProvider(aShot); + ShootingStrategy baseStrategy = getShootingStrategy(aShot); + assertThat(baseStrategy, is(instanceOf(ElementCroppingDecorator.class))); + + ShootingStrategy scrollbarHidingDecorator = (ShootingStrategy) FieldUtils.readField(baseStrategy, + SHOOTING_STRATEGY, true); + assertThat(scrollbarHidingDecorator, is(instanceOf(ScrollbarHidingDecorator.class))); + + ShootingStrategy viewportPastingDecorator = (ShootingStrategy) FieldUtils.readField(scrollbarHidingDecorator, + SHOOTING_STRATEGY, true); assertEquals(500, (int) FieldUtils.readField(viewportPastingDecorator, "scrollTimeout", true)); assertEquals(screenshotDebugger, FieldUtils.readField(viewportPastingDecorator, "screenshotDebugger", true)); @@ -160,10 +177,19 @@ void shouldCreateAshotUsingScrollableElement() throws IllegalAccessException screenshotParameters.setScrollTimeout(Duration.ofMillis(TEN)); AShot aShot = webAshotFactory.create(Optional.of(screenshotParameters)); - assertThat(FieldUtils.readField(aShot, COORDS_PROVIDER, true), is(instanceOf(CeilingJsCoordsProvider.class))); - ShootingStrategy scrollableElementAwareDecorator = getShootingStrategy(aShot); + validateCoordsProvider(aShot); + ShootingStrategy decorator = getShootingStrategy(aShot); + assertThat(decorator, is(instanceOf(ElementCroppingDecorator.class))); + + ShootingStrategy scrollbarHidingDecorator = (ShootingStrategy) FieldUtils.readField(decorator, + SHOOTING_STRATEGY, true); + assertThat(scrollbarHidingDecorator, is(instanceOf(ScrollbarHidingDecorator.class))); + + ShootingStrategy scrollableElementAwareDecorator = (ShootingStrategy) FieldUtils + .readField(scrollbarHidingDecorator, SHOOTING_STRATEGY, true); assertThat(scrollableElementAwareDecorator, is(instanceOf(AdjustingScrollableElementAwareViewportPastingDecorator.class))); + assertEquals(webElement, FieldUtils.readField(scrollableElementAwareDecorator, "scrollableElement", true)); ShootingStrategy scalingDecorator = getShootingStrategy(scrollableElementAwareDecorator); @@ -171,6 +197,14 @@ void shouldCreateAshotUsingScrollableElement() throws IllegalAccessException verifyDPR(scalingDecorator); } + private void validateCoordsProvider(AShot aShot) throws IllegalAccessException + { + CoordsProvider coordsProvider = (CoordsProvider) FieldUtils.readField(aShot, COORDS_PROVIDER, true); + assertThat(coordsProvider, is(instanceOf(ScrollBarHidingCoordsProviderDecorator.class))); + coordsProvider = (CoordsProvider) FieldUtils.readField(coordsProvider, COORDS_PROVIDER, true); + assertThat(coordsProvider, is(instanceOf(CeilingJsCoordsProvider.class))); + } + private CutStrategy getCutStrategy(Object hasCutStrategy) throws IllegalAccessException { return (CutStrategy) FieldUtils.readField(hasCutStrategy, "cutStrategy", true); diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAdjustingCoordsProviderTests.java b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebCoordsProviderTests.java similarity index 81% rename from vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAdjustingCoordsProviderTests.java rename to vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebCoordsProviderTests.java index b14e2dd743..127a94b08f 100644 --- a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebAdjustingCoordsProviderTests.java +++ b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebCoordsProviderTests.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -34,12 +33,11 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.vividus.selenium.manager.IWebDriverManager; -import org.vividus.ui.context.IUiContext; import ru.yandex.qatools.ashot.coordinates.Coords; @ExtendWith(MockitoExtension.class) -class WebAdjustingCoordsProviderTests +class WebCoordsProviderTests { private static final int X = 1; private static final int Y = 2; @@ -56,14 +54,11 @@ class WebAdjustingCoordsProviderTests @Mock private IWebDriverManager webDriverManager; - @Mock - private IUiContext uiContext; - @Mock private IScrollbarHandler scrollbarHandler; @InjectMocks - private WebAdjustingCoordsProvider adjustingCoordsProvider; + private WebCoordsProvider adjustingCoordsProvider; @Test void testGetCoordsNotIOS() @@ -92,12 +87,8 @@ void testGetCoordsIOS() @Test void shouldIntersectIgnoredElementWithContextAndAdjustCoordinates() { - Coords expectedCoords = new Coords(0, 0, 3, 5); + Coords expectedCoords = new Coords(1, 2, 4, 6); mockScrollbarActions(expectedCoords); - WebElement searchContext = mock(WebElement.class); - when(searchContext.getLocation()).thenReturn(new Point(2, 3)); - when(searchContext.getSize()).thenReturn(new Dimension(5, 5)); - when(uiContext.getSearchContext()).thenReturn(searchContext); when(webElement.getLocation()).thenReturn(new Point(X, Y)); when(webElement.getSize()).thenReturn(new Dimension(4, 6)); Coords coords = adjustingCoordsProvider.ofElement(webDriver, webElement); @@ -108,12 +99,8 @@ void shouldIntersectIgnoredElementWithContextAndAdjustCoordinates() @Test void shouldRelateCoordsIfTheyInsideContext() { - Coords expectedCoords = new Coords(1, 1, WIDTH, HEIGHT); + Coords expectedCoords = new Coords(2, 2, WIDTH, HEIGHT); mockScrollbarActions(expectedCoords); - WebElement searchContext = mock(WebElement.class); - when(searchContext.getLocation()).thenReturn(new Point(1, 1)); - when(searchContext.getSize()).thenReturn(new Dimension(5, 5)); - when(uiContext.getSearchContext()).thenReturn(searchContext); when(webElement.getLocation()).thenReturn(new Point(2, 2)); when(webElement.getSize()).thenReturn(new Dimension(WIDTH, HEIGHT)); Coords coords = adjustingCoordsProvider.ofElement(webDriver, webElement); @@ -129,8 +116,8 @@ private void mockScrollbarActions() private void mockScrollbarActions(Coords expectedCoords) { - when(scrollbarHandler.performActionWithHiddenScrollbars( - argThat(a -> expectedCoords.equals(a.get())))).thenReturn(expectedCoords); + when(scrollbarHandler.performActionWithHiddenScrollbars(argThat(a -> expectedCoords.equals(a.get())))) + .thenReturn(expectedCoords); } private void verifyCoords(Coords coordsToCheck) diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebScreenshotCropperTests.java b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebScreenshotCropperTests.java new file mode 100644 index 0000000000..a207ed33a1 --- /dev/null +++ b/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/WebScreenshotCropperTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2019-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 org.vividus.selenium.screenshot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.vividus.selenium.IWebDriverProvider; +import org.vividus.ui.action.ISearchActions; +import org.vividus.ui.action.search.Locator; +import org.vividus.ui.context.IUiContext; + +import ru.yandex.qatools.ashot.coordinates.Coords; +import ru.yandex.qatools.ashot.coordinates.CoordsProvider; + +@ExtendWith(MockitoExtension.class) +class WebScreenshotCropperTests +{ + @Mock private Locator elementLocator; + @Mock private WebDriver webDriver; + + @Mock private ISearchActions searchActions; + @Mock private CoordsProvider coordsProvider; + @Mock private IWebDriverProvider webDriverProvider; + @Mock private IUiContext uiContext; + @Mock private ScreenshotDebugger screenshotDebugger; + @InjectMocks private WebScreenshotCropper cropper; + + @Test + void shouldAdjustElementsToTargetContext() + { + when(webDriverProvider.get()).thenReturn(webDriver); + WebElement element = mock(WebElement.class); + when(searchActions.findElements(elementLocator)).thenReturn(List.of(element)); + when(coordsProvider.ofElements(webDriver, List.of(element))).thenReturn(Set.of(new Coords(100, 100, 100, 100))); + + WebElement currentContext = mock(WebElement.class); + when(uiContext.getSearchContext(WebElement.class)).thenReturn(Optional.of(currentContext)); + when(coordsProvider.ofElement(webDriver, currentContext)).thenReturn(new Coords(90, 90, 200, 200)); + + BufferedImage image = mock(BufferedImage.class); + Graphics2D g2 = mock(Graphics2D.class); + when(image.createGraphics()).thenReturn(g2); + + Coords targetContext = new Coords(95, 95, 200, 200); + + cropper.crop(image, Optional.of(targetContext), + Map.of(IgnoreStrategy.ELEMENT, Set.of(elementLocator)), 0); + + verify(g2).clearRect(105, 105, 100, 100); + } + + @Test + void shouldNotCalculateAdjustmentIfContextCoordsAreEmpty() + { + Point adjustment = cropper.calculateAdjustment(Optional.empty(), 42); + assertEquals(new Point(0, -42), adjustment); + verifyNoInteractions(webDriverProvider, coordsProvider); + } +} diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactoryTests.java b/vividus-plugin-web-app/src/test/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactoryTests.java index 6db9a004b8..90ba737bae 100644 --- a/vividus-plugin-web-app/src/test/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactoryTests.java +++ b/vividus-plugin-web-app/src/test/java/org/vividus/ui/web/screenshot/WebScreenshotParametersFactoryTests.java @@ -19,11 +19,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.time.Duration; import java.util.Map; import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,6 +34,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.WebElement; import org.vividus.selenium.screenshot.CoordsProviderType; +import org.vividus.selenium.screenshot.IgnoreStrategy; import org.vividus.ui.action.ISearchActions; import org.vividus.ui.action.search.Locator; import org.vividus.ui.screenshot.ScreenshotParameters; @@ -56,6 +59,7 @@ void shouldCreateScreenshotConfiguration() WebScreenshotConfiguration defaultConfiguration = new WebScreenshotConfiguration(); factory.setShootingStrategy(SIMPLE); factory.setScreenshotConfigurations(new PropertyMappedCollection<>(Map.of(SIMPLE, defaultConfiguration))); + factory.setIgnoreStrategies(Map.of()); WebScreenshotConfiguration userConfiguration = new WebScreenshotConfiguration(); userConfiguration.setShootingStrategy(Optional.of(SIMPLE)); @@ -83,11 +87,31 @@ void shouldCreateScreenshotConfiguration() assertEquals(Duration.ofSeconds(1), configuration.getScrollTimeout()); } + @Test + void shouldCreateScreenshotConfigurationWithIgnores() + { + WebScreenshotConfiguration defaultConfiguration = new WebScreenshotConfiguration(); + factory.setShootingStrategy(SIMPLE); + factory.setScreenshotConfigurations(new PropertyMappedCollection<>(Map.of(SIMPLE, defaultConfiguration))); + factory.setIgnoreStrategies(Map.of(IgnoreStrategy.ELEMENT, Set.of(), IgnoreStrategy.AREA, Set.of())); + + Locator locator = mock(Locator.class); + Map> ignores = Map.of( + IgnoreStrategy.ELEMENT, Set.of(locator), + IgnoreStrategy.AREA, Set.of(locator) + ); + Optional createdParameters = factory.create(ignores); + assertTrue(createdParameters.isPresent()); + WebScreenshotParameters configuration = (WebScreenshotParameters) createdParameters.get(); + assertEquals(ignores, configuration.getIgnoreStrategies()); + } + @Test void shouldFailIfElementByLocatorDoesNotExist() { factory.setShootingStrategy(SIMPLE); factory.setScreenshotConfigurations(new PropertyMappedCollection<>(Map.of())); + factory.setIgnoreStrategies(Map.of()); WebScreenshotConfiguration userParameters = new WebScreenshotConfiguration(); userParameters.setScrollableElement(Optional.of(locator)); diff --git a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/ScrollbarHidingAshotTests.java b/vividus-plugin-web-app/src/test/java/ru/yandex/qatools/ashot/shooting/ScrollbarHidingDecoratorTests.java similarity index 61% rename from vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/ScrollbarHidingAshotTests.java rename to vividus-plugin-web-app/src/test/java/ru/yandex/qatools/ashot/shooting/ScrollbarHidingDecoratorTests.java index 76bb987c9e..c0c31f1986 100644 --- a/vividus-plugin-web-app/src/test/java/org/vividus/selenium/screenshot/ScrollbarHidingAshotTests.java +++ b/vividus-plugin-web-app/src/test/java/ru/yandex/qatools/ashot/shooting/ScrollbarHidingDecoratorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,12 +14,13 @@ * limitations under the License. */ -package org.vividus.selenium.screenshot; +package ru.yandex.qatools.ashot.shooting; import static org.junit.jupiter.api.Assertions.assertSame; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.awt.image.BufferedImage; @@ -32,56 +33,51 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.vividus.selenium.screenshot.ScrollbarHandler; import ru.yandex.qatools.ashot.coordinates.Coords; -import ru.yandex.qatools.ashot.coordinates.CoordsProvider; -import ru.yandex.qatools.ashot.shooting.ShootingStrategy; @ExtendWith(MockitoExtension.class) -class ScrollbarHidingAshotTests +class ScrollbarHidingDecoratorTests { @Mock private ShootingStrategy strategy; @Mock private ScrollbarHandler scrollbarHandler; @Mock private WebDriver webDriver; @Mock private BufferedImage bufferedImage; - @Mock private ru.yandex.qatools.ashot.Screenshot screenshot; @Test void shouldTakeScreenshotsWithHiddenScrollbars() { - ScrollbarHidingAshot ashot = new ScrollbarHidingAshot(Optional.empty(), scrollbarHandler); - ashot.shootingStrategy(strategy); + ScrollbarHidingDecorator decorator = new ScrollbarHidingDecorator(strategy, Optional.empty(), scrollbarHandler); when(scrollbarHandler.performActionWithHiddenScrollbars(argThat(s -> { s.get(); return true; - }))).thenReturn(screenshot); + }))).thenReturn(bufferedImage); when(strategy.getScreenshot(webDriver)).thenReturn(bufferedImage); - ashot.takeScreenshot(webDriver); - assertSame(screenshot, ashot.takeScreenshot(webDriver)); + assertSame(bufferedImage, decorator.getScreenshot(webDriver)); } @Test void shouldTakeScreenshotsWithElementAndWithHiddenScrollbars() { WebElement scrollableElement = mock(WebElement.class); - ScrollbarHidingAshot ashot = new ScrollbarHidingAshot(Optional.of(scrollableElement), scrollbarHandler); - ashot.shootingStrategy(strategy); - ashot.coordsProvider(new CoordsProvider() - { - private static final long serialVersionUID = 8784997908203644003L; - - @Override - public Coords ofElement(WebDriver driver, WebElement element) - { - return new Coords(0, 0, 0, 0); - } - }); + ScrollbarHidingDecorator decorator = new ScrollbarHidingDecorator(strategy, Optional.of(scrollableElement), + scrollbarHandler); when(scrollbarHandler.performActionWithHiddenScrollbars(argThat(s -> { s.get(); return true; - }), eq(scrollableElement))).thenReturn(screenshot); + }), eq(scrollableElement))).thenReturn(bufferedImage); when(strategy.getScreenshot(webDriver, Set.of())).thenReturn(bufferedImage); - ashot.takeScreenshot(webDriver, scrollableElement); - assertSame(screenshot, ashot.takeScreenshot(webDriver, scrollableElement)); + assertSame(bufferedImage, decorator.getScreenshot(webDriver, Set.of())); + } + + @Test + void shouldPrepareCoords() + { + ScrollbarHidingDecorator decorator = new ScrollbarHidingDecorator(strategy, Optional.empty(), + scrollbarHandler); + Coords coords = mock(Coords.class); + decorator.prepareCoords(Set.of(coords)); + verify(strategy).prepareCoords(Set.of(coords)); } } diff --git a/vividus-tests/src/main/resources/baselines/ipad-ignore-element.png b/vividus-tests/src/main/resources/baselines/ipad-ignore-element.png new file mode 100644 index 0000000000..87e23c9e92 Binary files /dev/null and b/vividus-tests/src/main/resources/baselines/ipad-ignore-element.png differ diff --git a/vividus-tests/src/main/resources/properties/environment/system/saucelabs/ipad/environment.properties b/vividus-tests/src/main/resources/properties/environment/system/saucelabs/ipad/environment.properties new file mode 100644 index 0000000000..be2b8879da --- /dev/null +++ b/vividus-tests/src/main/resources/properties/environment/system/saucelabs/ipad/environment.properties @@ -0,0 +1 @@ +selenium.grid.capabilities.deviceName=iPad (5th generation) Simulator diff --git a/vividus-tests/src/main/resources/properties/suite/system/ipad/suite.properties b/vividus-tests/src/main/resources/properties/suite/system/ipad/suite.properties new file mode 100644 index 0000000000..f68142d56b --- /dev/null +++ b/vividus-tests/src/main/resources/properties/suite/system/ipad/suite.properties @@ -0,0 +1 @@ +bdd.story-loader.batch-1.resource-include-patterns=HealthCheck.story,IPadVisualStepsTests.story diff --git a/vividus-tests/src/main/resources/story/system/IPadVisualStepsTests.story b/vividus-tests/src/main/resources/story/system/IPadVisualStepsTests.story new file mode 100644 index 0000000000..53b8247265 --- /dev/null +++ b/vividus-tests/src/main/resources/story/system/IPadVisualStepsTests.story @@ -0,0 +1,9 @@ +Scenario: Validate element is ignored when native header to cut is set +Meta: @layout tablet +Given I am on a page with the URL 'https://example.com' +When I COMPARE_AGAINST baseline with name `ipad-ignore-element` ignoring: +|ELEMENT | +|By.tagName(h1)| +using screenshot configuration: +|nativeHeaderToCut| +|71 |