11'use strict' ;
22
3- var path = require ( 'path' ) ;
4- var through = require ( 'through2' ) ;
5- var querystring = require ( 'querystring' ) ;
6- var childProcess = require ( 'child_process' ) ;
3+ var path = require ( 'path' ) ;
4+
5+ var gulp = require ( 'gulp' ) ,
6+ gulpIf = require ( 'gulp-if' ) ,
7+ through = require ( 'through2' ) ,
8+ querystring = require ( 'querystring' ) ,
9+ childProcess = require ( 'child_process' ) ;
710
811/**
912 * Wrap the given value in quotation marks
@@ -14,60 +17,115 @@ function quote(value) {
1417 return '"' + value + '"' ;
1518}
1619
20+ var filesAppendRegex = / \/ \* + \s * A N G U L A R I T Y _ F I L E _ L I S T \s * \* + \/ / ;
21+
1722/**
18- * Run karma once only with the given <code>options</code> and the files from the stream appended.
19- * Removes any logging from the output.
20- * No output. Ends when the Karma process ends.
21- * @param {object } options Karma options
22- * @param {number } [bannerWidth] The width of banner comment, zero or omitted for none
23- * @returns {stream.Through } A through strconcateam that performs the operation of a gulp stream
23+ * Create a through2 object stream.
24+ * Expects all the `*.js` files to be included as the files list in the karma conf
25+ * Creates a new karma config file, based on the karma config file name found in
26+ * the local project root, and augments its file list by replacing
27+ * `ANGULARITY_FILE_LIST` in ablock comment with the actual array of files.
28+ * The new karma config file is added to the stream,
29+ * All input `*.js` files are filtered out of the stream
30+ *
31+ * @param {string } configFileName The project local karma config file to augment
32+ * Defaults to "karma.conf.js"
33+ * @return {stream.Through } The output of this stream is expected to contain
34+ * just one file: the augmented karma config file.
2435 */
25- module . exports = function ( options , bannerWidth ) {
26-
27- // setup
28- options . singleRun = true ;
29- options . autoWatch = false ;
30- options . configFile = options . configFile ? path . resolve ( options . configFile ) : undefined ;
31- options . files = options . files || [ ] ;
36+ function karmaConfig ( configFileName ) {
37+ configFileName = 'karma.conf.js' ;
38+ var files = [ ] ;
3239
33- // add unique all stream JS files to the options.files list
34- return through . obj ( function ( file , encoding , done ) {
35- var isValid = ! ( file . isNull ( ) ) && ( path . extname ( file . path ) === '.js' ) ;
36- if ( isValid && ( options . files . indexOf ( file . path ) < 0 ) ) {
37- options . files . push ( file . path ) ;
40+ function transformFn ( file , encoding , done ) {
41+ if ( ! file || ! file . path ) {
42+ throw 'Files must have paths' ;
43+ }
44+ var stream = this ;
45+ //filter out all files (nothing added back to the stream)
46+ //but we save file paths for later use in the flush function
47+ if ( path . extname ( file . path ) !== '.map' ) {
48+ files . push ( file . path ) ;
3849 }
3950 done ( ) ;
51+ }
52+
53+ function flushFn ( done ) {
54+ var stream = this ;
55+ var filesAppend = JSON . stringify ( files , null , ' ' ) ;
4056
41- // run once at the end of the stream
42- } , function ( done ) {
43- if ( options . files . length ) {
44- var appPath = path . join ( __dirname , 'karma-background.js' ) ;
45- var data = querystring . escape ( JSON . stringify ( options ) ) ;
46- var command = [ 'node' , quote ( appPath ) , data ] . join ( ' ' ) ;
47- childProcess . exec ( command , { cwd : process . cwd ( ) } , function ( stderr , stdout ) {
48- var report ;
49- if ( stdout ) {
50- report = stdout
51- . replace ( / ^ \s + / gm, '' ) // remove leading whitespace
52- . replace ( / ^ ( L O G .* \n $ ) / gm, options . silent ? '' : '$1' ) // remove logging
53- . replace ( / a t \s + n u l l \. .* / gm, '' ) // remove file reference
54- . replace ( / \n \n / gm, '\n' ) // consolidate consecutive line breaks
55- . replace ( / ^ \n | \n $ / g, '' ) ; // remove leading and trailing line breaks overall
56- } else if ( stderr ) {
57- var analysis = / $ E r r o r \: \s * ( .* ) $ / mg. exec ( stderr ) ;
58- report = analysis ? analysis [ 1 ] : stderr ;
59- }
60- if ( report ) {
61- var width = Number ( bannerWidth ) || 0 ;
62- var hr = new Array ( width + 1 ) ; // this is a good trick to repeat a character N times
63- var start = ( width > 0 ) ? ( hr . join ( '\u25BC' ) + '\n' ) : '' ;
64- var stop = ( width > 0 ) ? ( hr . join ( '\u25B2' ) + '\n' ) : '' ;
65- process . stdout . write ( start + '\n' + report + '\n\n' + stop ) ;
66- }
57+ //aggregate and append to karma.conf.js in the project root folder
58+ gulp
59+ . src ( path . resolve ( configFileName ) )
60+ . on ( 'data' , function ( karmaConfigFile ) {
61+ var contents = karmaConfigFile . contents . toString ( ) ;
62+ contents = contents . replace ( filesAppendRegex , filesAppend ) ;
63+ karmaConfigFile . contents = new Buffer ( contents ) ;
64+ stream . push ( karmaConfigFile ) ;
65+ } )
66+ . on ( 'end' , function ( ) {
6767 done ( ) ;
6868 } ) ;
69- } else {
69+ }
70+
71+ return through . obj ( transformFn , flushFn ) ;
72+ }
73+
74+ /**
75+ * Run karma once only with the karma config file present in the input stream.
76+ * No output. Ends when the Karma process ends.
77+ * Runs karma in a child process, to avoid `process.exit()` called by karma.
78+ *
79+ * @param {number } [bannerWidth] The width of banner comment, zero or omitted for none
80+ * @returns {stream.Through } A through strconcateam that performs the operation of a gulp stream
81+ */
82+ function karmaRun ( bannerWidth ) {
83+ var options = {
84+ configFile : undefined
85+ } ;
86+
87+ return through . obj ( function transformFn ( file , encoding , done ) {
88+ options . configFile = file . path ;
89+ done ( ) ;
90+ } ,
91+ function streamFn ( done ) {
92+ var appPath = path . join ( __dirname , 'karma-background.js' ) ;
93+ var data = querystring . escape ( JSON . stringify ( options ) ) ;
94+ var command = [ 'node' , quote ( appPath ) , data ] . join ( ' ' ) ;
95+
96+ //TODO @bguiz replace reporter function with a standard karma reporter,
97+ //and extract it to own module
98+ //perhaps extend the spec reporter to do what is being done here, instead of post processing its output here
99+ //check if there is a webstorm/ teamcity reporter
100+ childProcess . exec ( command , { cwd : process . cwd ( ) } , function reporter ( stderr , stdout ) {
101+ var report ;
102+ if ( stdout ) {
103+ console . log ( stdout ) ;
104+ report = stdout
105+ . replace ( / ^ \s + / gm, '' ) // remove leading whitespace
106+ . replace ( / ^ ( L O G .* \n $ ) / gm, options . silent ? '' : '$1' ) // remove logging
107+ . replace ( / a t \s + n u l l \. .* / gm, '' ) // remove file reference
108+ . replace ( / \n \n / gm, '\n' ) // consolidate consecutive line breaks
109+ . replace ( / ^ \n | \n $ / g, '' ) ; // remove leading and trailing line breaks overall
110+ } else if ( stderr ) {
111+ console . log ( stderr ) ;
112+
113+ var analysis = / $ E r r o r \: \s * ( .* ) $ / mg. exec ( stderr ) ;
114+ report = analysis ? analysis [ 1 ] : stderr ;
115+ }
116+ if ( report ) {
117+ var width = Number ( bannerWidth ) || 0 ;
118+ var hr = new Array ( width + 1 ) ; // this is a good trick to repeat a character N times
119+ var start = ( width > 0 ) ? ( hr . join ( '\u25BC' ) + '\n' ) : '' ;
120+ var stop = ( width > 0 ) ? ( hr . join ( '\u25B2' ) + '\n' ) : '' ;
121+ process . stdout . write ( start + '\n' + report + '\n\n' + stop ) ;
122+ }
70123 done ( ) ;
71- }
124+ } ) ;
72125 } ) ;
73126} ;
127+
128+ module . exports = {
129+ createConfig : karmaConfig ,
130+ run : karmaRun
131+ } ;
0 commit comments