From 7220112f46b684eec55cd6e920ac402bf3e43ea3 Mon Sep 17 00:00:00 2001 From: Ivan Radnev Date: Tue, 10 Dec 2024 16:24:33 +0200 Subject: [PATCH 01/27] Added error handling in browser shutdown method --- .../web/infrastructure/BrowserLifecyclePlugin.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 59a86f27..3d754b14 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 @@ -18,6 +18,7 @@ import solutions.bellatrix.core.plugins.TestResult; import solutions.bellatrix.core.utilities.Log; import solutions.bellatrix.core.utilities.SecretsResolver; +import solutions.bellatrix.core.utilities.Wait; import solutions.bellatrix.web.configuration.WebSettings; import java.lang.reflect.Method; @@ -83,8 +84,14 @@ public void postAfterTest(TestResult testResult, Method memberInfo, Throwable fa } private void shutdownBrowser() { - DriverService.close(); - PREVIOUS_BROWSER_CONFIGURATION.remove(); + try { + DriverService.close(); + } catch (Exception ex) { + PREVIOUS_BROWSER_CONFIGURATION.remove(); + Log.error("Failed to close the browser due to error: %s. Trying again...".formatted(ex.getMessage())); + Wait.forMilliseconds(100); + DriverService.close(); + } } private void startBrowser() { From cd15743dd0890cc5f54f1f084a4c48bea23b2452 Mon Sep 17 00:00:00 2001 From: Ivan Radnev Date: Wed, 11 Dec 2024 13:16:34 +0200 Subject: [PATCH 02/27] Rearrange final and static keywords --- .../main/java/solutions/bellatrix/web/components/Anchor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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..485f275f 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,8 @@ 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<>(); public void click() { defaultClick(CLICKING, CLICKED); From 5ab905376b20aeb6c34ba3aa4770fb9121433b4e Mon Sep 17 00:00:00 2001 From: Ivan Radnev Date: Wed, 11 Dec 2024 13:25:55 +0200 Subject: [PATCH 03/27] Revert "Added error handling in browser shutdown method" This reverts commit 7220112f46b684eec55cd6e920ac402bf3e43ea3. --- .../web/infrastructure/BrowserLifecyclePlugin.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) 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 3d754b14..59a86f27 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 @@ -18,7 +18,6 @@ import solutions.bellatrix.core.plugins.TestResult; import solutions.bellatrix.core.utilities.Log; import solutions.bellatrix.core.utilities.SecretsResolver; -import solutions.bellatrix.core.utilities.Wait; import solutions.bellatrix.web.configuration.WebSettings; import java.lang.reflect.Method; @@ -84,14 +83,8 @@ public void postAfterTest(TestResult testResult, Method memberInfo, Throwable fa } private void shutdownBrowser() { - try { - DriverService.close(); - } catch (Exception ex) { - PREVIOUS_BROWSER_CONFIGURATION.remove(); - Log.error("Failed to close the browser due to error: %s. Trying again...".formatted(ex.getMessage())); - Wait.forMilliseconds(100); - DriverService.close(); - } + DriverService.close(); + PREVIOUS_BROWSER_CONFIGURATION.remove(); } private void startBrowser() { From 239a4a9d241da332bbc90316a29b9524a1951e20 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Thu, 12 Dec 2024 11:09:20 +0200 Subject: [PATCH 04/27] update selenium version to latest --- bellatrix.core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 2c6196b773c30cec10378b335c20f6df58135866 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Thu, 12 Dec 2024 12:11:49 +0200 Subject: [PATCH 05/27] change usage of URI object --- .../web/infrastructure/ProxyServer.java | 128 +++++------------- 1 file changed, 37 insertions(+), 91 deletions(-) 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..f3411936 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 @@ -19,7 +19,6 @@ 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 +32,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; @@ -43,19 +43,10 @@ public class ProxyServer { private static final ThreadLocal PROXY_SERVER = ThreadLocal.withInitial(BrowserMobProxyServer::new); private static final ThreadLocal PORT = new ThreadLocal<>(); - private static final List successHttpStatusesList = Arrays.asList( - HttpStatus.SC_OK, - HttpStatus.SC_CREATED, - HttpStatus.SC_ACCEPTED, - HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, - HttpStatus.SC_NO_CONTENT, - HttpStatus.SC_RESET_CONTENT, - HttpStatus.SC_UNPROCESSABLE_ENTITY, - HttpStatus.SC_PARTIAL_CONTENT, - HttpStatus.SC_MULTI_STATUS); + private static final List successHttpStatusesList = Arrays.asList(HttpStatus.SC_OK, HttpStatus.SC_CREATED, HttpStatus.SC_ACCEPTED, HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_RESET_CONTENT, HttpStatus.SC_UNPROCESSABLE_ENTITY, HttpStatus.SC_PARTIAL_CONTENT, HttpStatus.SC_MULTI_STATUS); private static Gson gson; - + @SneakyThrows public static int init() { Log.info("Starting Proxy Service..."); @@ -65,11 +56,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 +89,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); } @@ -142,8 +127,7 @@ public static void waitForRequest(WebDriver driver, String requestPartialUrl, Ht return areRequestsMade; }); - } - catch (TimeoutException exception){ + } catch (TimeoutException exception) { Log.error(String.format("The expected request with URL '%s' is not loaded!", requestPartialUrl)); } } @@ -156,18 +140,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 +153,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 +178,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 +199,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 +221,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 +257,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 +272,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 +296,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,13 +320,11 @@ 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; } } From 9954e9424ce60faa8df21f7996f9511315e436f3 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Thu, 19 Dec 2024 10:11:29 +0200 Subject: [PATCH 06/27] Fix create instance for no args constructor in InstanceFactory --- .../bellatrix/core/utilities/InstanceFactory.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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; } From f8fc544e2f9fbc52952bd0f7ef4431f5d02f7c36 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Wed, 29 Jan 2025 10:16:07 +0200 Subject: [PATCH 07/27] replace --headless=old with --headless=new for executing tests in headless mode --- .../solutions/bellatrix/web/infrastructure/DriverService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..24f66b04 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 @@ -268,7 +268,7 @@ private static WebDriver initializeDriverRegularMode() { chromeHeadlessOptions.setAcceptInsecureCerts(true); 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); From 9ed7926eaca32f97829c9fbbbf9b04c2e51203e3 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Wed, 29 Jan 2025 15:52:19 +0200 Subject: [PATCH 08/27] Add method for mocking response for specific url --- .../web/infrastructure/ProxyServer.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) 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 f3411936..49d133de 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,6 +14,10 @@ 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; @@ -328,4 +332,30 @@ private static String getDataObject(String jsonString) { 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.protocolVersion(), + 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."); + } + }); + } } From b11a0e63c82d80495ec91f0095bc8cbcd977c8f6 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Wed, 29 Jan 2025 17:22:59 +0200 Subject: [PATCH 09/27] Revert "Add method for mocking response for specific url" This reverts commit 9ed7926eaca32f97829c9fbbbf9b04c2e51203e3. --- .../web/infrastructure/ProxyServer.java | 30 ------------------- 1 file changed, 30 deletions(-) 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 49d133de..f3411936 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,10 +14,6 @@ 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; @@ -332,30 +328,4 @@ private static String getDataObject(String jsonString) { 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.protocolVersion(), - 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."); - } - }); - } } From 17abb534675e621ba80a90698586c2d296517996 Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Wed, 29 Jan 2025 17:37:19 +0200 Subject: [PATCH 10/27] Refactor inline and fix warning --- .../web/infrastructure/ProxyServer.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) 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 f3411936..d9f160ee 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 @@ -43,7 +43,17 @@ public class ProxyServer { private static final ThreadLocal PROXY_SERVER = ThreadLocal.withInitial(BrowserMobProxyServer::new); private static final ThreadLocal PORT = new ThreadLocal<>(); - private static final List successHttpStatusesList = Arrays.asList(HttpStatus.SC_OK, HttpStatus.SC_CREATED, HttpStatus.SC_ACCEPTED, HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_RESET_CONTENT, HttpStatus.SC_UNPROCESSABLE_ENTITY, HttpStatus.SC_PARTIAL_CONTENT, HttpStatus.SC_MULTI_STATUS); + private static final List successHttpStatusesList = Arrays.asList( + HttpStatus.SC_OK, + HttpStatus.SC_CREATED, + HttpStatus.SC_ACCEPTED, + HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, + HttpStatus.SC_NO_CONTENT, + HttpStatus.SC_RESET_CONTENT, + HttpStatus.SC_UNPROCESSABLE_ENTITY, + HttpStatus.SC_PARTIAL_CONTENT, + HttpStatus.SC_MULTI_STATUS + ); private static Gson gson; @@ -123,9 +133,10 @@ 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) { Log.error(String.format("The expected request with URL '%s' is not loaded!", requestPartialUrl)); From 89e42ca9053c766e7709b380fbc5a45fa0419c5c Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Wed, 29 Jan 2025 18:17:59 +0200 Subject: [PATCH 11/27] Add method for mock specific request by URL --- .../web/infrastructure/ProxyServer.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) 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 d9f160ee..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,6 +14,10 @@ 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; @@ -339,4 +343,30 @@ private static String getDataObject(String jsonString) { 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 From fd60b67514098098670a9a066b3d3d8118fb75b3 Mon Sep 17 00:00:00 2001 From: Boris Date: Thu, 20 Feb 2025 14:51:51 +0200 Subject: [PATCH 12/27] Adding new device name with specific screen resolution --- .../java/solutions/bellatrix/web/infrastructure/DeviceName.java | 2 ++ 1 file changed, 2 insertions(+) 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..6a14d6be 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 @@ -22,6 +22,8 @@ public enum DeviceName { MOBILE_M("MOBILE_M", 320, 873, false, 1), MOBILE_L("MOBILE_L", 393, 873, false, 1), TABLET("TABLET", 768, 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"), From aba847bf7ef35cbd2ce1f59fe437bfd181f7a0e4 Mon Sep 17 00:00:00 2001 From: Hristo Date: Tue, 8 Apr 2025 08:40:08 +0300 Subject: [PATCH 13/27] commit --- .../src/main/java/solutions/bellatrix/web/components/Anchor.java | 1 + 1 file changed, 1 insertion(+) 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 485f275f..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 @@ -19,6 +19,7 @@ public class Anchor extends WebComponent implements ComponentHtml, ComponentText, ComponentHref, ComponentTarget, ComponentRel { public static final EventListener CLICKING = new EventListener<>(); public static final EventListener CLICKED = new EventListener<>(); + //commit public void click() { defaultClick(CLICKING, CLICKED); From fa6f06e070e10c66143a9f5919681064a21dece8 Mon Sep 17 00:00:00 2001 From: Hristo Date: Tue, 21 Oct 2025 16:21:34 +0300 Subject: [PATCH 14/27] add --proxy-bypass-list=* to Chrome and headless options --- .../solutions/bellatrix/web/infrastructure/DriverService.java | 2 ++ 1 file changed, 2 insertions(+) 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 24f66b04..8c5c87a8 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=*"); 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,6 +267,7 @@ private static WebDriver initializeDriverRegularMode() { var chromeHeadlessOptions = new ChromeOptions(); addDriverOptions(chromeHeadlessOptions); chromeHeadlessOptions.setAcceptInsecureCerts(true); + chromeHeadlessOptions.addArguments("--proxy-bypass-list=*"); chromeHeadlessOptions.addArguments("--log-level=3","--remote-allow-origins=*", "--disable-search-engine-choice-screen"); chromeHeadlessOptions.setCapability(CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR, UnexpectedAlertBehaviour.ACCEPT); chromeHeadlessOptions.addArguments("--headless=new"); From 68582e1963ebb28259b20fa39ee356b0e6e0835f Mon Sep 17 00:00:00 2001 From: Hristo Date: Wed, 22 Oct 2025 17:56:30 +0300 Subject: [PATCH 15/27] remove 'proxy-bypass-list' argument from browser configuration --- .../solutions/bellatrix/web/infrastructure/DriverService.java | 2 -- 1 file changed, 2 deletions(-) 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 8c5c87a8..24f66b04 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,7 +252,6 @@ private static WebDriver initializeDriverRegularMode() { var chromeOptions = new ChromeOptions(); addDriverOptions(chromeOptions); addDriverCapabilities(chromeOptions); - chromeOptions.addArguments("--proxy-bypass-list=*"); chromeOptions.addArguments("--log-level=3","--remote-allow-origins=*", "--disable-search-engine-choice-screen"); chromeOptions.setAcceptInsecureCerts(true); chromeOptions.setCapability(CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR, UnexpectedAlertBehaviour.ACCEPT); @@ -267,7 +266,6 @@ private static WebDriver initializeDriverRegularMode() { var chromeHeadlessOptions = new ChromeOptions(); addDriverOptions(chromeHeadlessOptions); chromeHeadlessOptions.setAcceptInsecureCerts(true); - chromeHeadlessOptions.addArguments("--proxy-bypass-list=*"); chromeHeadlessOptions.addArguments("--log-level=3","--remote-allow-origins=*", "--disable-search-engine-choice-screen"); chromeHeadlessOptions.setCapability(CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR, UnexpectedAlertBehaviour.ACCEPT); chromeHeadlessOptions.addArguments("--headless=new"); From c223e2a6bb1d5f51dc15777f40e8c36750ec1565 Mon Sep 17 00:00:00 2001 From: Hristo Date: Thu, 23 Oct 2025 11:38:04 +0300 Subject: [PATCH 16/27] add bypass proxy in browser configuration to avoid WebSocket handshake failures --- .../bellatrix/web/infrastructure/DriverService.java | 7 +++++++ 1 file changed, 7 insertions(+) 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 24f66b04..ec2386ea 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,6 +267,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); chromeHeadlessOptions.addArguments("--headless=new"); @@ -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); @@ -299,6 +302,7 @@ private static WebDriver initializeDriverRegularMode() { case FIREFOX -> { var firefoxOptions = new FirefoxOptions(); addDriverOptions(firefoxOptions); + firefoxOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com;"); firefoxOptions.setAcceptInsecureCerts(true); 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.addArguments("--proxy-bypass-list=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); From 818afd6542ea3df916e98dade6e7cef7342c50d4 Mon Sep 17 00:00:00 2001 From: Hristo Date: Fri, 24 Oct 2025 16:46:23 +0300 Subject: [PATCH 17/27] add bypass proxy in browser configuration to avoid WebSocket handshake failures --- .../web/infrastructure/DriverService.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 ec2386ea..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,7 +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("--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); @@ -267,7 +267,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("--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=new"); @@ -280,7 +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("--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); @@ -302,8 +302,8 @@ private static WebDriver initializeDriverRegularMode() { case FIREFOX -> { var firefoxOptions = new FirefoxOptions(); addDriverOptions(firefoxOptions); - firefoxOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com;"); 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); } @@ -311,21 +311,21 @@ private static WebDriver initializeDriverRegularMode() { var firefoxHeadlessOptions = new FirefoxOptions(); addDriverOptions(firefoxHeadlessOptions); firefoxHeadlessOptions.setAcceptInsecureCerts(true); - firefoxHeadlessOptions.addArguments("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com;"); + 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;"); + 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("--proxy-bypass-list=news-tracker-sockets.api.staging.sportal365.com"); edgeOptions.addArguments("--headless"); edgeOptions.addArguments("--disable-gpu"); addDriverOptions(edgeOptions); From 6cb61e30518bd25357bace3f16f893fb5dc6e3d6 Mon Sep 17 00:00:00 2001 From: ivans Date: Wed, 12 Nov 2025 13:00:04 +0200 Subject: [PATCH 18/27] visual test maintenance - breakpoints updated, removing default style of 8px margin for more accurate visual tests --- .../solutions/bellatrix/web/infrastructure/DeviceName.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 6a14d6be..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,8 @@ 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"), From 53217255f777b2f984aa22e1ce6f218ed718e5c7 Mon Sep 17 00:00:00 2001 From: Hristo Date: Wed, 4 Mar 2026 15:24:02 +0200 Subject: [PATCH 19/27] add shadowRoot for CMS tests --- .../main/java/solutions/bellatrix/web/pages/PageMap.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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..db687cec 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,6 +13,7 @@ package solutions.bellatrix.web.pages; +import solutions.bellatrix.web.components.Div; import solutions.bellatrix.web.services.App; import solutions.bellatrix.web.services.ComponentCreateService; @@ -24,4 +25,8 @@ public ComponentCreateService create() { public App app() { return new App(); } -} + + public Div cmsShadowHost() { + return create().byXPath(Div.class, "//div[@data-shadow-host='sidebar']"); + } +} \ No newline at end of file From 8fd89c7b2986a6a110317533219fa7563179f37a Mon Sep 17 00:00:00 2001 From: Hristo Date: Wed, 4 Mar 2026 16:45:44 +0200 Subject: [PATCH 20/27] add shadow root method for CMS --- .../src/main/java/solutions/bellatrix/web/pages/PageMap.java | 1 + 1 file changed, 1 insertion(+) 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 db687cec..1f7253d9 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 @@ -29,4 +29,5 @@ public App app() { public Div cmsShadowHost() { return create().byXPath(Div.class, "//div[@data-shadow-host='sidebar']"); } + } \ No newline at end of file From 87eda235ea0498ec743c1b51012d8a583b331df7 Mon Sep 17 00:00:00 2001 From: Hristo Date: Thu, 5 Mar 2026 16:16:10 +0200 Subject: [PATCH 21/27] update cmsShadowHost() --- .../src/main/java/solutions/bellatrix/web/pages/PageMap.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 1f7253d9..5570c216 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 @@ -27,7 +27,6 @@ public App app() { } public Div cmsShadowHost() { - return create().byXPath(Div.class, "//div[@data-shadow-host='sidebar']"); + return create().byXPath(Div.class, "//div[@data-shadow-host='sidebar' or @data-shadow-host='top-bar']"); } - } \ No newline at end of file From 6cee063bd82f611f6769b9810758c086a54b9393 Mon Sep 17 00:00:00 2001 From: Hristo Date: Thu, 5 Mar 2026 16:28:11 +0200 Subject: [PATCH 22/27] update cmsShadowHost() --- .../src/main/java/solutions/bellatrix/web/pages/PageMap.java | 1 + 1 file changed, 1 insertion(+) 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 5570c216..d73a014d 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 @@ -29,4 +29,5 @@ public App app() { public Div cmsShadowHost() { return create().byXPath(Div.class, "//div[@data-shadow-host='sidebar' or @data-shadow-host='top-bar']"); } + } \ No newline at end of file From a043a63a4e26f1b4f5c77fe95f8e4bea693bbd2f Mon Sep 17 00:00:00 2001 From: Hristo Date: Fri, 6 Mar 2026 16:17:08 +0200 Subject: [PATCH 23/27] add shadowHosType and use getShadowRoot from bellatrix --- .../bellatrix/web/pages/PageMap.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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 d73a014d..5d942262 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,11 +13,24 @@ package solutions.bellatrix.web.pages; +import lombok.AllArgsConstructor; +import lombok.Getter; import solutions.bellatrix.web.components.Div; +import solutions.bellatrix.web.components.shadowdom.ShadowRoot; 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"); + + private final String value; + } + public ComponentCreateService create() { return app().create(); } @@ -26,8 +39,8 @@ public App app() { return new App(); } - public Div cmsShadowHost() { - return create().byXPath(Div.class, "//div[@data-shadow-host='sidebar' or @data-shadow-host='top-bar']"); + public ShadowRoot cmsShadowRoot(ShadowHostType hostType) { + return create().byXPath(Div.class, String.format("//div[@data-shadow-host='%s']", hostType.getValue())) + .getShadowRoot(); } - } \ No newline at end of file From 614226fae61c28a237a479720a8aa65e492c719f Mon Sep 17 00:00:00 2001 From: Hristo Date: Wed, 11 Mar 2026 15:42:02 +0200 Subject: [PATCH 24/27] add scrollToShellWindowBottom in bellatrix framework --- .../solutions/bellatrix/web/components/WebComponent.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 fd57b34c..836b1d7d 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 @@ -144,6 +144,12 @@ public void scrollToBottom() { scrollToVisible(getWrappedElement(), false, ScrollPosition.END); } + //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 setAttribute(String name, String value) { SETTING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(this, value, name)); javaScriptService.execute(String.format("arguments[0].setAttribute('%s', '%s');", name, value), this); From 70843f52ea69f81875af4d1c71b6a8759f6ea6aa Mon Sep 17 00:00:00 2001 From: Hristo Date: Wed, 11 Mar 2026 15:57:55 +0200 Subject: [PATCH 25/27] change the location from WebComponent to BrowserService class --- .../solutions/bellatrix/web/components/WebComponent.java | 6 ------ .../solutions/bellatrix/web/services/BrowserService.java | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) 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 836b1d7d..fd57b34c 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 @@ -144,12 +144,6 @@ public void scrollToBottom() { scrollToVisible(getWrappedElement(), false, ScrollPosition.END); } - //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 setAttribute(String name, String value) { SETTING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(this, value, name)); javaScriptService.execute(String.format("arguments[0].setAttribute('%s', '%s');", name, value), this); 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)"); } From a03877950083df75b2be6b58aa440a202d4142d1 Mon Sep 17 00:00:00 2001 From: Hristo Date: Fri, 17 Apr 2026 08:49:09 +0300 Subject: [PATCH 26/27] add cms tng to shadow host --- .../src/main/java/solutions/bellatrix/web/pages/PageMap.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 5d942262..4ceb9bc6 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 @@ -26,7 +26,8 @@ public abstract class PageMap { @AllArgsConstructor public enum ShadowHostType { SIDEBAR("sidebar"), - TOP_BAR("top-bar"); + TOP_BAR("top-bar"), + CMS_TNG("cms-tng"); private final String value; } From f1910a242a9b7b01d535bbedb88c6fd1beb6d345 Mon Sep 17 00:00:00 2001 From: Ivan Radnev Date: Thu, 27 Aug 2026 13:51:20 +0300 Subject: [PATCH 27/27] Update CMS micro-app locator after Shadow DOM removal PLT-2665 removed the Shadow DOM boundary from apps/shell and renamed data-shadow-host to data-micro-app. PageMap.cmsShadowRoot now queries the new attribute and returns the container Div directly, since there is no shadow root left to unwrap. --- .../main/java/solutions/bellatrix/web/pages/PageMap.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 4ceb9bc6..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 @@ -16,7 +16,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import solutions.bellatrix.web.components.Div; -import solutions.bellatrix.web.components.shadowdom.ShadowRoot; import solutions.bellatrix.web.services.App; import solutions.bellatrix.web.services.ComponentCreateService; @@ -40,8 +39,7 @@ public App app() { return new App(); } - public ShadowRoot cmsShadowRoot(ShadowHostType hostType) { - return create().byXPath(Div.class, String.format("//div[@data-shadow-host='%s']", hostType.getValue())) - .getShadowRoot(); + 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