Skip to content

Commit

Permalink
Merge pull request #133 from selcukes/131-MobileVideo
Browse files Browse the repository at this point in the history
Fix #131  Native mobile video support
  • Loading branch information
RameshBabuPrudhvi authored Jun 3, 2022
2 parents 9619172 + 9c09140 commit dcdd3a3
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,12 @@ public File getWaterMarkFile() {
}

@SneakyThrows
public void createFile(String fileContent, String filePath) {
public File createFile(String fileContent, String filePath) {
byte[] decodedFile = Base64.getDecoder()
.decode(fileContent.getBytes(StandardCharsets.UTF_8));
Path destinationFile = Paths.get(filePath);
Files.write(destinationFile, decodedFile);
return destinationFile.toFile();
}
}

18 changes: 12 additions & 6 deletions selcukes-reports/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@
<dependency>
<groupId>net.masterthought</groupId>
<artifactId>cucumber-reporting</artifactId>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
Expand All @@ -75,11 +75,17 @@
<artifactId>selenium-java</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.selcukes</groupId>
<artifactId>selcukes-testng</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@

package io.github.selcukes.reports.screen;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidStartScreenRecordingOptions;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.ios.IOSStartScreenRecordingOptions;
import io.cucumber.java.Scenario;
import io.github.selcukes.commons.helper.FileHelper;
import io.github.selcukes.commons.helper.Preconditions;
import io.github.selcukes.commons.logging.LogRecordListener;
import io.github.selcukes.commons.logging.Logger;
Expand All @@ -34,6 +39,8 @@
import org.testng.Reporter;

