diff --git a/core/src/main/scala/com/karumi/shot/Shot.scala b/core/src/main/scala/com/karumi/shot/Shot.scala index 63bfbb3f..6d60d6b8 100644 --- a/core/src/main/scala/com/karumi/shot/Shot.scala +++ b/core/src/main/scala/com/karumi/shot/Shot.scala @@ -4,7 +4,7 @@ import com.karumi.shot.android.Adb import com.karumi.shot.domain._ import com.karumi.shot.domain.model.{AppId, FilePath, Folder, ScreenshotsSuite} import com.karumi.shot.json.ScreenshotsComposeSuiteJsonParser -import com.karumi.shot.reports.{ConsoleReporter, ExecutionReporter} +import com.karumi.shot.reports.{ConsoleReporter, HtmlExecutionReporter, ExecutionReporter} import com.karumi.shot.screenshots.{ ScreenshotsComparator, ScreenshotsDiffGenerator, @@ -33,7 +33,7 @@ class Shot( screenshotsDiffGenerator: ScreenshotsDiffGenerator, screenshotsSaver: ScreenshotsSaver, console: Console, - reporter: ExecutionReporter, + reporters: List[ExecutionReporter], consoleReporter: ConsoleReporter, envVars: EnvVars ) { @@ -54,7 +54,8 @@ class Shot( } else { val screenshots = regularScreenshotSuite.get ++ composeScreenshotSuite.get console.show("😃 Screenshots recorded and saved at: " + shotFolder.screenshotsFolder()) - reporter.generateRecordReport(appId, screenshots, shotFolder) + for (reporter <- reporters) + reporter.generateRecordReport(appId, screenshots, shotFolder) console.show( "🤓 You can review the execution report here: " + shotFolder.reportFolder() + "index.html" ) @@ -121,12 +122,13 @@ class Shot( } else { console.showSuccess("✅ Yeah!!! Your tests are passing.") } - reporter.generateVerificationReport( - appId, - comparison, - shotFolder, - showOnlyFailingTestsInReports - ) + for (reporter <- reporters) + reporter.generateVerificationReport( + appId, + comparison, + shotFolder, + showOnlyFailingTestsInReports + ) console.show( "🤓 You can review the execution report here: " + shotFolder .verificationReportFolder() + "index.html" diff --git a/core/src/main/scala/com/karumi/shot/reports/ExecutionReporter.scala b/core/src/main/scala/com/karumi/shot/reports/ExecutionReporter.scala index 2cdc289f..ef9111af 100644 --- a/core/src/main/scala/com/karumi/shot/reports/ExecutionReporter.scala +++ b/core/src/main/scala/com/karumi/shot/reports/ExecutionReporter.scala @@ -1,211 +1,19 @@ package com.karumi.shot.reports +import com.karumi.shot.domain.{ScreenshotsComparisionResult, ShotFolder} +import com.karumi.shot.domain.model.{AppId, ScreenshotsSuite} -import java.io.{File, FileWriter} - -import com.karumi.shot.domain._ -import com.karumi.shot.domain.model.{AppId, Folder, ScreenshotComparisionErrors, ScreenshotsSuite} -import com.karumi.shot.templates.RecordIndexTemplate.recordIndexTemplate -import com.karumi.shot.templates.VerificationIndexTemplate.verificationIndexTemplate - -class ExecutionReporter { +trait ExecutionReporter { def generateRecordReport( appId: AppId, screenshots: ScreenshotsSuite, shotFolder: ShotFolder - ) = { - val reportFileContents = populateRecordTemplate(appId, screenshots) - resetVerificationReport(shotFolder) - val reportFolder = shotFolder.recordingReportFolder() - writeReport(reportFileContents, reportFolder) - } + ): Unit def generateVerificationReport( appId: AppId, comparision: ScreenshotsComparisionResult, shotFolder: ShotFolder, showOnlyFailingTestsInReports: Boolean = false - ) = { - val reportFileContents = - populateVerificationTemplate(appId, comparision, showOnlyFailingTestsInReports) - resetVerificationReport(shotFolder) - val reportFolder = shotFolder.verificationReportFolder() - writeReport(reportFileContents, reportFolder) - } - - private def writeReport( - fileContents: String, - reportFolder: String - ) = { - val indexFile = new File(reportFolder + "index.html") - new File(reportFolder).mkdirs() - val writer = new FileWriter(indexFile) - writer.write(fileContents) - writer.close() - } - - private def resetVerificationReport(shotFolder: ShotFolder) = { - val file = new File(shotFolder.reportFolder() + "index.html") - if (file.exists()) { - file.delete() - } - } - - private def populateRecordTemplate( - appId: AppId, - screenshots: ScreenshotsSuite - ): String = { - val title = s"Record results: $appId" - val numberOfTests = screenshots.size - val summaryResults = - s"$numberOfTests screenshot tests recorded." - val summaryTableBody = generateRecordSummaryTableBody(screenshots) - recordIndexTemplate( - title = title, - summaryResult = summaryResults, - summaryTableBody = summaryTableBody - ) - } - - private def generateRecordSummaryTableBody(screenshots: ScreenshotsSuite): String = { - screenshots - .map { (screenshot: Screenshot) => - val testClass = screenshot.testClass - val testName = screenshot.testName - val originalScreenshot = "./images/recorded/" + screenshot.name + ".png" - val width = (screenshot.screenshotDimension.width * 0.2).toInt - val screenshotName = screenshot.name - "
Test class: $testClass
" + - s"Test name: $testName
" + - s"Screenshot name: $screenshotName
Test class: $testClass
" + - s"Test name: $testName
Screenshot name: $screenshotName
" + - s"Test class: $testClass
" + - s"Test name: $testName
" + - s"Screenshot name: $screenshotName
🔎 Recorded screenshot not found.
" - case DifferentScreenshots(_, _) => - "🤔 The application UI has been modified.
" - case DifferentImageDimensions(_, _, _) => - "📱 The size of the screenshot taken has changed.
" - case _ => - "😞 Ups! Something went wrong while comparing your screenshots but we couldn't identify the cause. If you think you've found a bug, please open an issue at https://github.com/karumi/shot.
" - } - .getOrElse("") + ): Unit } diff --git a/core/src/main/scala/com/karumi/shot/reports/HtmlExecutionReporter.scala b/core/src/main/scala/com/karumi/shot/reports/HtmlExecutionReporter.scala new file mode 100644 index 00000000..629d63a9 --- /dev/null +++ b/core/src/main/scala/com/karumi/shot/reports/HtmlExecutionReporter.scala @@ -0,0 +1,210 @@ +package com.karumi.shot.reports + +import java.io.{File, FileWriter} + +import com.karumi.shot.domain._ +import com.karumi.shot.domain.model.{AppId, Folder, ScreenshotComparisionErrors, ScreenshotsSuite} +import com.karumi.shot.templates.RecordIndexTemplate.recordIndexTemplate +import com.karumi.shot.templates.VerificationIndexTemplate.verificationIndexTemplate + +class HtmlExecutionReporter extends ExecutionReporter { + + def generateRecordReport( + appId: AppId, + screenshots: ScreenshotsSuite, + shotFolder: ShotFolder + ): Unit = { + val reportFileContents = populateRecordTemplate(appId, screenshots) + resetVerificationReport(shotFolder) + val reportFolder = shotFolder.recordingReportFolder() + writeReport(reportFileContents, reportFolder) + } + + def generateVerificationReport( + appId: AppId, + comparision: ScreenshotsComparisionResult, + shotFolder: ShotFolder, + showOnlyFailingTestsInReports: Boolean = false + ) = { + val reportFileContents = + populateVerificationTemplate(appId, comparision, showOnlyFailingTestsInReports) + resetVerificationReport(shotFolder) + val reportFolder = shotFolder.verificationReportFolder() + writeReport(reportFileContents, reportFolder) + } + private def writeReport( + fileContents: String, + reportFolder: String + ) = { + val indexFile = new File(reportFolder + "index.html") + new File(reportFolder).mkdirs() + val writer = new FileWriter(indexFile) + writer.write(fileContents) + writer.close() + } + + private def resetVerificationReport(shotFolder: ShotFolder) = { + val file = new File(shotFolder.reportFolder() + "index.html") + if (file.exists()) { + file.delete() + } + } + + private def populateRecordTemplate( + appId: AppId, + screenshots: ScreenshotsSuite + ): String = { + val title = s"Record results: $appId" + val numberOfTests = screenshots.size + val summaryResults = + s"$numberOfTests screenshot tests recorded." + val summaryTableBody = generateRecordSummaryTableBody(screenshots) + recordIndexTemplate( + title = title, + summaryResult = summaryResults, + summaryTableBody = summaryTableBody + ) + } + + private def generateRecordSummaryTableBody(screenshots: ScreenshotsSuite): String = { + screenshots + .map { (screenshot: Screenshot) => + val testClass = screenshot.testClass + val testName = screenshot.testName + val originalScreenshot = "./images/recorded/" + screenshot.name + ".png" + val width = (screenshot.screenshotDimension.width * 0.2).toInt + val screenshotName = screenshot.name + "Test class: $testClass
" + + s"Test name: $testName
" + + s"Screenshot name: $screenshotName
Test class: $testClass
" + + s"Test name: $testName
Screenshot name: $screenshotName
" + + s"Test class: $testClass
" + + s"Test name: $testName
" + + s"Screenshot name: $screenshotName
🔎 Recorded screenshot not found.
" + case DifferentScreenshots(_, _) => + "🤔 The application UI has been modified.
" + case DifferentImageDimensions(_, _, _) => + "📱 The size of the screenshot taken has changed.
" + case _ => + "😞 Ups! Something went wrong while comparing your screenshots but we couldn't identify the cause. If you think you've found a bug, please open an issue at https://github.com/karumi/shot.
" + } + .getOrElse("") +} diff --git a/core/src/main/scala/com/karumi/shot/reports/JunitExecutionReporter.scala b/core/src/main/scala/com/karumi/shot/reports/JunitExecutionReporter.scala new file mode 100644 index 00000000..eb9abee7 --- /dev/null +++ b/core/src/main/scala/com/karumi/shot/reports/JunitExecutionReporter.scala @@ -0,0 +1,131 @@ +package com.karumi.shot.reports + +import com.karumi.shot.domain.{DifferentImageDimensions, DifferentScreenshots, Screenshot, ScreenshotComparisonError, ScreenshotNotFound, ScreenshotsComparisionResult, ShotFolder} +import com.karumi.shot.domain.model.{AppId, ScreenshotComparisionErrors, ScreenshotsSuite} + +import java.io.{File, FileWriter} +import scala.collection.IterableOnce.iterableOnceExtensionMethods +import scala.language.postfixOps + +class JunitExecutionReporter extends ExecutionReporter { + + def generateRecordReport( + appId: AppId, + screenshots: ScreenshotsSuite, + shotFolder: ShotFolder + ): Unit = () + + def generateVerificationReport( + appId: AppId, + comparision: ScreenshotsComparisionResult, + shotFolder: ShotFolder, + showOnlyFailingTestsInReports: Boolean = false + ): Unit = { + val reportFileContents = + populateVerificationTemplate(appId, comparision) + resetVerificationReport(shotFolder) + val reportFolder = shotFolder.verificationReportFolder() + writeReport(reportFileContents, reportFolder) + } + + private def writeReport( + fileContents: String, + reportFolder: String + ): Unit = { + val indexFile = new File(reportFolder + "TEST-Shot.xml") + new File(reportFolder).mkdirs() + val writer = new FileWriter(indexFile) + writer.write(fileContents) + writer.close() + } + + private def resetVerificationReport(shotFolder: ShotFolder) = { + val file = new File(shotFolder.reportFolder() + "TEST-Shot.xml") + if (file.exists()) { + file.delete() + } + } + + private def populateVerificationTemplate( + appId: AppId, + comparision: ScreenshotsComparisionResult + ): String = { + val title = s"Screenshot results: $appId" + val summaryTableBody = + generateVerificationSummaryTableBody(comparision) + report( + title, + summaryTableBody + ) + } + + private def report(title: String, testResults: String): String = { + s"""| + |