Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public void addListener(Consumer<TArgs> listener) {
listeners.add(listener);
}

public void removeListener(Consumer<TArgs> listener) {
listeners.remove(listener);
}

public void broadcast(TArgs args) {
if (listeners.size() > 0) {
listeners.forEach(x -> x.accept(args));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,30 @@
// 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<Class<?>, Object> mapHolder = new HashMap<>();

private SingletonFactory() {
}
private static final ThreadLocal<Map<Class<?>, Object>> mapHolder = ThreadLocal.withInitial(HashMap::new);

@SneakyThrows
public static <T> T getInstance(Class<T> 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;
}
}

public static <T> void register(T instance) {
SINGLETON_FACTORY.mapHolder.put(instance.getClass(), instance);
mapHolder.get().put(instance.getClass(), instance);
}

public static <T> void register(Class<?> classKey, T instance) {
SINGLETON_FACTORY.mapHolder.put(classKey, instance);
mapHolder.get().put(classKey, instance);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<version>1.0-SNAPSHOT</version>
</parent>

<artifactId>bellatrix.addons.visual-regression-tracker</artifactId>
<artifactId>bellatrix.plugins.visual-regression-tracker</artifactId>

<repositories>
<repository>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,6 @@ public String getAccessKey() {
return getAttribute("accesskey");
}

public String getStyle() {
return getAttribute("style");
}

public String getDir() {
return getAttribute("dir");
}
Expand All @@ -224,6 +220,7 @@ public String getHtmlClass() {
return getAttribute("class");
}

@Override
public String getAttribute(String name) {
return getWrappedElement().getAttribute(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ public interface Component extends LayoutComponent {
Class<?> getComponentClass();
WebElement getWrappedElement();
FindStrategy getFindStrategy();
String getAttribute(String attributeName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Object>) () -> 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<module>bellatrix.plugins.screenshots</module>
<module>bellatrix.plugins.video</module>
<module>bellatrix.plugins.jira.zephyr</module>
<module>bellatrix.addons.visual-regression-tracker</module>
<module>bellatrix.plugins.visual-regression-tracker</module>
<module>bellatrix.web</module>
<module>bellatrix.playwright</module>
<module>bellatrix.desktop</module>
Expand Down