diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/plugins/EventListener.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/plugins/EventListener.java index c1eb0279..51a3cbae 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/plugins/EventListener.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/plugins/EventListener.java @@ -24,6 +24,10 @@ public void addListener(Consumer listener) { listeners.add(listener); } + public void removeListener(Consumer listener) { + listeners.remove(listener); + } + public void broadcast(TArgs args) { if (listeners.size() > 0) { listeners.forEach(x -> x.accept(args)); diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java index dd7d93b8..4676393a 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java @@ -22,22 +22,19 @@ // Based on http://neutrofoton.github.io/blog/2013/08/29/generic-singleton-pattern-in-java/ // Can be used inside App design pattern. @SuppressWarnings("unchecked") +@UtilityClass public class SingletonFactory { - private static final SingletonFactory SINGLETON_FACTORY = new SingletonFactory(); - - private final Map, Object> mapHolder = new HashMap<>(); - - private SingletonFactory() { - } + private static final ThreadLocal, Object>> mapHolder = ThreadLocal.withInitial(HashMap::new); @SneakyThrows public static T getInstance(Class classOf, Object... initargs) { try { - if (!SINGLETON_FACTORY.mapHolder.containsKey(classOf)) { + if (!mapHolder.get().containsKey(classOf)) { T obj = (T)classOf.getConstructors()[0].newInstance(initargs); - SINGLETON_FACTORY.mapHolder.put(classOf, obj); + register(obj); } - return (T)SINGLETON_FACTORY.mapHolder.get(classOf); + + return (T)mapHolder.get().get(classOf); } catch (Exception e) { Log.error("Failed to create instance of the object. Exception was: " + e); return null; @@ -45,10 +42,10 @@ public static T getInstance(Class classOf, Object... initargs) { } public static void register(T instance) { - SINGLETON_FACTORY.mapHolder.put(instance.getClass(), instance); + mapHolder.get().put(instance.getClass(), instance); } public static void register(Class classKey, T instance) { - SINGLETON_FACTORY.mapHolder.put(classKey, instance); + mapHolder.get().put(classKey, instance); } } diff --git a/bellatrix.addons.visual-regression-tracker/pom.xml b/bellatrix.plugins.visual-regression-tracker/pom.xml similarity index 95% rename from bellatrix.addons.visual-regression-tracker/pom.xml rename to bellatrix.plugins.visual-regression-tracker/pom.xml index d8516471..82eb7cc7 100644 --- a/bellatrix.addons.visual-regression-tracker/pom.xml +++ b/bellatrix.plugins.visual-regression-tracker/pom.xml @@ -9,7 +9,7 @@ 1.0-SNAPSHOT - bellatrix.addons.visual-regression-tracker + bellatrix.plugins.visual-regression-tracker diff --git a/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java b/bellatrix.plugins.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java similarity index 100% rename from bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java rename to bellatrix.plugins.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java diff --git a/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java b/bellatrix.plugins.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java similarity index 100% rename from bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java rename to bellatrix.plugins.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java index 814839f4..4b17d3f4 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java @@ -208,10 +208,6 @@ public String getAccessKey() { return getAttribute("accesskey"); } - public String getStyle() { - return getAttribute("style"); - } - public String getDir() { return getAttribute("dir"); } @@ -224,6 +220,7 @@ public String getHtmlClass() { return getAttribute("class"); } + @Override public String getAttribute(String name) { return getWrappedElement().getAttribute(name); } diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/Component.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/Component.java index 2c111043..75eedbd6 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/Component.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/Component.java @@ -21,4 +21,5 @@ public interface Component extends LayoutComponent { Class getComponentClass(); WebElement getWrappedElement(); FindStrategy getFindStrategy(); + String getAttribute(String attributeName); } diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/ComponentStyle.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/ComponentStyle.java index f5280cf1..a1fd26c8 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/ComponentStyle.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/contracts/ComponentStyle.java @@ -22,50 +22,39 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Objects; import java.util.function.Supplier; public interface ComponentStyle extends Component { - String getStyle(); + default String getStyle() { + return getAttribute("style"); + } + + default String getStyle(CssStyle style) { + return getWrappedElement().getCssValue(style.toString()); + } - @SneakyThrows default void validateStyleIs(String value) { ComponentValidator.defaultValidateAttributeIs((WebComponent)this, this::getStyle, value, "style"); } - @SneakyThrows default void validateStyleIsSet() { ComponentValidator.defaultValidateAttributeIsSet((WebComponent)this, this::getStyle, "style"); } - @SneakyThrows default void validateStyleNotSet() { ComponentValidator.defaultValidateAttributeNotSet((WebComponent)this, this::getStyle, "style"); } - @SneakyThrows default void validateStyleContains(String value) { ComponentValidator.defaultValidateAttributeContains((WebComponent)this, this::getStyle, value, "style"); } - @SneakyThrows default void validateStyleNotContains(String value) { ComponentValidator.defaultValidateAttributeNotContains((WebComponent)this, this::getStyle, value, "style"); } - default String getStyle(CssStyle style) { - var script = String.format("return window.getComputedStyle(arguments[0],null).getPropertyValue('%s');", style); - var result = new JavaScriptService().execute(script, (WebComponent) this); - - return result; - } - - @SneakyThrows default void validateStyle(CssStyle style, String expectedValue) { - try { - Method method = ComponentValidator.class.getDeclaredMethod("defaultValidateAttributeIs", WebComponent.class, Supplier.class, java.lang.String.class, java.lang.String.class); - method.invoke(SingletonFactory.getInstance(ComponentValidator.class), (WebComponent) this, (Supplier) () -> this.getStyle(style), expectedValue, java.lang.String.format("expected color should be %s", expectedValue)); - } catch (InvocationTargetException e) { - throw e.getCause(); - } + ComponentValidator.defaultValidateAttributeIs((WebComponent)this, () -> this.getStyle(style), expectedValue, style.toString()); } } diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/enums/CssStyle.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/enums/CssStyle.java index 7f5cf8c9..da1eddd5 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/enums/CssStyle.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/enums/CssStyle.java @@ -2,7 +2,26 @@ public enum CssStyle { BACKGROUND_COLOR("background-color"), - COLOR("color"); + BORDER_COLOR("border-color"), + COLOR("color"), + FONT_FAMILY("font-family"), + FONT_WEIGHT("font-weight"), + FONT_SIZE("font-size"), + TEXT_ALIGN("text-align"), + VERTICAL_ALIGN("vertical-align"), + LINE_HEIGHT("line-height"), + LETTER_SPACING("letter-spacing"), + MARGIN_TOP("margin-top"), + MARGIN_BOTTOM("margin-bottom"), + MARGIN_LEFT("margin-left"), + MARGIN_RIGHT("margin-right"), + PADDING_TOP("padding-top"), + PADDING_BOTTOM("padding-bottom"), + PADDING_LEFT("padding-left"), + PADDING_RIGHT("padding-right"), + POSITION("position"), + HEIGHT("height"), + WIDTH("width"); private final String style; diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/Browser.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/Browser.java index 2ff16eb7..ef2e0fd4 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/Browser.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/Browser.java @@ -22,11 +22,11 @@ public enum Browser { FIREFOX("firefox"), FIREFOX_HEADLESS("firefox_headless"), EDGE("edge"), - // EDGE_HEADLESS("edge"), // Unsupported by Selenium 3, Selenium 4 has support + EDGE_HEADLESS("edge_headless"), OPERA("opera"), SAFARI("safari"), - NOT_SET("not_set"), - INTERNET_EXPLORER("ie"); + INTERNET_EXPLORER("ie"), + NOT_SET("not_set"); private final String value; diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/BrowserLifecyclePlugin.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/BrowserLifecyclePlugin.java index e36a2211..550273ab 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/BrowserLifecyclePlugin.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/BrowserLifecyclePlugin.java @@ -139,32 +139,31 @@ private BrowserConfiguration getBrowserConfiguration(Method memberInfo) { } private BrowserConfiguration getExecutionBrowserMethodLevel(Method memberInfo) { - var executionBrowserAnnotation = (ExecutionBrowser)memberInfo.getDeclaredAnnotation(ExecutionBrowser.class); - if (executionBrowserAnnotation == null) { - return null; - } + if (!memberInfo.isAnnotationPresent(ExecutionBrowser.class)) return null; + var executionBrowserAnnotation = (ExecutionBrowser)memberInfo.getDeclaredAnnotation(ExecutionBrowser.class); return new BrowserConfiguration(executionBrowserAnnotation.browser(), executionBrowserAnnotation.deviceName(), executionBrowserAnnotation.lifecycle()); } - private BrowserConfiguration getExecutionBrowserClassLevel(Class type) { - var executionBrowserAnnotation = (ExecutionBrowser)type.getDeclaredAnnotation(ExecutionBrowser.class); + private BrowserConfiguration getExecutionBrowserClassLevel(Class clazz) { + var browser = Browser.fromText(SecretsResolver.getSecret(ConfigurationService.get(WebSettings.class).getDefaultBrowser())); + var lifecycle = Lifecycle.fromText(ConfigurationService.get(WebSettings.class).getDefaultLifeCycle()); + var width = ConfigurationService.get(WebSettings.class).getDefaultBrowserWidth(); + var height = ConfigurationService.get(WebSettings.class).getDefaultBrowserHeight(); - var defaultBrowser = Browser.fromText(SecretsResolver.getSecret(ConfigurationService.get(WebSettings.class).getDefaultBrowser())); - var defaultLifecycle = Lifecycle.fromText(ConfigurationService.get(WebSettings.class).getDefaultLifeCycle()); - var defaultWidth = ConfigurationService.get(WebSettings.class).getDefaultBrowserWidth(); - var defaultHeight = ConfigurationService.get(WebSettings.class).getDefaultBrowserHeight(); + if (clazz.isAnnotationPresent(ExecutionBrowser.class)) { + var executionBrowserAnnotation = clazz.getDeclaredAnnotation(ExecutionBrowser.class); - var finalBrowser = executionBrowserAnnotation.browser() != Browser.NOT_SET && executionBrowserAnnotation.browser() != defaultBrowser ? executionBrowserAnnotation.browser() : defaultBrowser; - var finalLifecycle = executionBrowserAnnotation.lifecycle() != defaultLifecycle ? executionBrowserAnnotation.lifecycle() : defaultLifecycle; - var finalWidth = executionBrowserAnnotation.width() != 0 ? executionBrowserAnnotation.width() : defaultWidth; - var finalHeight = executionBrowserAnnotation.height() != 0 ? executionBrowserAnnotation.height() : defaultHeight; + browser = executionBrowserAnnotation.browser() != Browser.NOT_SET && executionBrowserAnnotation.browser() != browser ? executionBrowserAnnotation.browser() : browser; + lifecycle = executionBrowserAnnotation.lifecycle() != lifecycle ? executionBrowserAnnotation.lifecycle() : lifecycle; + width = executionBrowserAnnotation.width() != 0 ? executionBrowserAnnotation.width() : width; + height = executionBrowserAnnotation.height() != 0 ? executionBrowserAnnotation.height() : height; - if (executionBrowserAnnotation.browser() == Browser.CHROME_MOBILE) { - return new BrowserConfiguration(executionBrowserAnnotation.deviceName(), finalLifecycle, type.getName()); - } - else { - return new BrowserConfiguration(finalBrowser, finalLifecycle, finalWidth, finalHeight); + if (executionBrowserAnnotation.browser() == Browser.CHROME_MOBILE) { + return new BrowserConfiguration(executionBrowserAnnotation.deviceName(), lifecycle, clazz.getName()); + } } + + return new BrowserConfiguration(browser, lifecycle, width, height); } } diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DriverService.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DriverService.java index 6c443a3e..0dcb56dd 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DriverService.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DriverService.java @@ -139,6 +139,7 @@ private static WebDriver initializeDriverCloudGridMode(GridSettings gridSettings caps.setCapability(ChromeOptions.CAPABILITY, firefoxOptions); break; } + case EDGE_HEADLESS: case EDGE: { var edgeOptions = new EdgeOptions(); caps.setCapability(ChromeOptions.CAPABILITY, edgeOptions); @@ -201,6 +202,7 @@ private static WebDriver initializeDriverGridMode(GridSettings gridSettings) { caps.setCapability(ChromeOptions.CAPABILITY, firefoxOptions); break; } + case EDGE_HEADLESS: case EDGE: { var edgeOptions = new EdgeOptions(); addGridOptions(edgeOptions, gridSettings); @@ -310,6 +312,14 @@ private static WebDriver initializeDriverRegularMode() { if (shouldCaptureHttpTraffic) edgeOptions.setProxy(proxyConfig); driver = new EdgeDriver(edgeOptions); } + case EDGE_HEADLESS -> { + var edgeOptions = new EdgeOptions(); + edgeOptions.addArguments("--headless"); + edgeOptions.addArguments("--disable-gpu"); + addDriverOptions(edgeOptions); + if (shouldCaptureHttpTraffic) edgeOptions.setProxy(proxyConfig); + driver = new EdgeDriver(edgeOptions); + } case SAFARI -> { System.setProperty("webdriver.safari.driver", "/usr/bin/safaridriver"); var safariOptions = new SafariOptions(); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/services/App.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/services/App.java index 46c49863..5eb6a63a 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/services/App.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/services/App.java @@ -22,31 +22,31 @@ public class App implements AutoCloseable { private boolean disposed = false; public NavigationService navigate() { - return new NavigationService(); + return SingletonFactory.getInstance(NavigationService.class); } public BrowserService browser() { - return new BrowserService(); + return SingletonFactory.getInstance(BrowserService.class); } public CookiesService cookies() { - return new CookiesService(); + return SingletonFactory.getInstance(CookiesService.class); } public DialogService dialogs() { - return new DialogService(); + return SingletonFactory.getInstance(DialogService.class); } public JavaScriptService script() { - return new JavaScriptService(); + return SingletonFactory.getInstance(JavaScriptService.class); } public ComponentCreateService create() { - return new ComponentCreateService(); + return SingletonFactory.getInstance(ComponentCreateService.class); } public ComponentWaitService waitFor() { - return new ComponentWaitService(); + return SingletonFactory.getInstance(ComponentWaitService.class); } public void addDriverOptions(String key, String value) { diff --git a/pom.xml b/pom.xml index 52b2847b..a8a1c0a4 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ bellatrix.plugins.screenshots bellatrix.plugins.video bellatrix.plugins.jira.zephyr - bellatrix.addons.visual-regression-tracker + bellatrix.plugins.visual-regression-tracker bellatrix.web bellatrix.playwright bellatrix.desktop