Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: pkg/unittest/lib/html_enhanced_config.dart

Issue 814953002: Remove unittest and matcher from the repo. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/unittest/lib/html_config.dart ('k') | pkg/unittest/lib/html_individual_config.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// A simple unit test library for running tests in a browser.
6 ///
7 /// Provides enhanced HTML output with collapsible group headers
8 /// and other at-a-glance information about the test results.
9 library unittest.html_enhanced_config;
10
11 import 'dart:collection' show LinkedHashMap;
12 import 'dart:convert';
13 import 'dart:html';
14 import 'unittest.dart';
15
16 class HtmlEnhancedConfiguration extends SimpleConfiguration {
17 /// Whether this is run within dartium layout tests.
18 final bool _isLayoutTest;
19 HtmlEnhancedConfiguration(this._isLayoutTest);
20
21 var _onErrorSubscription = null;
22 var _onMessageSubscription = null;
23
24 void _installOnErrorHandler() {
25 if (_onErrorSubscription == null) {
26 // Listen for uncaught errors.
27 _onErrorSubscription = window.onError.listen(
28 (e) => handleExternalError(e, '(DOM callback has errors)'));
29 }
30 }
31
32 void _installOnMessageHandler() {
33 if (_onMessageSubscription == null) {
34 // Listen for errors from JS.
35 _onMessageSubscription = window.onMessage.listen(
36 (e) => processMessage(e));
37 }
38 }
39
40 void _installHandlers() {
41 _installOnErrorHandler();
42 _installOnMessageHandler();
43 }
44
45 void _uninstallHandlers() {
46 if (_onErrorSubscription != null) {
47 _onErrorSubscription.cancel();
48 _onErrorSubscription = null;
49 }
50 if (_onMessageSubscription != null) {
51 _onMessageSubscription.cancel();
52 _onMessageSubscription = null;
53 }
54 }
55
56 void processMessage(e) {
57 if ('unittest-suite-external-error' == e.data) {
58 handleExternalError('<unknown>', '(external error detected)');
59 }
60 }
61
62 void onInit() {
63 _installHandlers();
64 //initialize and load CSS
65 final String _CSSID = '_unittestcss_';
66
67 var cssElement = document.head.querySelector('#${_CSSID}');
68 if (cssElement == null) {
69 cssElement = new StyleElement();
70 cssElement.id = _CSSID;
71 document.head.append(cssElement);
72 }
73
74 cssElement.text = _htmlTestCSS;
75 window.postMessage('unittest-suite-wait-for-done', '*');
76 }
77
78 void onStart() {
79 // Listen for uncaught errors.
80 _installOnErrorHandler();
81 }
82
83 void onSummary(int passed, int failed, int errors, List<TestCase> results,
84 String uncaughtError) {
85 _showInteractiveResultsInPage(passed, failed, errors, results,
86 _isLayoutTest, uncaughtError);
87 }
88
89 void onDone(bool success) {
90 _uninstallHandlers();
91 window.postMessage('unittest-suite-done', '*');
92 }
93
94 void _showInteractiveResultsInPage(int passed, int failed, int errors,
95 List<TestCase> results, bool isLayoutTest, String uncaughtError) {
96 if (isLayoutTest && passed == results.length) {
97 document.body.innerHtml = "PASS";
98 } else {
99 // changed the StringBuffer to an Element fragment
100 Element te = new Element.html('<div class="unittest-table"></div>');
101
102 te.children.add(new Element.html(passed == results.length
103 ? "<div class='unittest-overall unittest-pass'>PASS</div>"
104 : "<div class='unittest-overall unittest-fail'>FAIL</div>"));
105
106 // moved summary to the top since web browsers
107 // don't auto-scroll to the bottom like consoles typically do.
108 if (passed == results.length && uncaughtError == null) {
109 te.children.add(new Element.html("""
110 <div class='unittest-pass'>All ${passed} tests passed</div>"""));
111 } else {
112
113 if (uncaughtError != null) {
114 te.children.add(new Element.html("""
115 <div class='unittest-summary'>
116 <span class='unittest-error'>Uncaught error: $uncaughtError</span>
117 </div>"""));
118 }
119
120 te.children.add(new Element.html("""
121 <div class='unittest-summary'>
122 <span class='unittest-pass'>Total ${passed} passed</span>,
123 <span class='unittest-fail'>${failed} failed</span>,
124 <span class='unittest-error'>
125 ${errors + (uncaughtError == null ? 0 : 1)} errors</span>
126 </div>"""));
127 }
128
129 te.children.add(new Element.html("""
130 <div><button id='btnCollapseAll'>Collapse All</button></div>
131 """));
132
133 // handle the click event for the collapse all button
134 te.querySelector('#btnCollapseAll').onClick.listen((_){
135 document
136 .querySelectorAll('.unittest-row')
137 .forEach((el) => el.attributes['class'] = el.attributes['class']
138 .replaceAll('unittest-row ', 'unittest-row-hidden '));
139 });
140
141 var previousGroup = '';
142 var groupPassFail = true;
143 final indentAmount = 50;
144
145 // order by group and sort numerically within each group
146 var groupedBy = new LinkedHashMap<String, List<TestCase>>();
147
148 for (final t in results) {
149 if (!groupedBy.containsKey(t.currentGroup)) {
150 groupedBy[t.currentGroup] = new List<TestCase>();
151 }
152
153 groupedBy[t.currentGroup].add(t);
154 }
155
156 // flatten the list again with tests ordered
157 List<TestCase> flattened = new List<TestCase>();
158
159 groupedBy
160 .values
161 .forEach((tList){
162 tList.sort((tcA, tcB) => tcA.id - tcB.id);
163 flattened.addAll(tList);
164 }
165 );
166
167 var nonAlphanumeric = new RegExp('[^a-z0-9A-Z]');
168
169 // output group headers and test rows
170 for (final test_ in flattened) {
171
172 // replace everything but numbers and letters from the group name with
173 // '_' so we can use in id and class properties.
174 var safeGroup = test_.currentGroup.replaceAll(nonAlphanumeric, '_');
175
176 if (test_.currentGroup != previousGroup) {
177
178 previousGroup = test_.currentGroup;
179
180 var testsInGroup = results
181 .where((TestCase t) => t.currentGroup == previousGroup)
182 .toList();
183 var groupTotalTestCount = testsInGroup.length;
184 var groupTestPassedCount = testsInGroup.where(
185 (TestCase t) => t.result == 'pass').length;
186 groupPassFail = groupTotalTestCount == groupTestPassedCount;
187 var passFailClass = "unittest-group-status unittest-group-"
188 "status-${groupPassFail ? 'pass' : 'fail'}";
189
190 te.children.add(new Element.html("""
191 <div>
192 <div id='${safeGroup}'
193 class='unittest-group ${safeGroup} test${safeGroup}'>
194 <div ${_isIE ? "style='display:inline-block' ": ""}
195 class='unittest-row-status'>
196 <div class='$passFailClass'></div>
197 </div>
198 <div ${_isIE ? "style='display:inline-block' ": ""}>
199 ${test_.currentGroup}</div>
200 &nbsp;
201 <div ${_isIE ? "style='display:inline-block' ": ""}>
202 (${groupTestPassedCount}/${groupTotalTestCount})</div>
203 </div>
204 </div>"""));
205
206 // 'safeGroup' could be empty
207 var grp = (safeGroup == '') ?
208 null : te.querySelector('#${safeGroup}');
209 if (grp != null) {
210 grp.onClick.listen((_) {
211 var row = document.querySelector('.unittest-row-${safeGroup}');
212 if (row.attributes['class'].contains('unittest-row ')){
213 document.querySelectorAll('.unittest-row-${safeGroup}').forEach(
214 (e) => e.attributes['class'] = e.attributes['class']
215 .replaceAll('unittest-row ', 'unittest-row-hidden '));
216 }else{
217 document.querySelectorAll('.unittest-row-${safeGroup}').forEach(
218 (e) => e.attributes['class'] = e.attributes['class']
219 .replaceAll('unittest-row-hidden', 'unittest-row'));
220 }
221 });
222 }
223 }
224
225 _buildRow(test_, te, safeGroup, !groupPassFail);
226 }
227
228 document.body.children.clear();
229 document.body.children.add(te);
230 }
231 }
232
233 void _buildRow(TestCase test_, Element te, String groupID, bool isVisible) {
234 var background = 'unittest-row-${test_.id % 2 == 0 ? "even" : "odd"}';
235 var display = '${isVisible ? "unittest-row" : "unittest-row-hidden"}';
236
237 addRowElement(id, status, description){
238 te.children.add(
239 new Element.html(
240 ''' <div>
241 <div class='$display unittest-row-${groupID} $background'>
242 <div ${_isIE ? "style='display:inline-block' ": ""}
243 class='unittest-row-id'>$id</div>
244 <div ${_isIE ? "style='display:inline-block' ": ""}
245 class="unittest-row-status unittest-${test_.result}">
246 $status</div>
247 <div ${_isIE ? "style='display:inline-block' ": ""}
248 class='unittest-row-description'>$description</div>
249 </div>
250 </div>'''
251 )
252 );
253 }
254
255 if (!test_.isComplete) {
256 addRowElement('${test_.id}', 'NO STATUS', 'Test did not complete.');
257 return;
258 }
259
260 addRowElement('${test_.id}', '${test_.result.toUpperCase()}',
261 '${test_.description}. ${HTML_ESCAPE.convert(test_.message)}');
262
263 if (test_.stackTrace != null) {
264 addRowElement('', '',
265 '<pre>${HTML_ESCAPE.convert(test_.stackTrace.toString())}</pre>');
266 }
267 }
268
269
270 static bool get _isIE => window.navigator.userAgent.contains('MSIE');
271
272 String get _htmlTestCSS =>
273 '''
274 body{
275 font-size: 14px;
276 font-family: 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande','''
277 ''' sans-serif;
278 background: WhiteSmoke;
279 }
280
281 .unittest-group
282 {
283 background: rgb(75,75,75);
284 width:98%;
285 color: WhiteSmoke;
286 font-weight: bold;
287 padding: 6px;
288 cursor: pointer;
289
290 /* Provide some visual separation between groups for IE */
291 ${_isIE ? "border-bottom:solid black 1px;": ""}
292 ${_isIE ? "border-top:solid #777777 1px;": ""}
293
294 background-image: -webkit-linear-gradient(bottom, rgb(50,50,50) 0%, '''
295 '''rgb(100,100,100) 100%);
296 background-image: -moz-linear-gradient(bottom, rgb(50,50,50) 0%, '''
297 '''rgb(100,100,100) 100%);
298 background-image: -ms-linear-gradient(bottom, rgb(50,50,50) 0%, '''
299 '''rgb(100,100,100) 100%);
300 background-image: linear-gradient(bottom, rgb(50,50,50) 0%, '''
301 '''rgb(100,100,100) 100%);
302
303 display: -webkit-box;
304 display: -moz-box;
305 display: -ms-box;
306 display: box;
307
308 -webkit-box-orient: horizontal;
309 -moz-box-orient: horizontal;
310 -ms-box-orient: horizontal;
311 box-orient: horizontal;
312
313 -webkit-box-align: center;
314 -moz-box-align: center;
315 -ms-box-align: center;
316 box-align: center;
317 }
318
319 .unittest-group-status
320 {
321 width: 20px;
322 height: 20px;
323 border-radius: 20px;
324 margin-left: 10px;
325 }
326
327 .unittest-group-status-pass{
328 background: Green;
329 background: '''
330 '''-webkit-radial-gradient(center, ellipse cover, #AAFFAA 0%,Green 100%);
331 background: '''
332 '''-moz-radial-gradient(center, ellipse cover, #AAFFAA 0%,Green 100%);
333 background: '''
334 '''-ms-radial-gradient(center, ellipse cover, #AAFFAA 0%,Green 100%);
335 background: '''
336 '''radial-gradient(center, ellipse cover, #AAFFAA 0%,Green 100%);
337 }
338
339 .unittest-group-status-fail{
340 background: Red;
341 background: '''
342 '''-webkit-radial-gradient(center, ellipse cover, #FFAAAA 0%,Red 100%);
343 background: '''
344 '''-moz-radial-gradient(center, ellipse cover, #FFAAAA 0%,Red 100%);
345 background: '''
346 '''-ms-radial-gradient(center, ellipse cover, #AAFFAA 0%,Green 100%);
347 background: radial-gradient(center, ellipse cover, #FFAAAA 0%,Red 100%);
348 }
349
350 .unittest-overall{
351 font-size: 20px;
352 }
353
354 .unittest-summary{
355 font-size: 18px;
356 }
357
358 .unittest-pass{
359 color: Green;
360 }
361
362 .unittest-fail, .unittest-error
363 {
364 color: Red;
365 }
366
367 .unittest-row
368 {
369 display: -webkit-box;
370 display: -moz-box;
371 display: -ms-box;
372 display: box;
373 -webkit-box-orient: horizontal;
374 -moz-box-orient: horizontal;
375 -ms-box-orient: horizontal;
376 box-orient: horizontal;
377 width: 100%;
378 }
379
380 .unittest-row-hidden
381 {
382 display: none;
383 }
384
385 .unittest-row-odd
386 {
387 background: WhiteSmoke;
388 }
389
390 .unittest-row-even
391 {
392 background: #E5E5E5;
393 }
394
395 .unittest-row-id
396 {
397 width: 3em;
398 }
399
400 .unittest-row-status
401 {
402 width: 4em;
403 }
404
405 .unittest-row-description
406 {
407 }
408
409 ''';
410 }
411
412 void useHtmlEnhancedConfiguration([bool isLayoutTest = false]) {
413 unittestConfiguration = isLayoutTest ? _singletonLayout : _singletonNotLayout;
414 }
415
416 final _singletonLayout = new HtmlEnhancedConfiguration(true);
417 final _singletonNotLayout = new HtmlEnhancedConfiguration(false);
OLDNEW
« no previous file with comments | « pkg/unittest/lib/html_config.dart ('k') | pkg/unittest/lib/html_individual_config.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698