Skip to content

Commit

Permalink
add new test report format: HTML (#1750)
Browse files Browse the repository at this point in the history
* initial work

* add log reader to failed test report

* remove button & add missing end <div> tag

* using collapse

* add missing div close tag

* add function to get test step

* disable lint

* using collapse for test step

* add total test summary

* Update maestro-cli/src/main/java/maestro/cli/report/ReporterFactory.kt

Co-authored-by: Axel Niklasson <axel.r.niklasson@gmail.com>

* remove NoOpReporter.kt

* revert TestCommand.kt changes & remove disable lint

* revamp html builder

* Revert "revamp html builder"

This reverts commit c3d1feb.

* revamp html builder

* Update maestro-cli/src/main/java/maestro/cli/report/HtmlTestSuiteReporter.kt

Co-authored-by: Axel Niklasson <axel.r.niklasson@gmail.com>

* Apply suggestions from code review

Co-authored-by: Axel Niklasson <axel.r.niklasson@gmail.com>

---------

Co-authored-by: fitriahfebriani <fitriahfebriani19@gmail.com>
Co-authored-by: Axel Niklasson <axel.r.niklasson@gmail.com>
  • Loading branch information
3 people authored May 24, 2024
1 parent 082b0b9 commit 4b1547d
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 0 deletions.
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

0 comments on commit 4b1547d

Please sign in to comment.