import java.io.File;
import java.time.Duration;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.stream.Collectors;
Expand All @@ -49,9 +56,13 @@ class ScreenPlayImpl implements ScreenPlay {
private Scenario scenario;
private ScreenPlayResult result;
private ITestResult iTestResult;
boolean isNativeDevice;
WebDriver driver;

public ScreenPlayImpl(WebDriver driver) {
this.driver = driver;
capture = new SnapshotImpl(driver);
isNativeDevice = driver instanceof AndroidDriver || driver instanceof IOSDriver;
isFailedOnly = true;
startReadingLogs();
}
Expand All @@ -65,7 +76,8 @@ public String takeScreenshot() {
public ScreenPlay attachScreenshot() {

if (result.getTestType().equals(TestType.CUCUMBER)) {
attach(capture.shootPageAsBytes(), "image/png");
byte[] screenshot = isNativeDevice ? capture.shootVisiblePageAsBytes() : capture.shootPageAsBytes();
attach(screenshot, "image/png");

} else {
String screenshotPath = takeScreenshot();
Expand All @@ -79,18 +91,61 @@ public ScreenPlay attachScreenshot() {
public ScreenPlay attachVideo() {
if (isAttachable()) {
String videoPath = stop().getAbsolutePath();
String htmlToEmbed = "<video width=\"864\" height=\"576\" controls>" +
"<source src=" + videoPath + " type=\"video/mp4\">" +
"Your browser does not support the video tag." +
"</video>";
String htmlToEmbed = "<video width=\"864\" height=\"576\" controls>"
+ "<source src=" + videoPath + " type=\"video/mp4\">"
+ "Your browser does not support the video tag." + "</video>";
attach(htmlToEmbed);
} else recorder.stopAndDelete();
} else {
if (isNativeDevice) {
stopAndDeleteVideo();
} else recorder.stopAndDelete();
}
return this;
}

private void startNativeVideo() {
if (driver instanceof AndroidDriver) {
((AndroidDriver) driver)
.startRecordingScreen(new AndroidStartScreenRecordingOptions()
.withVideoSize("540x960").withBitRate(2000000)
.withTimeLimit(Duration.ofMinutes(30)));
} else if (driver instanceof IOSDriver) {
((IOSDriver) driver)
.startRecordingScreen(new IOSStartScreenRecordingOptions()
.withVideoType("libx264")
.withVideoQuality(IOSStartScreenRecordingOptions.VideoQuality.MEDIUM)
.withTimeLimit(Duration.ofMinutes(30)));

}
logger.info(() -> "Native Recording started");
}

private void stopAndDeleteVideo() {
File tempVideo = stopAndSaveNativeVideo(UUID.randomUUID().toString());
tempVideo.deleteOnExit();
logger.info(() -> "Deleting recorded video file...");
}

private File stopAndSaveNativeVideo(String fileName) {
String encodedVideo = "";
if (driver instanceof AndroidDriver) {
encodedVideo = ((AndroidDriver) driver).stopRecordingScreen();
} else if (driver instanceof IOSDriver) {
encodedVideo = ((IOSDriver) driver).stopRecordingScreen();
}
String path = "video-report/" + fileName + ".mp4";
File video = FileHelper.createFile(encodedVideo, path);
logger.info(() -> "Recording finished to " + video.getAbsolutePath());
return video;
}

@Override
public ScreenPlay start() {
if (recorder == null) {

if (isNativeDevice) {
startNativeVideo();
return this;
} else if (recorder == null) {
logger.warn(() -> "RecorderType not configured. Using Default RecorderType as MONTE");
withRecorder(RecorderType.MONTE);
}
Expand All @@ -100,6 +155,9 @@ public ScreenPlay start() {

@Override
public File stop() {
if (isNativeDevice) {
return stopAndSaveNativeVideo(result.getTestName());
}
Preconditions.checkNotNull(recorder, "Recording not started...");
return recorder.stopAndSave(result.getTestName());
}
Expand Down Expand Up @@ -129,8 +187,7 @@ public void attachLogs() {
if (isAttachable()) {
String infoLogs = loggerListener.getLogRecords(Level.INFO)
.map(LogRecord::getMessage)
.collect(Collectors.joining("</li><li>", "<ul><li> ",
"</li></ul><br/>"));
.collect(Collectors.joining("</li><li>", "<ul><li> ", "</li></ul><br/>"));
write(infoLogs);
}
stopReadingLogs();
Expand All @@ -141,8 +198,7 @@ public void attachLogs(Level level) {
if (isAttachable()) {
String logs = loggerListener.getLogRecords(level)
.map(LogRecord::getMessage)
.collect(Collectors.joining("</li><li>", "<ul><li> ",
"</li></ul><br/>"));
.collect(Collectors.joining("</li><li>", "<ul><li> ", "</li></ul><br/>"));
write(logs);
}
stopReadingLogs();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) Ramesh Babu Prudhvi.
*
* 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 io.github.selcukes.reports.tests;

import io.appium.java_client.AppiumBy;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import io.appium.java_client.service.local.flags.GeneralServerFlag;
import io.github.selcukes.reports.screen.ScreenPlay;
import io.github.selcukes.reports.screen.ScreenPlayBuilder;
import lombok.CustomLog;
import lombok.SneakyThrows;
import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.nio.file.Paths;

@CustomLog
public class AppiumVideoTest {

private WebDriver driver;
private ScreenPlay screenPlay;
private AppiumDriverLocalService service;

@SneakyThrows
@BeforeMethod
public void beforeTest() {
service = new AppiumServiceBuilder()
.withIPAddress("127.0.0.1")
.usingAnyFreePort()
.withArgument(GeneralServerFlag.SESSION_OVERRIDE)
.withArgument(GeneralServerFlag.BASEPATH, "/wd/")
.build();
service.start();

UiAutomator2Options options = new UiAutomator2Options();
String app = Paths.get("src/test/resources/android-app.apk").toFile().getAbsolutePath();
System.out.println(app);
options.setApp(app);
driver = new AndroidDriver(service.getUrl(), options);

}

@Test(enabled = false)
public void mobileVideoTest() {
screenPlay = ScreenPlayBuilder
.getScreenPlay(driver)
.start();

driver.findElement(AppiumBy.accessibilityId("Views")).click();
driver.findElement(AppiumBy.accessibilityId("Expandable Lists")).click();
driver.findElement(AppiumBy.accessibilityId("3. Simple Adapter")).click();
}


@AfterMethod
public void afterTest(ITestResult result) {
try {
screenPlay
.withResult(result)
.ignoreCondition()
.attachVideo();
if (driver != null)
driver.quit();

} finally {
if (service != null) {
service.stop();
}
}

}
}
2 changes: 1 addition & 1 deletion selcukes-reports/src/test/resources/selcukes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ cucumber:
plugin: io.github.selcukes.reports.cucumber.CucumberListener
web:
remote: true
browserName: CHROME
browser: CHROME
headLess: true
serviceUrl: "http://127.0.0.1:8080"
windows:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected void waitForScrolling() {
Await.until(TimeUnit.MILLISECONDS, 1);
}

private byte[] takeScreenshot() {
protected byte[] takeScreenshot() {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public interface Snapshot {

byte[] shootPageAsBytes();

byte[] shootVisiblePageAsBytes();

Snapshot withAddressBar();

Snapshot withText(String text);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public String shootPage() {
public byte[] shootPageAsBytes() {
return getScreenshot(OutputType.BYTES);
}
@Override
public byte[] shootVisiblePageAsBytes() {
return takeScreenshot();
}

private <X> X getScreenshot(OutputType<X> outputType) {
return screenshotText != null || isAddressBar ? getScreenshotWithText(outputType) : getFullScreenshotAs(outputType);
Expand Down

0 comments on commit dcdd3a3

Please sign in to comment.