diff --git a/bellatrix.core/pom.xml b/bellatrix.core/pom.xml index 667a658e..07e730aa 100644 --- a/bellatrix.core/pom.xml +++ b/bellatrix.core/pom.xml @@ -24,7 +24,7 @@ 1.0 - 4.11.0 + 4.27.0 8.3.0 7.7.0 5.9.2 diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java index dd8e5360..1b00e019 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java @@ -13,17 +13,27 @@ package solutions.bellatrix.core.utilities; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; +import java.util.Arrays; +import java.util.Optional; @SuppressWarnings("unchecked") public final class InstanceFactory { public static T create(Class classOf) { T obj = null; try { - obj = (T)classOf.getConstructors()[0].newInstance(); + Optional> constructor = Arrays.stream(classOf.getConstructors()) + .filter(c -> c.getParameterCount() == 0) + .findFirst(); + if (constructor.isPresent()) { + obj = (T)constructor.get().newInstance(); + } else { + throw new RuntimeException("No parameterless constructor found for type %s.".formatted(classOf.getName())); + } } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); + throw new RuntimeException("Failed to create an instance of type %s".formatted(classOf.getName()), e); } return obj; } diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/Anchor.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/Anchor.java index 27184c51..8bf7e447 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/Anchor.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/Anchor.java @@ -17,8 +17,9 @@ import solutions.bellatrix.web.components.contracts.*; public class Anchor extends WebComponent implements ComponentHtml, ComponentText, ComponentHref, ComponentTarget, ComponentRel { - public final static EventListener CLICKING = new EventListener<>(); - public final static EventListener CLICKED = new EventListener<>(); + public static final EventListener CLICKING = new EventListener<>(); + public static final EventListener CLICKED = new EventListener<>(); + //commit public void click() { defaultClick(CLICKING, CLICKED); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DeviceName.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DeviceName.java index 69e3ca2c..59f9045f 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DeviceName.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/DeviceName.java @@ -21,7 +21,10 @@ public enum DeviceName { MOBILE_S("MOBILE_S", 300, 873, false, 1), MOBILE_M("MOBILE_M", 320, 873, false, 1), MOBILE_L("MOBILE_L", 393, 873, false, 1), - TABLET("TABLET", 768, 873, false, 1), + TABLET_SMALL("TABLET_SMALL", 651, 873, false, 1), + TABLET("TABLET", 771, 873, false, 1), + SURFACE_PRO_7_L("Surface Pro 7 L",915,844,false,1), + SURFACE_PRO_7_M("Surface Pro 7 M",445,844,false,1), IPHONE_13_PRO_MOBILE("iPhone 13 Pro", 375, 667, true, 2, "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A366 Safari/600.1.4"), IPHONE_12_PRO_MOBILE("iPhone 12 Pro", 390, 844, true, 2, "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A366 Safari/600.1.4"), IPHONE_SE_MOBILE("iPhone SE", 375, 667, true, 2, "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A366 Safari/600.1.4"), 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 b6b4a388..a8c49f57 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 @@ -252,6 +252,7 @@ private static WebDriver initializeDriverRegularMode() { var chromeOptions = new ChromeOptions(); addDriverOptions(chromeOptions); addDriverCapabilities(chromeOptions); + chromeOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com"); chromeOptions.addArguments("--log-level=3","--remote-allow-origins=*", "--disable-search-engine-choice-screen"); chromeOptions.setAcceptInsecureCerts(true); chromeOptions.setCapability(CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR, UnexpectedAlertBehaviour.ACCEPT); @@ -266,9 +267,10 @@ private static WebDriver initializeDriverRegularMode() { var chromeHeadlessOptions = new ChromeOptions(); addDriverOptions(chromeHeadlessOptions); chromeHeadlessOptions.setAcceptInsecureCerts(true); + chromeHeadlessOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com"); chromeHeadlessOptions.addArguments("--log-level=3","--remote-allow-origins=*", "--disable-search-engine-choice-screen"); chromeHeadlessOptions.setCapability(CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR, UnexpectedAlertBehaviour.ACCEPT); - chromeHeadlessOptions.addArguments("--headless=old"); + chromeHeadlessOptions.addArguments("--headless=new"); System.setProperty("webdriver.chrome.silentOutput", "true"); if (shouldCaptureHttpTraffic) chromeHeadlessOptions.setProxy(proxyConfig); @@ -278,6 +280,7 @@ private static WebDriver initializeDriverRegularMode() { var chromeHeadlessOptions = new ChromeOptions(); addDriverOptions(chromeHeadlessOptions); chromeHeadlessOptions.setAcceptInsecureCerts(true); + chromeHeadlessOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com"); chromeHeadlessOptions.addArguments("--log-level=3","--remote-allow-origins=*", "--disable-search-engine-choice-screen"); chromeHeadlessOptions.setCapability(CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR, UnexpectedAlertBehaviour.ACCEPT); @@ -300,6 +303,7 @@ private static WebDriver initializeDriverRegularMode() { var firefoxOptions = new FirefoxOptions(); addDriverOptions(firefoxOptions); firefoxOptions.setAcceptInsecureCerts(true); + firefoxOptions.addPreference("network.proxy.no_proxies_on", "news-tracker-sockets.api.staging.sportal365.com"); if (shouldCaptureHttpTraffic) firefoxOptions.setProxy(proxyConfig); driver = new FirefoxDriver(firefoxOptions); } @@ -307,18 +311,21 @@ private static WebDriver initializeDriverRegularMode() { var firefoxHeadlessOptions = new FirefoxOptions(); addDriverOptions(firefoxHeadlessOptions); firefoxHeadlessOptions.setAcceptInsecureCerts(true); + firefoxHeadlessOptions.addPreference("network.proxy.no_proxies_on", "news-tracker-sockets.api.staging.sportal365.com"); firefoxHeadlessOptions.addArguments("--headless"); if (shouldCaptureHttpTraffic) firefoxHeadlessOptions.setProxy(proxyConfig); driver = new FirefoxDriver(firefoxHeadlessOptions); } case EDGE -> { var edgeOptions = new EdgeOptions(); + edgeOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com"); addDriverOptions(edgeOptions); if (shouldCaptureHttpTraffic) edgeOptions.setProxy(proxyConfig); driver = new EdgeDriver(edgeOptions); } case EDGE_HEADLESS -> { var edgeOptions = new EdgeOptions(); + edgeOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com"); edgeOptions.addArguments("--headless"); edgeOptions.addArguments("--disable-gpu"); addDriverOptions(edgeOptions); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/ProxyServer.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/ProxyServer.java index f9461bc6..8a8d681b 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/ProxyServer.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/ProxyServer.java @@ -14,12 +14,15 @@ package solutions.bellatrix.web.infrastructure; import com.google.gson.*; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; import lombok.SneakyThrows; import net.lightbody.bmp.BrowserMobProxyServer; import net.lightbody.bmp.core.har.HarEntry; import net.lightbody.bmp.proxy.CaptureType; import org.apache.http.HttpStatus; -import org.asynchttpclient.uri.Uri; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.http.HttpMethod; @@ -33,6 +36,7 @@ import java.io.IOException; import java.lang.reflect.Type; import java.net.ServerSocket; +import java.net.URI; import java.time.Duration; import java.time.LocalDateTime; import java.time.OffsetDateTime; @@ -52,10 +56,11 @@ public class ProxyServer { HttpStatus.SC_RESET_CONTENT, HttpStatus.SC_UNPROCESSABLE_ENTITY, HttpStatus.SC_PARTIAL_CONTENT, - HttpStatus.SC_MULTI_STATUS); + HttpStatus.SC_MULTI_STATUS + ); private static Gson gson; - + @SneakyThrows public static int init() { Log.info("Starting Proxy Service..."); @@ -65,11 +70,7 @@ public static int init() { PROXY_SERVER.get().enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT, CaptureType.REQUEST_HEADERS); PORT.set(port); Log.info("Proxy Service Started at Port %s".formatted(port)); - gson = new GsonBuilder() - .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter()) - .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()) - .registerTypeAdapterFactory(new EmptyObjectTypeAdapterFactory()) - .create(); + gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter()).registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()).registerTypeAdapterFactory(new EmptyObjectTypeAdapterFactory()).create(); return port; } @@ -102,9 +103,7 @@ public static List getCapturedEntries() { public static void assertNoErrorCodes() { var harEntries = PROXY_SERVER.get().getHar().getLog().getEntries(); - var areThereErrorCodes = harEntries.stream().anyMatch(r - -> r.getResponse().getStatus() > 400 - && r.getResponse().getStatus() < 599); + var areThereErrorCodes = harEntries.stream().anyMatch(r -> r.getResponse().getStatus() > 400 && r.getResponse().getStatus() < 599); Assert.assertFalse(areThereErrorCodes); } @@ -138,12 +137,12 @@ public static void waitForRequest(WebDriver driver, String requestPartialUrl, Ht try { webDriverWait.until(d -> { var harEntries = PROXY_SERVER.get().getHar().getLog().getEntries(); - var areRequestsMade = harEntries.stream().anyMatch(r -> r.getRequest().getUrl().contains(requestPartialUrl) && r.getRequest().getMethod().equals(httpMethod.toString())); - return areRequestsMade; + return harEntries.stream() + .anyMatch(r -> r.getRequest().getUrl().contains(requestPartialUrl) && + r.getRequest().getMethod().equals(httpMethod.toString())); }); - } - catch (TimeoutException exception){ + } catch (TimeoutException exception) { Log.error(String.format("The expected request with URL '%s' is not loaded!", requestPartialUrl)); } } @@ -156,18 +155,12 @@ public static void waitForResponse(WebDriver driver, String requestPartialUrl, H try { webDriverWait.until(d -> { var harEntries = PROXY_SERVER.get().getHar().getLog().getEntries(); - var isResponseReceived = harEntries.stream().anyMatch( - r -> (r.getRequest().getUrl().contains(requestPartialUrl) || r.getRequest().getUrl().contains(requestPartialUrl.replace("%20", "+"))) - && r.getRequest().getMethod().equals(httpMethod.toString()) - && successHttpStatusesList.contains(r.getResponse().getStatus()) - && (httpMethod.equals(HttpMethod.DELETE)? true : (r.getResponse().getContent().getText() != null && !r.getResponse().getContent().getText().isEmpty())) - ); + var isResponseReceived = harEntries.stream().anyMatch(r -> (r.getRequest().getUrl().contains(requestPartialUrl) || r.getRequest().getUrl().contains(requestPartialUrl.replace("%20", "+"))) && r.getRequest().getMethod().equals(httpMethod.toString()) && successHttpStatusesList.contains(r.getResponse().getStatus()) && (httpMethod.equals(HttpMethod.DELETE) ? true : (r.getResponse().getContent().getText() != null && !r.getResponse().getContent().getText().isEmpty()))); allHarEntries.clear(); allHarEntries.addAll(harEntries); return isResponseReceived; }); - } - catch (TimeoutException exception){ + } catch (TimeoutException exception) { String allUrlsString = getSimilarRequestsString(requestPartialUrl, allHarEntries); throw new RuntimeException(String.format("The expected response with request URL '%s' with method %s is not loaded! \r\nSimilar requests: %s", requestPartialUrl, httpMethod, allUrlsString)); @@ -175,23 +168,23 @@ public static void waitForResponse(WebDriver driver, String requestPartialUrl, H } private static String getSimilarRequestsString(String requestPartialUrl, List allHarEntries) { - try{ + try { ArrayList allUrls = new ArrayList<>(); allHarEntries.stream().forEach(e -> { - Uri uri = Uri.create(requestPartialUrl); - if(e.getRequest().getUrl().contains(uri.getHost()) || e.getRequest().getUrl().contains(requestPartialUrl)){ + + + URI uri = URI.create(requestPartialUrl); + if (e.getRequest().getUrl().contains(uri.getHost()) || e.getRequest().getUrl().contains(requestPartialUrl)) { allUrls.add(String.format("[%s]%s[%s]", e.getRequest().getMethod(), e.getRequest().getUrl(), e.getResponse().getStatusText())); } }); String allUrlsString = ""; - for (String url: - allUrls) { + for (String url : allUrls) { allUrlsString += url; allUrlsString += "\r\n"; } return allUrlsString; - } - catch (Exception ex){ + } catch (Exception ex) { ArrayList allUrls = new ArrayList<>(); allHarEntries.forEach(e -> allUrls.add(e.getRequest().getUrl())); return allUrls.toString(); @@ -200,9 +193,7 @@ private static String getSimilarRequestsString(String requestPartialUrl, List r.getResponse().getContent().getMimeType().startsWith("image") - && r.getResponse().getContent().getSize() > 40000); + var areThereLargeImages = harEntries.stream().anyMatch(r -> r.getResponse().getContent().getMimeType().startsWith("image") && r.getResponse().getContent().getSize() > 40000); Assert.assertFalse(areThereLargeImages); } @@ -223,21 +214,11 @@ private static int findFreePort() { } public static T getLastRequest(Class requestModelClass) { - return getCapturedEntries().stream() - .map(HarEntry::getRequest) - .filter(request -> request.getPostData() != null) - .map(request -> gson.fromJson(request.getPostData().getText(), requestModelClass)) - .reduce((first, second) -> second) - .orElse(null); + return getCapturedEntries().stream().map(HarEntry::getRequest).filter(request -> request.getPostData() != null).map(request -> gson.fromJson(request.getPostData().getText(), requestModelClass)).reduce((first, second) -> second).orElse(null); } public static T getLastResponse(Class responseModelClass) { - return getCapturedEntries().stream() - .map(HarEntry::getResponse) - .filter(response -> response.getContent() != null) - .map(response -> gson.fromJson(getDataObject(response.getContent().getText()), responseModelClass)) - .reduce((first, second) -> second) - .orElse(null); + return getCapturedEntries().stream().map(HarEntry::getResponse).filter(response -> response.getContent() != null).map(response -> gson.fromJson(getDataObject(response.getContent().getText()), responseModelClass)).reduce((first, second) -> second).orElse(null); } public static T getRequestByIndex(int index, Class requestModelClass) { @@ -255,46 +236,35 @@ public static T getResponseByIndex(int index, Class responseModelClass) { public static T getRequestByUrl(String url, String httpMethod, Class requestModelClass) { var harEntries = getCapturedEntries(); - var harEntry = harEntries.stream() - .filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)) - .findFirst() - .orElse(null); + var harEntry = harEntries.stream().filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)).findFirst().orElse(null); if (harEntry == null) { return null; } String json = harEntry.getRequest().getPostData().getText(); try { return gson.fromJson(json, requestModelClass); - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException("Error occurred while converting json to model. Json was: %s".formatted(json), e); } } public static T getRequestByUrl(String url, String httpMethod, Type modelType) { var harEntries = getCapturedEntries(); - var harEntry = harEntries.stream() - .filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)) - .findFirst() - .orElse(null); + var harEntry = harEntries.stream().filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)).findFirst().orElse(null); if (harEntry == null) { return null; } String json = harEntry.getRequest().getPostData().getText(); try { return gson.fromJson(json, modelType); - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException("Error occurred while converting json to model. Json was: %s".formatted(json), e); } } public static T getResponseByUrl(String url, String httpMethod, Class responseModelClass) { var harEntries = getCapturedEntries(); - var harEntry = harEntries.stream() - .filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)) - .findFirst() - .orElse(null); + var harEntry = harEntries.stream().filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)).findFirst().orElse(null); if (harEntry == null) { System.out.println("There is no match!"); return null; @@ -302,18 +272,14 @@ public static T getResponseByUrl(String url, String httpMethod, Class res String json = harEntry.getResponse().getContent().getText(); try { return gson.fromJson(getDataObject(json), responseModelClass); - } - catch (Exception ex){ + } catch (Exception ex) { throw new AssertionFailedError("Cannot get JSON body from the string: " + json + ". Error was: " + ex.getMessage()); } } public static T getResponseByUrl(String url, String httpMethod, Type responseModelType) { var harEntries = getCapturedEntries(); - var harEntry = harEntries.stream() - .filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)) - .findFirst() - .orElse(null); + var harEntry = harEntries.stream().filter(r -> r.getRequest().getUrl().contains(url) && r.getRequest().getMethod().equals(httpMethod)).findFirst().orElse(null); if (harEntry == null) { System.out.println("There is no match!"); return null; @@ -321,18 +287,17 @@ public static T getResponseByUrl(String url, String httpMethod, Type respons String json = harEntry.getResponse().getContent().getText(); try { return gson.fromJson(getDataObject(json), responseModelType); - } - catch (Exception ex) { + } catch (Exception ex) { throw new RuntimeException("Failed to Serialize Json to Object: \n Entity Type: %s\n Json was: %s".formatted(responseModelType.getTypeName(), json)); } } public static void blockRequestByUrl(String url, HttpMethod httpMethod) { - PROXY_SERVER.get().blacklistRequests(url,407, httpMethod.toString()); + PROXY_SERVER.get().blacklistRequests(url, 407, httpMethod.toString()); } public static void blockRequestByUrl(String url) { - PROXY_SERVER.get().blacklistRequests(url,407); + PROXY_SERVER.get().blacklistRequests(url, 407); } public static void clearblockRequestList() { @@ -346,21 +311,19 @@ private static String getDataObject(String jsonString) { boolean isObject = false; try { - jsonObject = (JsonObject) parser.parse(jsonString); + jsonObject = (JsonObject)parser.parse(jsonString); isObject = true; - } - catch (NullPointerException nullEx){ + } catch (NullPointerException nullEx) { throw new RuntimeException("JSON data is null. " + nullEx.getMessage()); - } - catch (Exception exception) { - jsonArray = (JsonArray) parser.parse(jsonString); + } catch (Exception exception) { + jsonArray = (JsonArray)parser.parse(jsonString); } JsonObject dataObject = null; JsonArray dataArray = null; if (isObject) { - if (jsonObject.has("data")){ - if (jsonObject.get("data").isJsonObject()){ + if (jsonObject.has("data")) { + if (jsonObject.get("data").isJsonObject()) { dataObject = jsonObject.getAsJsonObject("data"); } else { dataArray = jsonObject.getAsJsonArray("data"); @@ -372,14 +335,38 @@ private static String getDataObject(String jsonString) { dataArray = jsonArray.getAsJsonArray(); } - if (dataObject != null){ + if (dataObject != null) { return dataObject.toString(); - } - else if (dataArray != null) { + } else if (dataArray != null) { return dataArray.toString(); - } - else { + } else { return jsonString; } } -} + + /** + * This method should be used when request must not reach the server and response is immediately returned + * This implementation will wipe all the request headers and there is a chance to hit CORS or some other edge scenarios. + * If you need add headers or the response in order to mock the desired request's response + * + * @param url - the URL of the request + * @param jsonBody - the JSON body of the response + * @param statusCode - the status code of the response + */ + public static void addRequestFilterWithModifiedResponse(String url, String jsonBody, int statusCode, String... headers) { + PROXY_SERVER.get().addRequestFilter((request, contents, messageInfo) -> { + if (messageInfo.getOriginalUrl().contains(url)) { + final HttpResponse response = new DefaultFullHttpResponse( + request.getProtocolVersion(), + HttpResponseStatus.valueOf(statusCode), + Unpooled.copiedBuffer(jsonBody.getBytes())); + for (int i = 0; i < headers.length; i += 2) { + response.headers().add(headers[i], headers[i + 1]); + } + return response; + } else { + throw new RuntimeException("The request is not mocked. The URL is not matching the expected URL."); + } + }); + } +} \ No newline at end of file diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/pages/PageMap.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/pages/PageMap.java index 8f65abfb..a408c8da 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/pages/PageMap.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/pages/PageMap.java @@ -13,10 +13,24 @@ package solutions.bellatrix.web.pages; +import lombok.AllArgsConstructor; +import lombok.Getter; +import solutions.bellatrix.web.components.Div; import solutions.bellatrix.web.services.App; import solutions.bellatrix.web.services.ComponentCreateService; public abstract class PageMap { + + @Getter + @AllArgsConstructor + public enum ShadowHostType { + SIDEBAR("sidebar"), + TOP_BAR("top-bar"), + CMS_TNG("cms-tng"); + + private final String value; + } + public ComponentCreateService create() { return app().create(); } @@ -24,4 +38,8 @@ public ComponentCreateService create() { public App app() { return new App(); } -} + + public Div cmsShadowRoot(ShadowHostType hostType) { + return create().byXPath(Div.class, String.format("//div[@data-micro-app='%s']", hostType.getValue())); + } +} \ No newline at end of file diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/services/BrowserService.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/services/BrowserService.java index 12e1bd7f..c0e2485e 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/services/BrowserService.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/services/BrowserService.java @@ -147,6 +147,12 @@ public void scrollToBottom() { ((JavascriptExecutor)getWrappedDriver()).executeScript("window.scrollTo(0, document.body.scrollHeight)"); } + //ToDo hhristov 11/03/2026 - This method should be deleted once the CMS refactoring is finished + public void scrollToShellWindowBottom() { + ((JavascriptExecutor)getWrappedDriver()).executeScript("var c = document.querySelector('.shell__content > div');" + + " if (c) c.scrollTop = c.scrollHeight; else window.scrollTo(0, document.body.scrollHeight);"); + } + public void scrollToTop() { ((JavascriptExecutor)getWrappedDriver()).executeScript("window.scrollTo(0, 0)"); }