Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add new test report format: HTML #1750

Merged
merged 18 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions maestro-cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ tasks.named<JavaExec>("run") {
}

dependencies {
val kotlinxHtmlVersion = "0.8.0"
implementation(project(path = ":maestro-utils"))
annotationProcessor(libs.picocli.codegen)

Expand All @@ -48,6 +49,7 @@ dependencies {
implementation(libs.ktor.client.cio)
implementation(libs.jarchivelib)
implementation(libs.commons.codec)
implementation("org.jetbrains.kotlinx:kotlinx-html:$kotlinxHtmlVersion")

testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
Expand Down
127 changes: 127 additions & 0 deletions maestro-cli/src/main/java/maestro/cli/report/HtmlTestSuiteReporter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package maestro.cli.report

import maestro.cli.model.TestExecutionSummary
import maestro.cli.report.TestDebugReporter
import okio.Sink
import okio.buffer
import java.io.BufferedReader
import java.io.FileReader
import kotlinx.html.*
import kotlinx.html.stream.appendHTML

class HtmlTestSuiteReporter : TestSuiteReporter {
override fun report(summary: TestExecutionSummary, out: Sink) {
val bufferedOut = out.buffer()
val htmlContent = buildHtmlReport(summary)
bufferedOut.writeUtf8(htmlContent)
bufferedOut.close()
}

private fun getFailedTest(summary: TestExecutionSummary): Array<String>{
var failedTest = emptyArray<String>()
for (suite in summary.suites) {
for(flow in suite.flows){
if(flow.status.toString() == "ERROR"){
failedTest += flow.name
}
}
}
return failedTest
}

private fun buildHtmlReport(summary: TestExecutionSummary): String {
var failedTest = getFailedTest(summary)
return buildString {
appendHTML().html {
head {
title { +"Maestro Test Report" }
link(rel = "stylesheet", href = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css") {}
}
body {
summary.suites.forEach { suite ->
div(classes = "card mb-4") {
div(classes = "card-body") {
h1(classes = "mt-5 text-center") { +"Flow Execution Summary" }
br{}
+"Test Result: ${if (suite.passed) "PASSED" else "FAILED"}"
br{}
+"Duration: ${suite.duration}"
br{}
br{}
div(classes = "card-group mb-4") {
div(classes = "card") {
div(classes = "card-body") {
h5(classes = "card-title text-center") { +"Total number of Flows" }
h3(classes = "card-text text-center") { +"${suite.flows.size}" }
}
}
div(classes = "card text-white bg-danger") {
div(classes = "card-body") {
h5(classes = "card-title text-center") { +"Failed Flows" }
h3(classes = "card-text text-center") { +"${failedTest.size}" }
}
}
div(classes = "card text-white bg-success") {
div(classes = "card-body") {
h5(classes = "card-title text-center") { +"Successful Flows" }
h3(classes = "card-text text-center") { +"${suite.flows.size - failedTest.size}" }
}
}
}
if(failedTest.size != 0){
div(classes = "card border-danger mb-3") {
div(classes = "card-body text-danger") {
b { +"Failed Flow" }
br{}
p(classes = "card-text") {
failedTest.forEach { test ->
+"${test}"
br{}
}
}
}
}
}
suite.flows.forEach { flow ->
val buttonClass = if (flow.status.toString() == "ERROR") "btn btn-danger" else "btn btn-success"
div(classes = "card mb-4") {
div(classes = "card-header") {
h5(classes = "mb-0") {
button(classes = "$buttonClass") {
attributes["type"] = "button"
attributes["data-bs-toggle"] = "collapse"
attributes["data-bs-target"] = "#${flow.name}"
attributes["aria-expanded"] = "false"
attributes["aria-controls"] = "${flow.name}"
+"${flow.name} : ${flow.status}"
}
}
}
div(classes = "collapse") {
id = "${flow.name}"
div(classes = "card-body") {
p(classes = "card-text") {
+"Status: ${flow.status}"
br{}
+"Duration: ${flow.duration}"
br{}
+"File Name: ${flow.fileName}"
}
if(flow.failure != null) {
p(classes = "card-text text-danger"){
+"${flow.failure.message}"
}
}
}
}
}
}
}
script(src = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js", content = "")
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ enum class ReportFormat(
) {

JUNIT(".xml"),
HTML(".html"),
NOOP(null),

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package maestro.cli.report

import maestro.cli.model.TestExecutionSummary
import okio.BufferedSink

object ReporterFactory {

fun buildReporter(format: ReportFormat, testSuiteName: String?): TestSuiteReporter {
return when (format) {
ReportFormat.JUNIT -> JUnitTestSuiteReporter.xml(testSuiteName)
ReportFormat.NOOP -> TestSuiteReporter.NOOP
ReportFormat.HTML -> HtmlTestSuiteReporter()
}
}

Expand Down
Loading