diff --git a/bellatrix.addons.visual-regression-tracker/pom.xml b/bellatrix.addons.visual-regression-tracker/pom.xml
new file mode 100644
index 00000000..d8516471
--- /dev/null
+++ b/bellatrix.addons.visual-regression-tracker/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+
+ solutions.bellatrix
+ bellatrix
+ 1.0-SNAPSHOT
+
+
+ bellatrix.addons.visual-regression-tracker
+
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
+
+
+ solutions.bellatrix
+ bellatrix.core
+ 1.0
+
+
+ solutions.bellatrix
+ bellatrix.plugins.screenshots
+ 1.0
+
+
+ com.github.Visual-Regression-Tracker
+ sdk-java
+ 5.2.1
+
+
+
+
+ 19
+ 19
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java b/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java
new file mode 100644
index 00000000..b4a9142f
--- /dev/null
+++ b/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTracker.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2024 Automate The Planet Ltd.
+ * Author: Miriam Kyoseva
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package solutions.bellatrix.plugins.vrt;
+
+import io.visual_regression_tracker.sdk_java.VisualRegressionTrackerConfig;
+import lombok.SneakyThrows;
+import lombok.experimental.UtilityClass;
+import plugins.screenshots.ScreenshotPlugin;
+import solutions.bellatrix.core.configuration.ConfigurationService;
+import solutions.bellatrix.core.utilities.SingletonFactory;
+
+import java.util.Objects;
+
+@UtilityClass
+public class VisualRegressionTracker {
+ private static final VisualRegressionTrackerSettings settings = ConfigurationService.get(VisualRegressionTrackerSettings.class);
+ private static final VisualRegressionTrackerConfig config = new VisualRegressionTrackerConfig(
+ settings.getApiUrl(),
+ settings.getApiKey(),
+ settings.getProject(),
+ settings.getBranch(),
+ settings.getCiBuildId(),
+ settings.isEnableSoftAssert(),
+ settings.getHttpTimeout()
+ );
+ private static io.visual_regression_tracker.sdk_java.VisualRegressionTracker tracker;
+
+ static {
+ tracker = new io.visual_regression_tracker.sdk_java.VisualRegressionTracker(config);
+ }
+
+ @SneakyThrows
+ public static void takeSnapshot() {
+ var caller = Thread.currentThread().getStackTrace()[1]; // gets the caller method of screenshot()
+ var name = caller.getMethodName();
+
+ tracker.track(name, Objects.requireNonNull(SingletonFactory.getInstance(ScreenshotPlugin.class)).takeScreenshot(name));
+ }
+
+ @SneakyThrows
+ public static void takeSnapshot(String name) {
+ tracker.track(name, Objects.requireNonNull(SingletonFactory.getInstance(ScreenshotPlugin.class)).takeScreenshot(name));
+ }
+}
diff --git a/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java b/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java
new file mode 100644
index 00000000..7369f03a
--- /dev/null
+++ b/bellatrix.addons.visual-regression-tracker/src/main/java/solutions/bellatrix/plugins/vrt/VisualRegressionTrackerSettings.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 Automate The Planet Ltd.
+ * Author: Miriam Kyoseva
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package solutions.bellatrix.plugins.vrt;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter @Setter @NoArgsConstructor
+public class VisualRegressionTrackerSettings {
+ private String apiUrl;
+ private String project;
+ private String apiKey;
+ private String branch;
+ private boolean enableSoftAssert;
+ private String ciBuildId;
+ private int httpTimeout;
+}
diff --git a/bellatrix.android/src/main/java/solutions/bellatrix/android/infrastructure/MobileScreenshotPlugin.java b/bellatrix.android/src/main/java/solutions/bellatrix/android/infrastructure/MobileScreenshotPlugin.java
index 89b74937..61250771 100644
--- a/bellatrix.android/src/main/java/solutions/bellatrix/android/infrastructure/MobileScreenshotPlugin.java
+++ b/bellatrix.android/src/main/java/solutions/bellatrix/android/infrastructure/MobileScreenshotPlugin.java
@@ -18,11 +18,14 @@
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import plugins.screenshots.ScreenshotPlugin;
+import plugins.screenshots.ScreenshotPluginEventArgs;
import solutions.bellatrix.android.configuration.AndroidSettings;
import solutions.bellatrix.core.configuration.ConfigurationService;
import solutions.bellatrix.core.utilities.PathNormalizer;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.nio.file.Paths;
import java.util.UUID;
@@ -33,10 +36,43 @@ public MobileScreenshotPlugin() {
@Override
@SneakyThrows
- protected void takeScreenshot(String screenshotSaveDir, String filename) {
- File screenshot = ((TakesScreenshot)DriverService.getWrappedAndroidDriver()).getScreenshotAs(OutputType.FILE);
- var destFile = new File(Paths.get(screenshotSaveDir, filename) + ".png");
- FileUtils.copyFile(screenshot, destFile);
+ public String takeScreenshot(String name) {
+ var screenshotSaveDir = getOutputFolder();
+ var filename = getUniqueFileName(name);
+
+ var screenshot = ((TakesScreenshot)DriverService.getWrappedAndroidDriver()).getScreenshotAs(OutputType.BASE64);
+
+ var path = Paths.get(screenshotSaveDir, filename) + ".png";
+
+ var file = new File(path);
+
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(screenshot);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, screenshot));
+ return screenshot;
+ }
+
+ @Override
+ @SneakyThrows
+ public String takeScreenshot(String screenshotSaveDir, String filename) {
+ var screenshot = ((TakesScreenshot)DriverService.getWrappedAndroidDriver()).getScreenshotAs(OutputType.BASE64);
+
+ var path = Paths.get(screenshotSaveDir, filename) + ".png";
+
+ var file = new File(path);
+
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(screenshot);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, screenshot));
+ return screenshot;
}
@Override
diff --git a/bellatrix.desktop/src/main/java/solutions/bellatrix/desktop/infrastructure/DesktopScreenshotPlugin.java b/bellatrix.desktop/src/main/java/solutions/bellatrix/desktop/infrastructure/DesktopScreenshotPlugin.java
index ffafa2ed..b8c95926 100644
--- a/bellatrix.desktop/src/main/java/solutions/bellatrix/desktop/infrastructure/DesktopScreenshotPlugin.java
+++ b/bellatrix.desktop/src/main/java/solutions/bellatrix/desktop/infrastructure/DesktopScreenshotPlugin.java
@@ -18,10 +18,14 @@
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import plugins.screenshots.ScreenshotPlugin;
+import plugins.screenshots.ScreenshotPluginEventArgs;
import solutions.bellatrix.core.configuration.ConfigurationService;
import solutions.bellatrix.desktop.configuration.DesktopSettings;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
@@ -32,10 +36,41 @@ public DesktopScreenshotPlugin() {
@Override
@SneakyThrows
- protected void takeScreenshot(String screenshotSaveDir, String filename) {
- File screenshot = ((TakesScreenshot)DriverService.getWrappedDriver()).getScreenshotAs(OutputType.FILE);
- var destFile = new File(Paths.get(screenshotSaveDir, filename) + ".png");
- FileUtils.copyFile(screenshot, destFile);
+ public String takeScreenshot(String name) {
+ var screenshotSaveDir = getOutputFolder();
+ var filename = getUniqueFileName(name);
+
+ var screenshot = ((TakesScreenshot)DriverService.getWrappedDriver()).getScreenshotAs(OutputType.BASE64);
+ Path path = Paths.get(screenshotSaveDir, filename);
+
+ var file = new File(path + ".png");
+
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(screenshot);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, screenshot));
+ return screenshot;
+ }
+
+ @Override
+ @SneakyThrows
+ public String takeScreenshot(String screenshotSaveDir, String filename) {
+ var screenshot = ((TakesScreenshot)DriverService.getWrappedDriver()).getScreenshotAs(OutputType.BASE64);
+ Path path = Paths.get(screenshotSaveDir, filename);
+
+ var file = new File(path + ".png");
+
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(screenshot);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, screenshot));
+ return screenshot;
}
@Override
diff --git a/bellatrix.ios/src/main/java/solutions/bellatrix/ios/infrastructure/MobileScreenshotPlugin.java b/bellatrix.ios/src/main/java/solutions/bellatrix/ios/infrastructure/MobileScreenshotPlugin.java
index 12eff289..6e932d0b 100644
--- a/bellatrix.ios/src/main/java/solutions/bellatrix/ios/infrastructure/MobileScreenshotPlugin.java
+++ b/bellatrix.ios/src/main/java/solutions/bellatrix/ios/infrastructure/MobileScreenshotPlugin.java
@@ -18,11 +18,14 @@
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import plugins.screenshots.ScreenshotPlugin;
+import plugins.screenshots.ScreenshotPluginEventArgs;
import solutions.bellatrix.core.configuration.ConfigurationService;
import solutions.bellatrix.core.utilities.PathNormalizer;
import solutions.bellatrix.ios.configuration.IOSSettings;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.nio.file.Paths;
import java.util.UUID;
@@ -33,10 +36,39 @@ public MobileScreenshotPlugin() {
@Override
@SneakyThrows
- protected void takeScreenshot(String screenshotSaveDir, String filename) {
- File screenshot = ((TakesScreenshot)DriverService.getWrappedIOSDriver()).getScreenshotAs(OutputType.FILE);
- var destFile = new File(Paths.get(screenshotSaveDir, filename) + ".png");
- FileUtils.copyFile(screenshot, destFile);
+ public String takeScreenshot(String name) {
+ var screenshotSaveDir = getOutputFolder();
+ var filename = getUniqueFileName(name);
+
+ var screenshot = ((TakesScreenshot)DriverService.getWrappedIOSDriver()).getScreenshotAs(OutputType.BASE64);
+ var path = Paths.get(screenshotSaveDir, filename) + ".png";
+ var file = new File(path);
+
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(screenshot);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, screenshot));
+ return screenshot;
+ }
+
+ @Override
+ @SneakyThrows
+ public String takeScreenshot(String screenshotSaveDir, String filename) {
+ var screenshot = ((TakesScreenshot)DriverService.getWrappedIOSDriver()).getScreenshotAs(OutputType.BASE64);
+ var path = Paths.get(screenshotSaveDir, filename) + ".png";
+ var file = new File(path);
+
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(screenshot);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, screenshot));
+ return screenshot;
}
@Override
diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WebScreenshotPlugin.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WebScreenshotPlugin.java
index 116b9dba..e8c1ab98 100644
--- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WebScreenshotPlugin.java
+++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WebScreenshotPlugin.java
@@ -16,11 +16,13 @@
import com.microsoft.playwright.Page;
import com.microsoft.playwright.options.ScreenshotType;
import plugins.screenshots.ScreenshotPlugin;
+import plugins.screenshots.ScreenshotPluginEventArgs;
import solutions.bellatrix.core.utilities.PathNormalizer;
import solutions.bellatrix.playwright.utilities.Settings;
import java.io.File;
import java.nio.file.Paths;
+import java.util.Base64;
import java.util.UUID;
public class WebScreenshotPlugin extends ScreenshotPlugin {
@@ -29,12 +31,36 @@ public WebScreenshotPlugin() {
}
@Override
- protected void takeScreenshot(String screenshotSaveDir, String filename) {
+ public String takeScreenshot(String name) {
+ var screenshotSaveDir = getOutputFolder();
+ var filename = getUniqueFileName(name);
+
+ var path = Paths.get(screenshotSaveDir, filename);
+ var screenshot = PlaywrightService.wrappedBrowser().getCurrentPage()
+ .screenshot(new Page.ScreenshotOptions()
+ .setPath(path)
+ .setType(ScreenshotType.PNG)
+ );
+
+ var image = Base64.getEncoder().encodeToString(screenshot);
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, image));
+ return image;
+ }
+
+ @Override
+ public String takeScreenshot(String screenshotSaveDir, String filename) {
+ var path = Paths.get(screenshotSaveDir, filename);
var screenshot = PlaywrightService.wrappedBrowser().getCurrentPage()
.screenshot(new Page.ScreenshotOptions()
- .setPath(Paths.get(screenshotSaveDir, filename))
+ .setPath(path)
.setType(ScreenshotType.PNG)
);
+
+ var image = Base64.getEncoder().encodeToString(screenshot);
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, image));
+ return image;
}
@Override
diff --git a/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPlugin.java b/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPlugin.java
index b31e3805..528d24e7 100644
--- a/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPlugin.java
+++ b/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPlugin.java
@@ -29,7 +29,8 @@ public ScreenshotPlugin(boolean isEnabled) {
this.isEnabled = isEnabled;
}
- protected abstract void takeScreenshot(String screenshotSaveDir, String filename);
+ public abstract String takeScreenshot(String fileName);
+ public abstract String takeScreenshot(String screenshotSaveDir, String filename);
protected abstract String getOutputFolder();
protected abstract String getUniqueFileName(String testName);
@@ -41,7 +42,7 @@ public void postAfterTest(TestResult testResult, Method memberInfo, Throwable fa
var screenshotSaveDir = getOutputFolder();
var screenshotFileName = getUniqueFileName(memberInfo.getName());
- takeScreenshot(screenshotSaveDir, screenshotFileName);
- SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(Paths.get(screenshotSaveDir, screenshotFileName).toString(), screenshotFileName));
+ var image = takeScreenshot(screenshotSaveDir, screenshotFileName);
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(Paths.get(screenshotSaveDir, screenshotFileName).toString(), screenshotFileName, image));
}
}
diff --git a/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPluginEventArgs.java b/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPluginEventArgs.java
index b0026cc5..f68c842e 100644
--- a/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPluginEventArgs.java
+++ b/bellatrix.plugins.screenshots/src/main/java/plugins/screenshots/ScreenshotPluginEventArgs.java
@@ -20,7 +20,7 @@ public class ScreenshotPluginEventArgs {
private final String screenshotPath;
private final String fileName;
- public ScreenshotPluginEventArgs(String screenshotPath, String fileName) {
+ public ScreenshotPluginEventArgs(String screenshotPath, String fileName, String image) {
this.screenshotPath = screenshotPath;
this.fileName = fileName;
}
diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/WebScreenshotPlugin.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/WebScreenshotPlugin.java
index b58a9ab0..bc58145e 100644
--- a/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/WebScreenshotPlugin.java
+++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/infrastructure/WebScreenshotPlugin.java
@@ -14,6 +14,7 @@
package solutions.bellatrix.web.infrastructure;
import plugins.screenshots.ScreenshotPlugin;
+import plugins.screenshots.ScreenshotPluginEventArgs;
import ru.yandex.qatools.ashot.AShot;
import ru.yandex.qatools.ashot.shooting.ShootingStrategies;
import solutions.bellatrix.core.configuration.ConfigurationService;
@@ -22,9 +23,12 @@
import solutions.bellatrix.web.configuration.WebSettings;
import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
+import java.util.Base64;
import java.util.UUID;
public class WebScreenshotPlugin extends ScreenshotPlugin {
@@ -33,17 +37,48 @@ public WebScreenshotPlugin() {
}
@Override
- protected void takeScreenshot(String screenshotSaveDir, String filename) {
+ public String takeScreenshot(String name) {
+ var screenshotSaveDir = getOutputFolder();
+ var filename = getUniqueFileName(name);
+
+ var screenshot = new AShot()
+ .shootingStrategy(ShootingStrategies.viewportPasting(100))
+ .takeScreenshot(DriverService.getWrappedDriver());
+
+ var path = Paths.get(screenshotSaveDir, filename).toString();
+ var destFile = new File(path);
+ Log.info("Saving screenshot with path: " + destFile);
+ try {
+ ImageIO.write(screenshot.getImage(), "png", destFile);
+ } catch (IOException e) {
+ Log.error(e.toString());
+ }
+
+ var base64image = bufferedImageToBase64(screenshot.getImage());
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, base64image));
+ return base64image;
+ }
+
+ @Override
+ public String takeScreenshot(String screenshotSaveDir, String filename) {
var screenshot = new AShot()
.shootingStrategy(ShootingStrategies.viewportPasting(100))
.takeScreenshot(DriverService.getWrappedDriver());
- var destFile = new File(Paths.get(screenshotSaveDir, filename).toString());
+
+ var path = Paths.get(screenshotSaveDir, filename).toString();
+ var destFile = new File(path);
Log.info("Saving screenshot with path: " + destFile);
try {
ImageIO.write(screenshot.getImage(), "png", destFile);
} catch (IOException e) {
Log.error(e.toString());
}
+
+ var base64image = bufferedImageToBase64(screenshot.getImage());
+
+ SCREENSHOT_GENERATED.broadcast(new ScreenshotPluginEventArgs(path.toString(), filename, base64image));
+ return base64image;
}
@Override
@@ -63,4 +98,23 @@ protected String getOutputFolder() {
protected String getUniqueFileName(String testName) {
return testName.concat(UUID.randomUUID().toString()).concat(".png");
}
+
+ private static String bufferedImageToBase64(BufferedImage image) {
+ String base64String = null;
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try {
+ ImageIO.write(image, "png", outputStream);
+ byte[] imageBytes = outputStream.toByteArray();
+ base64String = Base64.getEncoder().encodeToString(imageBytes);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return base64String;
+ }
}
diff --git a/pom.xml b/pom.xml
index d7e3e3ed..52b2847b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,7 @@
bellatrix.plugins.screenshots
bellatrix.plugins.video
bellatrix.plugins.jira.zephyr
+ bellatrix.addons.visual-regression-tracker
bellatrix.web
bellatrix.playwright
bellatrix.desktop