io.github.selcukes.reports.screen.ScreenPlayImpl Maven / Gradle / Ivy
/*
* 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.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.appium.java_client.windows.WindowsDriver;
import io.cucumber.java.Scenario;
import io.github.selcukes.commons.fixture.SelcukesFixture;
import io.github.selcukes.commons.helper.FileHelper;
import io.github.selcukes.notifier.Notifier;
import io.github.selcukes.notifier.NotifierFactory;
import io.github.selcukes.notifier.enums.NotifierType;
import io.github.selcukes.reports.enums.TestType;
import io.github.selcukes.snapshot.SnapshotImpl;
import io.github.selcukes.video.Recorder;
import io.github.selcukes.video.RecorderFactory;
import io.github.selcukes.video.enums.RecorderType;
import lombok.CustomLog;
import org.openqa.selenium.WebDriver;
import java.io.File;
import java.time.Duration;
import java.util.Objects;
import java.util.UUID;
import static io.github.selcukes.extent.report.Reporter.getReporter;
import static java.util.Optional.ofNullable;
@CustomLog
class ScreenPlayImpl implements ScreenPlay {
private final SnapshotImpl capture;
protected Recorder recorder;
protected Notifier notifier;
boolean isFailedOnly;
final boolean isNativeDevice;
final boolean isDesktop;
final WebDriver driver;
private Scenario scenario;
private ScreenPlayResult result;
private String screenshotPath;
public ScreenPlayImpl(WebDriver driver) {
this.driver = driver;
capture = new SnapshotImpl(driver);
isNativeDevice = driver instanceof AndroidDriver || driver instanceof IOSDriver;
isDesktop = driver instanceof WindowsDriver;
isFailedOnly = true;
}
@Override
public String takeScreenshot() {
try {
return isNativeDevice || isDesktop ? capture.shootVisiblePage() : capture.shootPage();
} catch (Exception e) {
logger.warn(e::getMessage);
return "";
}
}
@Override
public ScreenPlay attachScreenshot() {
if (result.getTestType().equals(TestType.CUCUMBER)) {
try {
byte[] screenshot = isNativeDevice || isDesktop ? capture.shootVisiblePageAsBytes()
: capture.shootPageAsBytes();
attach(screenshot, "image/png");
} catch (Exception e) {
logger.warn(e::getMessage);
}
} else {
screenshotPath = takeScreenshot();
if (!screenshotPath.isEmpty()) {
String htmlToEmbed = "
";
attach(htmlToEmbed);
}
}
return this;
}
@Override
public ScreenPlay attachVideo() {
if (isAttachable()) {
String videoPath = stop().getAbsolutePath();
String htmlToEmbed = "";
attach(htmlToEmbed);
} else {
if (isNativeDevice) {
stopAndDeleteVideo();
} else {
recorder.stopAndDelete();
}
}
return this;
}
private void startNativeVideo() {
if (driver instanceof AndroidDriver androidDriver) {
androidDriver
.startRecordingScreen(new AndroidStartScreenRecordingOptions()
.withVideoSize("540x960").withBitRate(2000000)
.withTimeLimit(Duration.ofMinutes(30)));
} else if (driver instanceof IOSDriver iosDriver) {
iosDriver
.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 androidDriver) {
encodedVideo = androidDriver.stopRecordingScreen();
} else if (driver instanceof IOSDriver iosDriver) {
encodedVideo = iosDriver.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 (isNativeDevice) {
startNativeVideo();
return this;
} else if (recorder == null) {
logger.warn(() -> "RecorderType not configured. Using Default RecorderType as MONTE");
withRecorder(RecorderType.MONTE);
}
recorder.start();
return this;
}
@Override
public File stop() {
if (isNativeDevice) {
return stopAndSaveNativeVideo(result.getTestName());
}
Objects.requireNonNull(recorder, "Recording not started...");
return recorder.stopAndSave(result.getTestName());
}
@Override
public ScreenPlay sendNotification(String message) {
if (notifier == null) {
logger.warn(() -> "NotifierType not configured. Using Default RecorderType as TEAMS");
withNotifier(NotifierType.TEAMS);
}
notifier.scenarioName(result.getTestName())
.scenarioStatus(result.getStatus())
.stepDetails(message)
.path(ofNullable(screenshotPath).orElse(""));
if (result.getErrorMessage() != null) {
notifier.errorMessage(result.getErrorMessage());
}
notifier.pushNotification();
return this;
}
@Override
public void attachLogs() {
if (isAttachable()) {
write(getReporter().getLogRecords());
}
}
@Override
public ScreenPlay withRecorder(RecorderType recorderType) {
recorder = RecorderFactory.getRecorder(recorderType);
return this;
}
@Override
public ScreenPlay withNotifier(NotifierType notifierType) {
notifier = NotifierFactory.getNotifier(notifierType);
return this;
}
@Override
public ScreenPlay withResult(T scenario) {
result = new ScreenPlayResult(scenario);
if (scenario instanceof Scenario scenarioResult) {
this.scenario = scenarioResult;
}
return this;
}
@Override
public ScreenPlay ignoreCondition() {
isFailedOnly = false;
return this;
}
private void write(String text) {
if (result.getTestType().equals(TestType.CUCUMBER)) {
scenario.log(text);
logger.info(() -> "Attached Logs to Cucumber Report");
} else {
SelcukesFixture.attach(text);
logger.info(() -> "Attached Logs to TestNG Report");
}
}
private void attach(String attachment) {
if (isAttachable()) {
if (result.getTestType().equals(TestType.CUCUMBER)) {
byte[] objToEmbed = attachment.getBytes();
attach(objToEmbed, "text/html");
logger.info(() -> "Attached Video to Cucumber Report");
} else {
SelcukesFixture.attach(attachment);
String contentType = attachment.contains("video") ? "Video" : "Screenshot";
logger.info(() -> "Attached " + contentType + " to TestNG Report");
}
}
}
private void attach(byte[] objToEmbed, String mediaType) {
scenario.attach(objToEmbed, mediaType, scenario.getName());
}
boolean isAttachable() {
if (isFailedOnly) {
return result.isFailed();
} else {
return true;
}
}
}