- * This class constructs the required writer on its own, it's only needed to pass the {@link Writer} class it should use. It also requires configuration object - * of type {@link RecordingConfigurations} and the name of the result file (will also be created by the class itself) + * This class constructs the required writer on its own, it's only needed to pass the {@link Writer} class it should + * use. It also requires configuration object of type {@link RecordingConfigurations} and the name of the result file + * (will also be created by the class itself) * * @author olha */ @@ -44,13 +49,13 @@ public class TakeScreenshotsThread extends Thread private Writer writer; public TakeScreenshotsThread(WebDriver driver, Class extends Writer> writerClass, RecordingConfigurations recordingConfigurations, - String testName) + String testName) throws IOException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { this.recordingConfigurations = recordingConfigurations; fileName = recordingConfigurations.tempFolderToStoreRecording() - + testName.replaceAll("\\s", "-").replaceAll(":", "-").replaceAll("/", "_") + "." + recordingConfigurations.format(); + + testName.replaceAll("\\s", "-").replaceAll(":", "-").replaceAll("/", "_") + "." + recordingConfigurations.format(); this.writer = Writer.instantiate(writerClass, recordingConfigurations, fileName); File directory = new File(recordingConfigurations.tempFolderToStoreRecording()); if (!directory.exists()) @@ -82,6 +87,16 @@ public synchronized void run() LOGGER.error("Could not create temp file for last screenshot, alert handling for test recording will be disabled.", e); } + try + { + // Create a temp file to hold the last frame + lastFrameTempFile = File.createTempFile("last_frame_", ".png"); + } + catch (IOException e) + { + LOGGER.error("Could not create temp file for last screenshot, alert handling for test recording will be disabled.", e); + } + try { // try to start writer @@ -101,7 +116,8 @@ public synchronized void run() { long delay = Math.max(recordingConfigurations.oneImagePerMilliseconds(), duration); - // taking a screenshot while an alert is open will throw an exception and closes the alert, so it is checked here + // taking a screenshot while an alert is open will throw an exception and closes the alert, so + // it is checked here if (alertIsPresent().apply(driver) != null) { // write the last successful frame again, if it exists @@ -113,6 +129,14 @@ public synchronized void run() else { File file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); + int cropWidth = ((Long) ((JavascriptExecutor) driver).executeScript("return window.innerWidth;")).intValue(); + int cropHeight = ((Long) ((JavascriptExecutor) driver).executeScript("return window.innerHeight;")).intValue(); + BufferedImage fullImage = ImageIO.read(file); + if (cropWidth > 0 && cropHeight > 0) + { + BufferedImage croppedImage = fullImage.getSubimage(0, 0, cropWidth, cropHeight); + ImageIO.write(croppedImage, "png", file); + } writer.compressImageIfNeeded(file, recordingConfigurations.imageScaleFactor(), recordingConfigurations.imageQuality()); writer.write(file, delay); @@ -148,7 +172,7 @@ public synchronized void run() if (recordingConfigurations.logInformationAboutRecording()) { AllureAddons.addToReport("average " + (isGif ? "gif" : "video") + " sequence recording creation duration = " + millis + " / " + turns + "=" - + millis / turns, ""); + + millis / turns, ""); } writer.stop(); try @@ -189,7 +213,8 @@ public synchronized void run() * Stops screenshot loop. Please, don't forget to call {@link Thread#join()} method after this to kill the thread * * @param testFailed - * {@link Boolean} if the filmed test failed (needed to decide whether the record should be attached to the allure report) + * {@link Boolean} if the filmed test failed (needed to decide whether the record should be attached to + * the allure report) */ public void stopRun(boolean testFailed) { diff --git a/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationTest.java b/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationTest.java index e7163f5d6..14660b86a 100644 --- a/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationTest.java +++ b/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationTest.java @@ -10,6 +10,7 @@ import org.aeonbits.owner.ConfigFactory; import org.apache.commons.lang3.StringUtils; import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import com.xceptance.neodymium.common.recording.FilmTestExecution; @@ -19,7 +20,9 @@ public class RecordingDurationTest extends AbstractNeodymiumTest { - public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOException + private File recordingFile; + + public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOException, InterruptedException { CustomRecordingTest.isGif = isGif; String format = isGif ? "gif" : "video"; @@ -36,8 +39,11 @@ public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOEx tempFiles.add(tempConfigFile1); run(CustomRecordingTest.class); RecordingConfigurations config = isGif ? FilmTestExecution.getContextGif() : FilmTestExecution.getContextVideo(); - File recordingFile = new File(config.tempFolderToStoreRecording() + CustomRecordingTest.uuid + "." + config.format()); - recordingFile.deleteOnExit(); + recordingFile = new File(config.tempFolderToStoreRecording() + CustomRecordingTest.uuid + "." + config.format()); + for (int i = 0; i < 3 && !recordingFile.exists(); i++) + { + Thread.sleep(1000); + } Assert.assertTrue("the recording file doesn't exist", recordingFile.exists()); ProcessBuilder pb = new ProcessBuilder("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", recordingFile.getAbsolutePath()); pb.redirectErrorStream(true); @@ -53,7 +59,7 @@ public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOEx } @Test - public void testVideoRecording() throws IOException + public void testVideoRecording() throws IOException, InterruptedException { double run100 = runTest(false, "100"); double run1000 = runTest(false, "1000"); @@ -63,7 +69,7 @@ public void testVideoRecording() throws IOException } @Test - public void testGifRecording() throws IOException + public void testGifRecording() throws IOException, InterruptedException { double run100 = runTest(true, "100"); double run1500 = runTest(true, "1000"); @@ -72,11 +78,20 @@ public void testGifRecording() throws IOException } @Test - public void testMixedRecording() throws IOException + public void testMixedRecording() throws IOException, InterruptedException { double runVideo1000 = runTest(false, "1000"); double runGif1000 = runTest(true, "1000"); Assert.assertEquals("Gifs with different oneImagePerMilliseconds value should have approximaty the same length (video = " + runVideo1000 + ", gif = " + runGif1000 + ")", runVideo1000, runGif1000, 5.0); } + + @AfterEach + public void cleanup() + { + if (recordingFile != null) + { + recordingFile.delete(); + } + } } diff --git a/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationWithAlertTest.java b/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationWithAlertTest.java index 1746a887e..32b47051d 100644 --- a/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationWithAlertTest.java +++ b/src/test/java/com/xceptance/neodymium/junit5/tests/recording/automatic/RecordingDurationWithAlertTest.java @@ -7,6 +7,7 @@ import org.aeonbits.owner.ConfigFactory; import org.apache.commons.lang3.StringUtils; import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import java.io.BufferedReader; @@ -18,7 +19,9 @@ public class RecordingDurationWithAlertTest extends AbstractNeodymiumTest { - public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOException + private File recordingFile; + + public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOException, InterruptedException { CustomRecordingWithAlertTest.isGif = isGif; String format = isGif ? "gif" : "video"; @@ -40,12 +43,15 @@ public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOEx run(CustomRecordingWithAlertTest.class); RecordingConfigurations config = isGif ? FilmTestExecution.getContextGif() : FilmTestExecution.getContextVideo(); - File recordingFile = new File(config.tempFolderToStoreRecording() + CustomRecordingWithAlertTest.uuid + "." + config.format()); - recordingFile.deleteOnExit(); + recordingFile = new File(config.tempFolderToStoreRecording() + CustomRecordingWithAlertTest.uuid + "." + config.format()); + + for (int i = 0; i < 3 && !recordingFile.exists(); i++) + { + Thread.sleep(1000); + } Assert.assertTrue("the recording file doesn't exist", recordingFile.exists()); - ProcessBuilder pb = new ProcessBuilder("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", - recordingFile.getAbsolutePath()); + ProcessBuilder pb = new ProcessBuilder("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", recordingFile.getAbsolutePath()); pb.redirectErrorStream(true); Process p = pb.start(); @@ -61,30 +67,39 @@ public double runTest(boolean isGif, String oneImagePerMilliseconds) throws IOEx } @Test - public void testVideoRecording() throws IOException + public void testVideoRecording() throws IOException, InterruptedException { double run100 = runTest(false, "100"); double run1000 = runTest(false, "1000"); Assert.assertEquals("Videos with different oneImagePerMilliseconds value should have approximaty the same length (1/100 = " + run1000 - + ", 1/1000 = " + run100 + ")", run1000, run1000, 5.0); + + ", 1/1000 = " + run100 + ")", run1000, run1000, 5.0); } @Test - public void testGifRecording() throws IOException + public void testGifRecording() throws IOException, InterruptedException { double run100 = runTest(true, "100"); double run1000 = runTest(true, "1000"); Assert.assertEquals("Gifs with different oneImagePerMilliseconds value should have approximaty the same length (1/100 = " + run100 + ", 1/1000 = " - + run1000 + ")", run100, run1000, 5.0); + + run1000 + ")", run100, run1000, 5.0); } @Test - public void testMixedRecording() throws IOException + public void testMixedRecording() throws IOException, InterruptedException { double runVideo1000 = runTest(false, "1000"); double runGif1000 = runTest(true, "1000"); Assert.assertEquals("Gifs with different oneImagePerMilliseconds value should have approximaty the same length (video = " + runVideo1000 + ", gif = " - + runGif1000 + ")", runVideo1000, runGif1000, 5.0); + + runGif1000 + ")", runVideo1000, runGif1000, 5.0); + } + + @AfterEach + public void cleanup() + { + if (recordingFile != null) + { + recordingFile.delete(); + } } }