Enable Granular Videos for Desktop [Java - Junit]
In order to enable granular videos for selenium, we are using a selenium driver to take screenshots after regular intervals. In the last using the FFMPEG
library, we'll create a video from these screenshots.
Add dependency to pom.xml
Add VideoRecording class to the framework
Add startVideoRecording and stopVideoRecording in Before and After method
Please follow the following steps:
Add dependency to pom.xml
This dependency is used to call the command line execution from Java.
<dependency>
<groupId>org.buildobjects</groupId>
<artifactId>jproc</artifactId>
<version>2.8.2</version>
</dependency>
Add VideoRecording
class to the framework
This is a utility class, which does all the dirty work. This class exposes two methods startVideoRecording
and stopVideoRecording
. This class takes screenshots after configurable intervals, and at the end, it creates a video using compiling all the screenshots.
package com.testlio.lib.utility.video;
import io.qameta.allure.Allure;
import org.apache.commons.io.FileUtils;
import org.buildobjects.process.ProcBuilder;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static com.testlio.lib.properties.Execution.properties;
public class VideoRecording {
private static AtomicInteger number = new AtomicInteger();
private static ScheduledExecutorService executor;
//Time it takes new screenshot
private static int SCREEN_SHOT_DELAY_MS = 700;
private static Path tempFilePath;
private static Runnable createScreenshot(final String testName, WebDriver driver) throws IOException {
System.out.println("Creating Directory if not exists");
tempFilePath = Files.createTempDirectory(testName);
return () -> {
if (driver != null) {
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
File dest = new File(tempFilePath.toAbsolutePath() + "/" + number + ".png");
number.getAndIncrement();
try {
FileUtils.copyFile(screenshot, dest);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public static void startVideoRecording(String testName, WebDriver driver) throws IOException {
// Make sure we are in Selenium/Desktop
if (properties().isWebExecution()) {
number.set(0);
executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(createScreenshot(testName, driver), 0, SCREEN_SHOT_DELAY_MS, TimeUnit.MILLISECONDS);
}
}
public static void stopVideoRecording(String testName) {
try {
if (!properties().isWebExecution() || executor == null) {
return;
}
executor.shutdownNow();
Path tempDirectory = Files.createTempDirectory(testName);
String videoFileName = tempDirectory.toAbsolutePath() + "/" + testName + "-video.mp4";
ByteArrayOutputStream output = new ByteArrayOutputStream();
ByteArrayOutputStream errorOutput = new ByteArrayOutputStream();
// FFMPEG library command
new ProcBuilder("ffmpeg")
.withArgs("-y", "-i", tempFilePath.toAbsolutePath() + "/" + "%d.png", "-c:v", "libx264", "-r", "5", "-vf", "setpts=10*PTS", videoFileName)
.withOutputStream(output)
.withErrorStream(errorOutput)
.withTimeoutMillis(20000)
.run();
System.out.println(output);
System.out.println(errorOutput);
File initialFile = new File(videoFileName);
if (initialFile.exists()) {
System.out.println("File exists, attaching as allure report");
InputStream targetStream = Files.newInputStream(initialFile.toPath());
Allure.getLifecycle().addAttachment(testName, "video/mp4", "mp4", targetStream);
}
}
catch (Exception e) {
System.out.println(e);
}
}
}
Add startVideoRecording and stopVideoRecording
in Before and After
method
We need to start video recording before each method.
@Rule
public TestName name = new TestName();
@Before
public void setUp() throws IOException {
driverProvider = getDriverProvider();
// Check if Desktop/Selenium driver then start videoRecording
if (properties().isWebExecution()) {
// create web driver and pass it to startVideoRecording method
webDriver = driverProvider.createDriver();
startVideoRecording(testName.getMethodName(), getWebDriver());
}
}
@After
public void after(){
// Check if Desktop/Selenium driver then stop videoRecording
if (properties().isWebExecution()) {
stopVideoRecording(testName.getMethodName());
}
}
Enable Granular Videos for Desktop [Java - TestNG]
In order to enable granular videos for selenium, we are using a selenium driver to take screenshots after regular intervals. In the last using the FFMPEG
library, we'll create a video from these screenshots.
Add dependency to pom.xml
Add VideoRecording class to the framework
Add ListenersTestNG class to framework
Add Listeners to BaseTest class
Add startVideoRecording in BeforeMethod method
Please follow the following steps:
Add dependency to pom.xml
This dependency is used to call the command line execution from Java.
<dependency>
<groupId>org.buildobjects</groupId>
<artifactId>jproc</artifactId>
<version>2.8.2</version>
</dependency>
Add VideoRecording
class to the framework
This is a utility class, which does all the dirty work. This class exposes two methods startVideoRecording
and stopVideoRecording
. This class takes screenshots after configurable intervals, and at the end, it creates a video using compiling all the screenshots.
package com.testlio.lib.utility.video;
import io.qameta.allure.Allure;
import org.apache.commons.io.FileUtils;
import org.buildobjects.process.ProcBuilder;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static com.testlio.lib.properties.Execution.properties;
public class VideoRecording {
private static AtomicInteger number = new AtomicInteger();
private static ScheduledExecutorService executor;
//Time it takes new screenshot
private static int SCREEN_SHOT_DELAY_MS = 700;
private static Path tempFilePath;
private static Runnable createScreenshot(final String testName, WebDriver driver) throws IOException {
System.out.println("Creating Directory if not exists");
tempFilePath = Files.createTempDirectory(testName);
return () -> {
if (driver != null) {
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
File dest = new File(tempFilePath.toAbsolutePath() + "/" + number + ".png");
number.getAndIncrement();
try {
FileUtils.copyFile(screenshot, dest);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public static void startVideoRecording(String testName, WebDriver driver) throws IOException {
// Make sure we are in Selenium/Desktop
if (properties().isWebExecution()) {
number.set(0);
executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(createScreenshot(testName, driver), 0, SCREEN_SHOT_DELAY_MS, TimeUnit.MILLISECONDS);
}
}
public static void stopVideoRecording(String testName) {
try {
if (!properties().isWebExecution() || executor == null) {
return;
}
executor.shutdownNow();
Path tempDirectory = Files.createTempDirectory(testName);
String videoFileName = tempDirectory.toAbsolutePath() + "/" + testName + "-video.mp4";
ByteArrayOutputStream output = new ByteArrayOutputStream();
ByteArrayOutputStream errorOutput = new ByteArrayOutputStream();
// FFMPEG library command
new ProcBuilder("ffmpeg")
.withArgs("-y", "-i", tempFilePath.toAbsolutePath() + "/" + "%d.png", "-c:v", "libx264", "-r", "5", "-vf", "setpts=10*PTS", videoFileName)
.withOutputStream(output)
.withErrorStream(errorOutput)
.withTimeoutMillis(20000)
.run();
System.out.println(output);
System.out.println(errorOutput);
File initialFile = new File(videoFileName);
if (initialFile.exists()) {
System.out.println("File exists, attaching as allure report");
InputStream targetStream = Files.newInputStream(initialFile.toPath());
Allure.getLifecycle().addAttachment(testName, "video/mp4", "mp4", targetStream);
}
}
catch (Exception e) {
System.out.println(e);
}
}
}
Add ListenersTestNG
class to framework
afterInvocation
method will be invoked after each test (success or failure)
package com.testlio.lib.utility.video;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
import static com.testlio.lib.utility.video.VideoRecording.stopVideoRecording;
public class ListenersTestNG implements IInvokedMethodListener {
public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
if (method.isTestMethod()) {
stopVideoRecording(method.getTestMethod().getMethodName());
}
}
}
Add Listeners to BaseTest class
@Listeners(value= ListenersTestNG.class)
public abstract class BaseTest {
Add startVideoRecording
in BeforeMethod
method
We need to start video recording before each method.
@BeforeMethod(alwaysRun = true)
public void setUp(ITestContext context, Method method) throws IOException {
driverProvider = getDriverProvider();
// Check if Desktop/Selenium driver then start videoRecording
if (properties().isWebExecution()) {
webDriver = driverProvider.createDriver();
startVideoRecording(method.getName(), getWebDriver());
}
}