/
HtmlTestResult.cfc
261 lines (221 loc) · 10.2 KB
/
HtmlTestResult.cfc
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
<!---
Extension of TestResult
--->
<cfcomponent displayname="HTMLTestResult" output="true" extends="TestResult" hint="Responsible for generating HTML representation of a TestResult">
<cfparam name="this.testResults" type="any" default="" />
<cffunction name="HTMLTestResult" hint="Constructor" access="public" returntype="HTMLTestResult">
<cfargument name="testResults" type="TestResult" required="false" />
<cfset this.testRuns = arguments.testResults.testRuns />
<cfset this.failures = arguments.testResults.testFailures />
<cfset this.errors = arguments.testResults.testErrors />
<cfset this.successes = arguments.testResults.testSuccesses />
<cfset this.totalExecutionTime = arguments.testResults.totalExecutionTime />
<cfset this.testResults = arguments.testResults.results />
<cfset this.installRoot = createObject("component","ComponentUtils").getInstallRoot() />
<cfset totalBad = this.failures+this.errors />
<cfif totalBad eq 0 >
<cfset this.sucessRatio = 1 />
<cfelse>
<cfset this.sucessRatio = 1-(totalBad/this.testRuns) />
</cfif>
<!---
iif( this.failures+this.errors eq 0, 1, this.failures+this.errors )
double prod = 0.0;
double errorsAndFailures = (double) this.totalErrors + (double) this.totalFailures;
if (this.totalTestRuns > 0) {
prod = (errorsAndFailures / (double) this.totalTestRuns);
}
return (1 - prod);
--->
<cfreturn this />
</cffunction>
<!--- bill : 3.7.10
Todo: Make sure it works with no external CSS or JavaScript. Maybe redirect to old XMLResult if JS is not enabled?
Todo: Filter should work with components. That is, when filtering results of a TestSuite, if suite
doesn't contain filter items (empty) it should not display.
--->
<cffunction name="printResources" access="public" output="true" hint="Prints CSS and JavaScript refs for stylizing">
<cfargument name="mxunit_root" required="no" default="./mxunit" hint="Location in the webroot where MXUnit is installed." />
<cfargument name="test_title" required="false" default="MXUnit Test Results" offhint="An HTML title to display for this test" />
<link rel="stylesheet" type="text/css" href="#mxunit_root#/resources/theme/styles.css">
<link rel="stylesheet" type="text/css" href="#mxunit_root#/resources/jquery/tablesorter/green/style.css">
<link rel="stylesheet" type="text/css" href="#mxunit_root#/resources/theme/results.css">
<link rel="stylesheet" type="text/css" href="#mxunit_root#/resources/jquery/tipsy/stylesheets/tipsy.css">
<script type="text/javascript" src="#mxunit_root#/resources/jquery/jquery.min.js"></script>
<script type="text/javascript" src="#mxunit_root#/resources/jquery/jquery-ui.min.js"></script>
<script type="text/javascript" src="#mxunit_root#/resources/jquery/jquery.sparkline.min.js"></script>
<script type="text/javascript" src="#mxunit_root#/resources/jquery/tablesorter/jquery.tablesorter.js"></script>
<script type="text/javascript" src="#mxunit_root#/resources/jquery/tipsy/javascripts/jquery.tipsy.js"></script>
<script type="text/javascript" src="#mxunit_root#/resources/jquery/jquery.runner.js"></script>
<title>#test_title#</title>
</cffunction>
<cffunction name="getHtmlResults" access="public" returntype="string" output="false" hint="Returns a stylized HTML representation of the TestResult">
<cfargument name="mxunit_root" required="no" default="#this.installRoot#" hint="Location in the webroot where MXUnit is installed." />
<cfargument name="test_title" required="false" default="MXUnit Test Results" hint="An HTML title to display for this test">
<cfset var result = "" />
<cfset var temp = "" />
<cfsavecontent variable="result">
<cfset printResources(mxunit_root,test_title) />
<cfoutput>#trim(getRawHtmlResults(mxunit_root))#</cfoutput>
</cfsavecontent>
<cfreturn result>
</cffunction>
<cffunction name="getRawHtmlResults" access="public" returntype="string" output="false" hint="Returns a _raw_ HTML representation of the TestResult">
<cfargument name="mxunit_root" required="no" default="#this.installRoot#" hint="Location in the webroot where MXUnit is installed." />
<cfset var result = "" />
<cfset var classname = "" />
<cfset var i = "" />
<cfset var k = "" />
<cfset var isNewComponent = false />
<cfset var tableHead = '' />
<cfset var theme = "pass" />
<cfset var debugMessage = "Run with verbose debug output." />
<cfset var toggledUrl = "" />
<cfif this.successes neq this.testRuns>
<cfset theme = "fail" />
</cfif>
<cfsavecontent variable="tableHead">
<thead>
<tr>
<th class="test">Test</th>
<th class="error">Error Info</th>
<th class="output">Output</th>
<th class="result">Result</th>
<th class="speed">Speed</th>
</tr>
</thead>
</cfsavecontent>
<cfsavecontent variable="result">
<cfoutput>
<div class="mxunitResults">
<div class="summary">
<ul class="nav horizontal">
<li class="failed">
<a href="##" rel="tipsy" title="Filter by Failures">#this.failures# Failures</a>
</li>
<li class="error">
<a href="##" rel="tipsy" title="Filter by Errors">#this.errors# Errors</a>
</li>
<li class="passed">
<a href="##" rel="tipsy" title="Filter by Successes">#this.successes# Successes</a>
</li>
</ul>
<!-- brain no working, but this does --->
<cfif find('debug=true',cgi.QUERY_STRING)>
<cfset toggledUrl = cgi.SCRIPT_NAME & '?' & replace(cgi.QUERY_STRING,'debug=true','debug=false') />
<cfset bugMessage = 'Run without debug output.' />
<cfelseif find('debug=false',cgi.QUERY_STRING)>
<cfset toggledUrl = cgi.SCRIPT_NAME & '?' & replace(cgi.QUERY_STRING,'debug=false','debug=true') />
<cfset bugMessage = 'Run with verbose debug output.' />
<cfelse>
<cfset toggledUrl = cgi.SCRIPT_NAME & '?' & cgi.QUERY_STRING & '&debug=true' />
<cfset bugMessage = 'Run with verbose debug output.' />
</cfif>
<div id="bugjar">
<a id="bug" href="#toggledUrl#" rel="tipsy" title="#bugMessage#"><img border="0" height="24" align="absmiddle" src="#mxunit_root#/images/bug_green.gif"></a>
</div>
<cfset sparkTitle = "#this.testRuns# tests in #this.totalExecutionTime#ms. Success ratio #int(this.sucessRatio*100)#%">
<div id="sparkcontainer" rel="tipsy" title="#sparkTitle#">
<span class="mxunittestsparks">
Replace this in HTMLTestResult <cfscript>
//generate data for sparkline
for(i=1;i lte this.failures;i=i+1){
writeoutput(-1 & ",");
}
for(i=1;i lte this.errors;i=i+1){
writeoutput(-2 & ",");
}
for(i=1;i lte this.successes;i=i+1){
writeoutput(1 & ",");
}
i=1;
</cfscript>
</span>
</div>
<div class="clear"><!-- clear --></div>
</div>
<div>#sparkTitle#</div>
<cfloop from="1" to="#ArrayLen(this.testResults)#" index="i">
<!--- Check if we are on a new component --->
<cfset isNewComponent = classname neq this.testResults[i].component />
<cfif isNewComponent>
<!--- If this is not the first component close the previous one --->
<cfif classname neq ''>
</tbody>
</table>
</cfif>
<cfset classname = this.testResults[i].component>
<!--- printing incorrect results for MXUnitInstallTest.cfc - could be engine bug --->
<cfset classtesturl = CGI.CONTEXT_PATH & "/" & Replace(this.testResults[i].component, ".", "/", "all") & ".cfc?method=runtestremote&output=html">
<h3><a href="#classtesturl#" title="Run all tests in #this.testResults[i].component#">#this.testResults[i].component#</a></h3>
<table class="results tablesorter #theme#">
#tableHead#
<tbody>
</cfif>
<tr class="#lCase(this.testResults[i].TestStatus)#">
<td class="test">
<a href="#classtesturl#&testmethod=#this.testResults[i].TestName#" title="only run the #this.testResults[i].TestName# test">#this.testResults[i].TestName#</a>
</td>
<td class="error">
#renderErrorStruct(this.testResults[i].Error)#
</td>
<td class="output">
<cfif find('debug=true',cgi.QUERY_STRING)>
<cfif ArrayLen(this.testResults[i].Debug)>
<cfloop from="1" to="#ArrayLen(this.testResults[i].Debug)#" index="k">
<cfif IsSimpleValue(this.testResults[i].Debug[k].var)>
#this.testResults[i].Debug[k].var#<br />
<cfelse>
<cfdump attributecollection="#this.testResults[i].Debug[k]#">
</cfif>
</cfloop>
</cfif>
</cfif>
</td>
<td class="result">
#this.testResults[i].TestStatus#
</td>
<td class="speed">
#this.testResults[i].Time# ms
</td>
</tr>
</cfloop>
</tbody>
</table>
</div>
</cfoutput>
</cfsavecontent>
<cfreturn Trim(result) />
</cffunction>
<cffunction name="renderErrorStruct" output="false" returntype="string" access="private" hint="I render a coldfusion error struct as HTML">
<cfargument name="ErrorCollection" required="true" type="any">
<cfset var result = "" />
<cfset var i = 0 />
<cfset var template = "" />
<cfset var line = "" />
<cfif NOT IsSimpleValue(arguments.ErrorCollection)>
<cfsavecontent variable="result">
<cfoutput>
<cfif Left(arguments.ErrorCollection.Message, 2) neq "::">
<strong>#Replace(arguments.ErrorCollection.Message,"::","<br />")#</strong> <br />
<pre style="width:100%;">#arguments.ErrorCollection.Detail#</pre>
<cfelse>
#arguments.ErrorCollection.Message#
</cfif>
<table class="tagcontext">
<cfloop from="1" to="#ArrayLen(arguments.ErrorCollection.TagContext)#" index="i">
<cfset template = arguments.ErrorCollection.TagContext[i].template />
<cfset line = arguments.ErrorCollection.TagContext[i].line />
<tr>
<td>
#template# (<a href="txmt://open/?url=file://#template#&line=#line#" title="Open this in TextMate">#line#</a>)
</td>
</tr>
</cfloop>
</table>
</cfoutput>
</cfsavecontent>
</cfif>
<cfreturn result />
</cffunction>
</cfcomponent>