From 690680f987a6616e83a977e6242cb9053dd26e2f Mon Sep 17 00:00:00 2001 From: eric gilbertson Date: Sun, 29 Mar 2015 18:26:20 -0700 Subject: [PATCH 1/5] Enclose each test group in a bootstrap panel - tweak default margins for more compact layout - store open/close state in local storage - restore open/close state on page refresh --- testrunner/app/views/TestRunner/Index.html | 276 +++++++++++++-------- 1 file changed, 178 insertions(+), 98 deletions(-) diff --git a/testrunner/app/views/TestRunner/Index.html b/testrunner/app/views/TestRunner/Index.html index 712dbc9..6d0c76a 100644 --- a/testrunner/app/views/TestRunner/Index.html +++ b/testrunner/app/views/TestRunner/Index.html @@ -1,110 +1,190 @@ - - Revel Test Runner - - - - - - - - - -
-
-
-

Test Runner

-

Run all of your application's tests from here.

-
- -
-
-
+ + Revel Test Runner + + + + + + + + + +
+
+

Test Runner - Run your unit tests here.

+
+ +
+
+
+
+
+ {{range .testSuites}} + {{ $testFile := .Name }} +
+
+ +  {{.Name}} +
+
+ + {{range .Tests}} + + + + + + {{end}} +
  {{ .Name }}
+
+
+ {{end}} +
-
- {{range .testSuites}} -

{{.Name}}

- - {{range .Tests}} - - - - - - {{end}} -
{{.Name}} -
- {{end}} -
+ + $("button[all-tests]").click(function() { + $("tr").removeClass("passed").removeClass("failed"); + passCount = 0; + failCount = 0; + var button = $(this).addClass("disabled").text("Running"); + $("button.leftbutton[test]").click(); + }); - + $("a.collapseLnk").click(function() { + var tableId = $(this).data("target"); + var visible = !$(tableId).is(":visible"); + localStorage.setItem("testrunner_" + tableId, visible); + }); + + function addToQueue(button) { + buttons.push(button); + if (!running) { + running = true; + nextTest(); + } + } + + function nextTest() { + if (buttons.length == 0) { + running = false; + } else { + var next = buttons.shift(); + runTest(next); + } + } + + function runTest(button) { + var suite = button.parents("table").attr("suite"); + var test = button.attr("test"); + var row = button.parents("tr"); + var resultCell = row.children(".result"); + $.ajax({ + dataType: "json", + url: "{{url `Root`}}/@tests/"+suite+"/"+test, + success: function(result) { + row.attr("class", result.Passed ? "passed" : "failed"); + if (result.Passed) { + console.log("pass: " + result.Name); + passCount++; + resultCell.html(""); + } else { + console.log("fail: result.Name"); + failCount++; + resultCell.html(result.ErrorHtml); + + $("#result_" + suite + "_" + test + " pre code").each(function(i, block) { + hljs.highlightBlock(block); + }); + } + button.removeClass("disabled").text("Run"); + var runAllBut = $("button[all-tests]"); + if (buttons.length == 0 && runAllBut.hasClass("disabled")) { + runAllBut.removeClass("disabled").text("Run All Tests"); + var resMsg = passCount + " passed, " + failCount + " failed."; + $("#allTestResults").text(resMsg); + } + nextTest(); + } + }); + } + + + From 47e9ef41b321300d9c12196640e537fc6bf4cfe2 Mon Sep 17 00:00:00 2001 From: eric gilbertson Date: Sun, 29 Mar 2015 18:31:51 -0700 Subject: [PATCH 2/5] change tabs to spaces. --- testrunner/app/views/TestRunner/Index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testrunner/app/views/TestRunner/Index.html b/testrunner/app/views/TestRunner/Index.html index 6d0c76a..f4082db 100644 --- a/testrunner/app/views/TestRunner/Index.html +++ b/testrunner/app/views/TestRunner/Index.html @@ -78,13 +78,13 @@

