@@ -219,42 +219,140 @@ module.exports = function(grunt) {
219219 var files = this . filesSrc ;
220220 var TestRunner = YUITest . TestRunner ;
221221 var done = this . async ( ) ;
222+ var errors = [ ] ,
223+ failures = [ ] ,
224+ stack = [ ] ;
222225
223226 //Eval each file so the tests are brought into this scope were CSSLint and YUITest are loaded already
224227 files . forEach ( function ( filepath ) {
225228 eval ( grunt . file . read ( filepath ) ) ;
226229 } ) ;
227230
228- //Generic test event handler for individual test
229- function handleTestResult ( data ) {
230- switch ( data . type ) {
231+ // From YUITest Node CLI
232+ function filterStackTrace ( stackTrace ) {
233+ if ( stackTrace ) {
234+ var lines = stackTrace . split ( "\n" ) ,
235+ result = [ ] ,
236+ i , len ;
237+
238+ //skip first line, it's the error
239+ for ( i = 1 , len = lines . length ; i < len ; i ++ ) {
240+ if ( lines [ i ] . indexOf ( "yuitest-node" ) > - 1 ) {
241+ break ;
242+ } else {
243+ result . push ( lines [ i ] ) ;
244+ }
245+ }
246+
247+ return result . join ( "\n" ) ;
248+ } else {
249+ return "Unavailable." ;
250+ }
251+ }
252+
253+ // From YUITest Node CLI with minor colourization changes
254+ function handleEvent ( event ) {
255+
256+ var message = "" ,
257+ results = event . results ,
258+ i , len ;
259+
260+ switch ( event . type ) {
261+ case TestRunner . BEGIN_EVENT :
262+ message = "YUITest for Node.js\n" ;
263+
264+ if ( TestRunner . _groups ) {
265+ message += "Filtering on groups '" + TestRunner . _groups . slice ( 1 , - 1 ) + "'\n" ;
266+ }
267+ break ;
268+
269+ case TestRunner . COMPLETE_EVENT :
270+ message = "\nTotal tests: " + results . total + ", " +
271+ ( "Failures: " + results . failed ) . red + ", " +
272+ ( "Skipped: " + results . ignored ) . yellow +
273+ ", Time: " + ( results . duration / 1000 ) + " seconds\n" ;
274+
275+ if ( failures . length ) {
276+ message += "\nTests failed:\n" . red ;
277+
278+ for ( i = 0 , len = failures . length ; i < len ; i ++ ) {
279+ message += "\n" + ( i + 1 ) + ") " + failures [ i ] . name + " : " + failures [ i ] . error . getMessage ( ) + "\n" ;
280+ message += "Stack trace:\n" + filterStackTrace ( failures [ i ] . error . stack ) + "\n" ;
281+ }
282+
283+ message += "\n" ;
284+ }
285+
286+ if ( errors . length ) {
287+ message += "\nErrors:\n" . red ;
288+
289+ for ( i = 0 , len = errors . length ; i < len ; i ++ ) {
290+ message += "\n" + ( i + 1 ) + ") " + errors [ i ] . name + " : " + errors [ i ] . error . message + "\n" ;
291+ message += "Stack trace:\n" + filterStackTrace ( errors [ i ] . error . stack ) + "\n" ;
292+ }
293+
294+ message += "\n" ;
295+ }
296+
297+ message += "\n\n" ;
298+ //Tell grunt we're done the async operation
299+ done ( ) ;
300+ break ;
301+
231302 case TestRunner . TEST_FAIL_EVENT :
232- grunt . verbose . fail ( "Test named '" + data . testName + "' failed with message: '" + data . error . message + "'." ) . or . write ( "." . red ) ;
303+ message = "F" . red ;
304+ failures . push ( {
305+ name : stack . concat ( [ event . testName ] ) . join ( " > " ) ,
306+ error : event . error
307+ } ) ;
308+
233309 break ;
234- case TestRunner . TEST_PASS_EVENT :
235- grunt . verbose . ok ( "Test named '" + data . testName + "' passed." ) . or . write ( "." . green ) ;
310+
311+ case TestRunner . ERROR_EVENT :
312+ errors . push ( {
313+ name : stack . concat ( [ event . methodName ] ) . join ( " > " ) ,
314+ error : event . error
315+ } ) ;
316+
236317 break ;
318+
237319 case TestRunner . TEST_IGNORE_EVENT :
238- grunt . verbose . warn ( "Test named '" + data . testName + "' was ignored." ) . or . write ( "." . yellow ) ;
320+ message = "S" . yellow ;
321+ break ;
322+
323+ case TestRunner . TEST_PASS_EVENT :
324+ message = "." . green ;
239325 break ;
326+
327+ case TestRunner . TEST_SUITE_BEGIN_EVENT :
328+ stack . push ( event . testSuite . name ) ;
329+ break ;
330+
331+ case TestRunner . TEST_CASE_COMPLETE_EVENT :
332+ case TestRunner . TEST_SUITE_COMPLETE_EVENT :
333+ stack . pop ( ) ;
334+ break ;
335+
336+ case TestRunner . TEST_CASE_BEGIN_EVENT :
337+ stack . push ( event . testCase . name ) ;
338+ break ;
339+
340+ //no default
240341 }
241- }
242342
243- //Event to execute after all tests suites are finished
244- function reportResults ( allsuites ) {
245- var results = allsuites . results ;
246- grunt . log . write ( "\nTotal tests: " + results . total + ", Failures: " +
247- results . failed + ", Skipped: " + results . ignored +
248- ", Time: " + ( results . duration / 1000 ) + " seconds\n" ) ;
249-
250- //Tell grunt we're done the async testing
251- done ( ) ;
343+ grunt . log . write ( message ) ;
252344 }
253345 //Add event listeners
254- TestRunner . subscribe ( TestRunner . TEST_FAIL_EVENT , handleTestResult ) ;
255- TestRunner . subscribe ( TestRunner . TEST_IGNORE_EVENT , handleTestResult ) ;
256- TestRunner . subscribe ( TestRunner . TEST_PASS_EVENT , handleTestResult ) ;
257- TestRunner . subscribe ( TestRunner . COMPLETE_EVENT , reportResults ) ;
346+ TestRunner . subscribe ( TestRunner . BEGIN_EVENT , handleEvent ) ;
347+ TestRunner . subscribe ( TestRunner . TEST_FAIL_EVENT , handleEvent ) ;
348+ TestRunner . subscribe ( TestRunner . TEST_PASS_EVENT , handleEvent ) ;
349+ TestRunner . subscribe ( TestRunner . ERROR_EVENT , handleEvent ) ;
350+ TestRunner . subscribe ( TestRunner . TEST_IGNORE_EVENT , handleEvent ) ;
351+ TestRunner . subscribe ( TestRunner . TEST_CASE_BEGIN_EVENT , handleEvent ) ;
352+ TestRunner . subscribe ( TestRunner . TEST_CASE_COMPLETE_EVENT , handleEvent ) ;
353+ TestRunner . subscribe ( TestRunner . TEST_SUITE_BEGIN_EVENT , handleEvent ) ;
354+ TestRunner . subscribe ( TestRunner . TEST_SUITE_COMPLETE_EVENT , handleEvent ) ;
355+ TestRunner . subscribe ( TestRunner . COMPLETE_EVENT , handleEvent ) ;
258356 TestRunner . run ( ) ;
259357 } ) ;
260358
0 commit comments