/
Shot.scala
163 lines (145 loc) · 6.36 KB
/
Shot.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package com.karumi.shot
import java.io.File
import com.karumi.shot.android.Adb
import com.karumi.shot.domain._
import com.karumi.shot.domain.model.{AppId, Folder, ScreenshotsSuite}
import com.karumi.shot.reports.{ConsoleReporter, ExecutionReporter}
import com.karumi.shot.screenshots.{
ScreenshotsComparator,
ScreenshotsDiffGenerator,
ScreenshotsSaver
}
import com.karumi.shot.ui.Console
import com.karumi.shot.xml.ScreenshotsSuiteXmlParser._
import org.apache.commons.io.FileUtils
object Shot {
private val appIdErrorMessage =
"🤔 Error found executing screenshot tests. The appId param is not configured properly. You should configure the appId following the plugin instructions you can find at https://github.com/karumi/shot"
}
class Shot(adb: Adb,
files: Files,
screenshotsComparator: ScreenshotsComparator,
screenshotsDiffGenerator: ScreenshotsDiffGenerator,
screenshotsSaver: ScreenshotsSaver,
console: Console,
reporter: ExecutionReporter,
consoleReporter: ConsoleReporter) {
import Shot._
def configureAdbPath(adbPath: Folder): Unit = {
Adb.adbBinaryPath = adbPath
}
def downloadScreenshots(projectFolder: Folder, appId: Option[AppId]): Unit =
executeIfAppIdIsValid(appId) { applicationId =>
console.show("⬇️ Pulling screenshots from your connected devices!")
pullScreenshots(projectFolder, applicationId)
}
def recordScreenshots(appId: AppId,
buildFolder: Folder,
projectFolder: Folder,
projectName: String): Unit = {
console.show("💾 Saving screenshots.")
val screenshots = readScreenshotsMetadata(projectFolder, projectName)
screenshotsSaver.saveRecordedScreenshots(projectFolder, screenshots)
screenshotsSaver.copyRecordedScreenshotsToTheReportFolder(
projectFolder,
buildFolder + Config.recordingReportFolder + "/images/recorded/")
console.show(
"😃 Screenshots recorded and saved at: " + projectFolder + Config.screenshotsFolderName)
reporter.generateRecordReport(appId, screenshots, buildFolder)
console.show(
"🤓 You can review the execution report here: " + buildFolder + Config.recordingReportFolder + "/index.html")
removeProjectTemporalScreenshotsFolder(projectFolder)
}
def verifyScreenshots(
appId: AppId,
buildFolder: Folder,
projectFolder: Folder,
projectName: String,
shouldPrintBase64Error: Boolean): ScreenshotsComparisionResult = {
console.show("🔎 Comparing screenshots with previous ones.")
val screenshots = readScreenshotsMetadata(projectFolder, projectName)
val newScreenshotsVerificationReportFolder = buildFolder + Config.verificationReportFolder + "/images/"
screenshotsSaver.saveTemporalScreenshots(
screenshots,
projectName,
newScreenshotsVerificationReportFolder)
val comparision = screenshotsComparator.compare(screenshots)
val updatedComparision = screenshotsDiffGenerator.generateDiffs(
comparision,
newScreenshotsVerificationReportFolder,
shouldPrintBase64Error)
screenshotsSaver.copyRecordedScreenshotsToTheReportFolder(
projectFolder,
buildFolder + Config.verificationReportFolder + "/images/recorded/")
if (updatedComparision.hasErrors) {
consoleReporter.showErrors(updatedComparision,
newScreenshotsVerificationReportFolder)
} else {
console.showSuccess("✅ Yeah!!! Your tests are passing.")
}
removeProjectTemporalScreenshotsFolder(projectFolder)
reporter.generateVerificationReport(appId, comparision, buildFolder)
console.show(
"🤓 You can review the execution report here: " + buildFolder + Config.verificationReportFolder + "/index.html")
comparision
}
def removeScreenshots(appId: Option[AppId]): Unit =
executeIfAppIdIsValid(appId) { applicationId =>
clearScreenshots(applicationId)
}
private def executeIfAppIdIsValid(appId: Option[AppId])(f: AppId => Unit) =
appId match {
case Some(applicationId) => f(applicationId)
case None => console.showError(appIdErrorMessage)
}
private def clearScreenshots(appId: AppId): Unit = adb.devices.foreach {
device =>
adb.clearScreenshots(device, appId)
}
private def createScreenshotsFolderIfDoesNotExist(screenshotsFolder: AppId) = {
val folder = new File(screenshotsFolder)
folder.mkdirs()
}
private def pullScreenshots(projectFolder: Folder, appId: AppId): Unit = {
adb.devices.foreach { device =>
val screenshotsFolder = projectFolder + Config.screenshotsFolderName
createScreenshotsFolderIfDoesNotExist(screenshotsFolder)
adb.pullScreenshots(device, screenshotsFolder, appId)
renameMetadataFile(projectFolder, device)
}
}
private def renameMetadataFile(projectFolder: Folder, device: String): Unit = {
val metadataFilePath = projectFolder + Config.metadataFileName
val newMetadataFilePath = metadataFilePath + "_" + device
files.rename(metadataFilePath, newMetadataFilePath)
}
private def readScreenshotsMetadata(
projectFolder: Folder,
projectName: String): ScreenshotsSuite = {
val screenshotsFolder = projectFolder + Config.pulledScreenshotsFolder
val filesInScreenshotFolder = new java.io.File(screenshotsFolder).listFiles
val metadataFiles = filesInScreenshotFolder.filter(file =>
file.getAbsolutePath.contains(Config.metadataFileName))
val screenshotSuite = metadataFiles.flatMap { metadataFilePath =>
val metadataFileContent =
files.read(metadataFilePath.getAbsolutePath)
parseScreenshots(metadataFileContent,
projectName,
projectFolder + Config.screenshotsFolderName,
projectFolder + Config.pulledScreenshotsFolder)
}
screenshotSuite.par.map { screenshot =>
val viewHierarchyContent = files.read(
projectFolder + Config.pulledScreenshotsFolder + screenshot.viewHierarchy)
parseScreenshotSize(screenshot, viewHierarchyContent)
}.toList
}
private def removeProjectTemporalScreenshotsFolder(
projectFolder: Folder): Unit = {
val projectTemporalScreenshots = new File(
projectFolder + Config.pulledScreenshotsFolder)
if (projectTemporalScreenshots.exists()) {
FileUtils.deleteDirectory(projectTemporalScreenshots)
}
}
}