Test Runner - Run your unit tests here. Date: Tue, 21 Apr 2015 08:54:42 -0700 Subject: [PATCH 3/5] Display test suites in sorted order Improve error reporting on test runner page: - display condensed error msg, e.g panic msg and file/line # - hide extended error display, e.g. strack trace and error info - toggle display of extended display when error summary is clicked - reduce width of right col to provide more space for error msg - clear error display when test is run --- testrunner/app/controllers/testrunner.go | 31 +++++++++++++++++++++- testrunner/app/views/TestRunner/Index.html | 21 ++++++++++----- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/testrunner/app/controllers/testrunner.go b/testrunner/app/controllers/testrunner.go index 5982ef7..8a89fc0 100644 --- a/testrunner/app/controllers/testrunner.go +++ b/testrunner/app/controllers/testrunner.go @@ -6,6 +6,7 @@ import ( "fmt" "html/template" "reflect" + "sort" "strings" "github.com/revel/revel" @@ -191,7 +192,25 @@ func describeSuite(testSuite interface{}) TestSuiteDesc { // errorSummary gets an error and returns its summary in human readable format. func errorSummary(err *revel.Error) (message string) { - message = fmt.Sprintf("%4sStatus: %s\n%4sIn %s", "", err.Description, "", err.Path) + EXPECTED_PREFIX := "(expected)" + ACTUAL_SUFFIX := "(actual)" + errDesc := err.Description + //strip the actual/expected stuff to provide more condensed display. + if strings.Index(errDesc, EXPECTED_PREFIX) == 0 { + errDesc = errDesc[len(EXPECTED_PREFIX):len(errDesc)] + } + if strings.LastIndex(errDesc, ACTUAL_SUFFIX) > 0 { + errDesc = errDesc[0 : len(errDesc)-len(ACTUAL_SUFFIX)] + } + + errFile := err.Path + slashIdx := strings.LastIndex(errFile, "/") + if slashIdx > 0 { + errFile = errFile[slashIdx+1 : len(errFile)] + } + + message = fmt.Sprintf("%s %s#%d", errDesc, errFile, err.Line) + return // If line of error isn't known return the message as is. if err.Line == 0 { @@ -234,6 +253,15 @@ func formatResponse(t testing.TestSuite) map[string]string { } } +//functions needed to sort the testsuites by name. +type SortBySuiteName []interface{} + +func (a SortBySuiteName) Len() int { return len(a) } +func (a SortBySuiteName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a SortBySuiteName) Less(i, j int) bool { + return reflect.TypeOf(a[i]).Elem().Name() < reflect.TypeOf(a[j]).Elem().Name() +} + func init() { // Every time app is restarted convert the list of available test suites // provided by the revel testing package into a format which will be used by @@ -241,6 +269,7 @@ func init() { revel.OnAppStart(func() { // Extracting info about available test suites from revel/testing package. registeredTests = map[string]int{} + sort.Sort(SortBySuiteName(testing.TestSuites)) for _, testSuite := range testing.TestSuites { testSuites = append(testSuites, describeSuite(testSuite)) } diff --git a/testrunner/app/views/TestRunner/Index.html b/testrunner/app/views/TestRunner/Index.html index f4082db..eb9eb6c 100644 --- a/testrunner/app/views/TestRunner/Index.html +++ b/testrunner/app/views/TestRunner/Index.html @@ -18,7 +18,9 @@ .table > tbody > tr > td { padding-top:1px; padding-bottom:2px; vertical-align: middle; } .passed td { background-color: #90EE90 !important; } .failed td { background-color: #FFB6C1 !important; } - .tests td.name, .tests td.result { } + td.result div.panel-default{ display:none; } + td.result > a { color: red; } + td.rightCol { width: 40px; } pre { font-size:10px; white-space: pre; } .panel-heading { padding: 2px 2px @@ -33,7 +35,7 @@ .panel-heading a.collapsed:after { content:"\25b6"; } - .name { width: 50%; } + .name { width: 35%; } .w100 { width: 100%; } @@ -60,8 +62,8 @@

Test Runner - Run your unit tests here.   {{ .Name }} - - + + {{end}} @@ -110,6 +112,11 @@

