@@ -50,8 +50,56 @@ class ApplicationBuildError extends Error {
50
50
this . name = 'ApplicationBuildError' ;
51
51
}
52
52
}
53
+ function injectKarmaReporter ( context , buildOptions , karmaConfig , subscriber ) {
54
+ const reporterName = 'angular-progress-notifier' ;
55
+ class ProgressNotifierReporter {
56
+ emitter ;
57
+ static $inject = [ 'emitter' ] ;
58
+ constructor ( emitter ) {
59
+ this . emitter = emitter ;
60
+ this . startWatchingBuild ( ) ;
61
+ }
62
+ startWatchingBuild ( ) {
63
+ void ( async ( ) => {
64
+ for await ( const buildOutput of ( 0 , private_1 . buildApplicationInternal ) ( {
65
+ ...buildOptions ,
66
+ watch : true ,
67
+ } , context ) ) {
68
+ if ( buildOutput . kind === private_1 . ResultKind . Failure ) {
69
+ subscriber . next ( { success : false , message : 'Build failed' } ) ;
70
+ }
71
+ else if ( buildOutput . kind === private_1 . ResultKind . Incremental ||
72
+ buildOutput . kind === private_1 . ResultKind . Full ) {
73
+ await writeTestFiles ( buildOutput . files , buildOptions . outputPath ) ;
74
+ this . emitter . refreshFiles ( ) ;
75
+ }
76
+ }
77
+ } ) ( ) ;
78
+ }
79
+ onRunComplete = function ( _browsers , results ) {
80
+ if ( results . exitCode === 0 ) {
81
+ subscriber . next ( { success : true } ) ;
82
+ }
83
+ else {
84
+ subscriber . next ( { success : false } ) ;
85
+ }
86
+ } ;
87
+ }
88
+ karmaConfig . reporters ??= [ ] ;
89
+ karmaConfig . reporters . push ( reporterName ) ;
90
+ karmaConfig . plugins ??= [ ] ;
91
+ karmaConfig . plugins . push ( {
92
+ [ `reporter:${ reporterName } ` ] : [
93
+ 'factory' ,
94
+ Object . assign ( ( ...args ) => new ProgressNotifierReporter ( ...args ) , ProgressNotifierReporter ) ,
95
+ ] ,
96
+ } ) ;
97
+ }
53
98
function execute ( options , context , karmaOptions , transforms = { } ) {
54
- return ( 0 , rxjs_1 . from ) ( initializeApplication ( options , context , karmaOptions , transforms ) ) . pipe ( ( 0 , rxjs_1 . switchMap ) ( ( [ karma , karmaConfig ] ) => new rxjs_1 . Observable ( ( subscriber ) => {
99
+ return ( 0 , rxjs_1 . from ) ( initializeApplication ( options , context , karmaOptions , transforms ) ) . pipe ( ( 0 , rxjs_1 . switchMap ) ( ( [ karma , karmaConfig , buildOptions ] ) => new rxjs_1 . Observable ( ( subscriber ) => {
100
+ if ( options . watch ) {
101
+ injectKarmaReporter ( context , buildOptions , karmaConfig , subscriber ) ;
102
+ }
55
103
// Complete the observable once the Karma server returns.
56
104
const karmaServer = new karma . Server ( karmaConfig , ( exitCode ) => {
57
105
subscriber . next ( { success : exitCode === 0 } ) ;
@@ -98,19 +146,17 @@ async function initializeApplication(options, context, karmaOptions, transforms
98
146
if ( transforms . webpackConfiguration ) {
99
147
context . logger . warn ( `This build is using the application builder but transforms.webpackConfiguration was provided. The transform will be ignored.` ) ;
100
148
}
101
- const testDir = path . join ( context . workspaceRoot , 'dist/test-out' , ( 0 , crypto_1 . randomUUID ) ( ) ) ;
149
+ const outputPath = path . join ( context . workspaceRoot , 'dist/test-out' , ( 0 , crypto_1 . randomUUID ) ( ) ) ;
102
150
const projectSourceRoot = await getProjectSourceRoot ( context ) ;
103
151
const [ karma , entryPoints ] = await Promise . all ( [
104
152
Promise . resolve ( ) . then ( ( ) => __importStar ( require ( 'karma' ) ) ) ,
105
153
collectEntrypoints ( options , context , projectSourceRoot ) ,
106
- fs . rm ( testDir , { recursive : true , force : true } ) ,
154
+ fs . rm ( outputPath , { recursive : true , force : true } ) ,
107
155
] ) ;
108
- const outputPath = testDir ;
109
156
const instrumentForCoverage = options . codeCoverage
110
157
? createInstrumentationFilter ( projectSourceRoot , getInstrumentationExcludedPaths ( context . workspaceRoot , options . codeCoverageExclude ?? [ ] ) )
111
158
: undefined ;
112
- // Build tests with `application` builder, using test files as entry points.
113
- const buildOutput = await first ( ( 0 , private_1 . buildApplicationInternal ) ( {
159
+ const buildOptions = {
114
160
entryPoints,
115
161
tsConfig : options . tsConfig ,
116
162
outputPath,
@@ -127,27 +173,29 @@ async function initializeApplication(options, context, karmaOptions, transforms
127
173
styles : options . styles ,
128
174
polyfills : normalizePolyfills ( options . polyfills ) ,
129
175
webWorkerTsConfig : options . webWorkerTsConfig ,
130
- } , context ) ) ;
176
+ } ;
177
+ // Build tests with `application` builder, using test files as entry points.
178
+ const buildOutput = await first ( ( 0 , private_1 . buildApplicationInternal ) ( buildOptions , context ) ) ;
131
179
if ( buildOutput . kind === private_1 . ResultKind . Failure ) {
132
180
throw new ApplicationBuildError ( 'Build failed' ) ;
133
181
}
134
182
else if ( buildOutput . kind !== private_1 . ResultKind . Full ) {
135
183
throw new ApplicationBuildError ( 'A full build result is required from the application builder.' ) ;
136
184
}
137
185
// Write test files
138
- await writeTestFiles ( buildOutput . files , testDir ) ;
186
+ await writeTestFiles ( buildOutput . files , buildOptions . outputPath ) ;
139
187
karmaOptions . files ??= [ ] ;
140
188
karmaOptions . files . push (
141
189
// Serve polyfills first.
142
- { pattern : `${ testDir } /polyfills.js` , type : 'module' } ,
190
+ { pattern : `${ outputPath } /polyfills.js` , type : 'module' } ,
143
191
// Allow loading of chunk-* files but don't include them all on load.
144
- { pattern : `${ testDir } /{chunk,worker}-*.js` , type : 'module' , included : false } ) ;
192
+ { pattern : `${ outputPath } /{chunk,worker}-*.js` , type : 'module' , included : false } ) ;
145
193
karmaOptions . files . push (
146
194
// Serve remaining JS on page load, these are the test entrypoints.
147
- { pattern : `${ testDir } /*.js` , type : 'module' } ) ;
195
+ { pattern : `${ outputPath } /*.js` , type : 'module' } ) ;
148
196
if ( options . styles ?. length ) {
149
197
// Serve CSS outputs on page load, these are the global styles.
150
- karmaOptions . files . push ( { pattern : `${ testDir } /*.css` , type : 'css' } ) ;
198
+ karmaOptions . files . push ( { pattern : `${ outputPath } /*.css` , type : 'css' } ) ;
151
199
}
152
200
const parsedKarmaConfig = await karma . config . parseConfig ( options . karmaConfig && path . resolve ( context . workspaceRoot , options . karmaConfig ) , transforms . karmaOptions ? transforms . karmaOptions ( karmaOptions ) : karmaOptions , { promiseConfig : true , throwErrors : true } ) ;
153
201
// Remove the webpack plugin/framework:
@@ -171,7 +219,7 @@ async function initializeApplication(options, context, karmaOptions, transforms
171
219
! parsedKarmaConfig . reporters ?. some ( ( r ) => r === 'coverage' || r === 'coverage-istanbul' ) ) {
172
220
parsedKarmaConfig . reporters = ( parsedKarmaConfig . reporters ?? [ ] ) . concat ( [ 'coverage' ] ) ;
173
221
}
174
- return [ karma , parsedKarmaConfig ] ;
222
+ return [ karma , parsedKarmaConfig , buildOptions ] ;
175
223
}
176
224
async function writeTestFiles ( files , testDir ) {
177
225
const directoryExists = new Set ( ) ;
0 commit comments