Test Runner - Run your unit tests here. Test Runner - Run your unit tests here. Test Runner - Run your unit tests here. Date: Wed, 22 Apr 2015 09:35:46 -0700 Subject: [PATCH 4/5] Update per comments from anon - make sorting interface private - make local string constants LC - comment out unused code --- testrunner/app/controllers/testrunner.go | 49 ++++++++++++------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/testrunner/app/controllers/testrunner.go b/testrunner/app/controllers/testrunner.go index 8a89fc0..bbf3f74 100644 --- a/testrunner/app/controllers/testrunner.go +++ b/testrunner/app/controllers/testrunner.go @@ -192,15 +192,15 @@ func describeSuite(testSuite interface{}) TestSuiteDesc { // errorSummary gets an error and returns its summary in human readable format. func errorSummary(err *revel.Error) (message string) { - EXPECTED_PREFIX := "(expected)" - ACTUAL_SUFFIX := "(actual)" + expected_prefix := "(expected)" + actual_prefix := "(actual)" errDesc := err.Description //strip the actual/expected stuff to provide more condensed display. - if strings.Index(errDesc, EXPECTED_PREFIX) == 0 { - errDesc = errDesc[len(EXPECTED_PREFIX):len(errDesc)] + if strings.Index(errDesc, expected_prefix) == 0 { + errDesc = errDesc[len(expected_prefix):len(errDesc)] } - if strings.LastIndex(errDesc, ACTUAL_SUFFIX) > 0 { - errDesc = errDesc[0 : len(errDesc)-len(ACTUAL_SUFFIX)] + if strings.LastIndex(errDesc, actual_prefix) > 0 { + errDesc = errDesc[0 : len(errDesc)-len(actual_prefix)] } errFile := err.Path @@ -210,21 +210,22 @@ func errorSummary(err *revel.Error) (message string) { } message = fmt.Sprintf("%s %s#%d", errDesc, errFile, err.Line) - return - // If line of error isn't known return the message as is. - if err.Line == 0 { - return - } + /* + // If line of error isn't known return the message as is. + if err.Line == 0 { + return + } - // Otherwise, include info about the line number and the relevant - // source code lines. - message += fmt.Sprintf(" (around line %d): ", err.Line) - for _, line := range err.ContextSource() { - if line.IsError { - message += line.Source + // Otherwise, include info about the line number and the relevant + // source code lines. + message += fmt.Sprintf(" (around line %d): ", err.Line) + for _, line := range err.ContextSource() { + if line.IsError { + message += line.Source + } } - } + */ return } @@ -253,12 +254,12 @@ func formatResponse(t testing.TestSuite) map[string]string { } } -//functions needed to sort the testsuites by name. -type SortBySuiteName []interface{} +//sortbySuiteName sorts the testsuites by name. +type sortBySuiteName []interface{} -func (a SortBySuiteName) Len() int { return len(a) } -func (a SortBySuiteName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a SortBySuiteName) Less(i, j int) bool { +func (a sortBySuiteName) Len() int { return len(a) } +func (a sortBySuiteName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a sortBySuiteName) Less(i, j int) bool { return reflect.TypeOf(a[i]).Elem().Name() < reflect.TypeOf(a[j]).Elem().Name() } @@ -269,7 +270,7 @@ func init() { revel.OnAppStart(func() { // Extracting info about available test suites from revel/testing package. registeredTests = map[string]int{} - sort.Sort(SortBySuiteName(testing.TestSuites)) + sort.Sort(sortBySuiteName(testing.TestSuites)) for _, testSuite := range testing.TestSuites { testSuites = append(testSuites, describeSuite(testSuite)) } From 856db5e91784338b3174074348d6a25f5362a9d0 Mon Sep 17 00:00:00 2001 From: eric gilbertson Date: Sun, 7 Jun 2015 18:22:50 -0700 Subject: [PATCH 5/5] Expand closed panels if there is a failed test * test suite panel is opened if it is closed and there is an error * vertically center the "Run All Tests" button * remove some log messages * increase size of Run button --- testrunner/app/views/TestRunner/Index.html | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/testrunner/app/views/TestRunner/Index.html b/testrunner/app/views/TestRunner/Index.html index eb9eb6c..61f0991 100644 --- a/testrunner/app/views/TestRunner/Index.html +++ b/testrunner/app/views/TestRunner/Index.html @@ -12,7 +12,7 @@ header { background-color:#ADD8E6 } header h1 {margin-top: 10px; margin-bottom:20px;} header table {margin-bottom: 0px } - td .btn {margin-bottom: 1px; line-height: 1.0} + td .btn {margin-bottom: 1px; } button.file-test { margin-bottom: 0px; margin-left: 2px } table.tests tr { border-bottom: 1px solid #ddd; background-color: #f9f9f9; } .table > tbody > tr > td { padding-top:1px; padding-bottom:2px; vertical-align: middle; } @@ -43,7 +43,7 @@

Test Runner - Run your unit tests here.

-
+
@@ -54,8 +54,8 @@

Test Runner - Run your unit tests here.
- -  {{.Name}} + +  {{.Name}}
@@ -98,9 +98,10 @@

Test Runner - Run your unit tests here. = 0) { + badRows[0].scrollIntoView(); + } return false; }); @@ -170,14 +171,19 @@

Test Runner - Run your unit tests here.