@@ -9,23 +9,30 @@ import type {
9
9
TestContext ,
10
10
TestResult ,
11
11
} from '@jest/reporters' ;
12
+ import type { TestInvocationMetadata } from 'jest-metadata' ;
12
13
import JestMetadataReporter from 'jest-metadata/reporter' ;
13
14
import type {
14
- AllureTestRunMetadata ,
15
15
AllureTestCaseMetadata ,
16
16
AllureTestFileMetadata ,
17
+ AllureTestRunMetadata ,
18
+ GlobalExtractorContext ,
17
19
Helpers ,
18
20
PropertyExtractorContext ,
19
21
ReporterOptions ,
20
22
TestCaseExtractorContext ,
21
23
TestFileExtractorContext ,
22
24
TestRunExtractorContext ,
23
- GlobalExtractorContext ,
24
25
} from 'jest-allure2-reporter' ;
25
26
26
27
import { type ReporterConfig , resolveOptions } from '../options' ;
27
28
import { AllureMetadataProxy , MetadataSquasher } from '../metadata' ;
28
- import { compactArray , FileNavigatorCache , stringifyValues } from '../utils' ;
29
+ import {
30
+ compactArray ,
31
+ DeferredTaskQueue ,
32
+ FileNavigatorCache ,
33
+ memoize ,
34
+ stringifyValues ,
35
+ } from '../utils' ;
29
36
import { type AllureWriter , FileAllureWriter } from '../serialization' ;
30
37
import { log , optimizeForTracing } from '../logger' ;
31
38
@@ -45,13 +52,29 @@ const __TID_NAME = optimizeForTracing((test: Test, testCaseResult: TestCaseResul
45
52
fullName : testCaseResult . fullName ,
46
53
} ) ) ;
47
54
55
+ interface QueuedTestResult {
56
+ test : Test ;
57
+ testCaseResult : TestCaseResult ;
58
+ testInvocationMetadata : TestInvocationMetadata ;
59
+ }
60
+
48
61
export class JestAllure2Reporter extends JestMetadataReporter {
49
62
private readonly _globalConfig : Config . GlobalConfig ;
50
63
private readonly _options : ReporterOptions ;
51
64
private _globalContext : GlobalExtractorContext = NOT_INITIALIZED ;
52
65
private _writer : AllureWriter = NOT_INITIALIZED ;
53
66
private _config : ReporterConfig < void > = NOT_INITIALIZED ;
54
67
private _globalMetadataProxy : AllureMetadataProxy < AllureTestRunMetadata > = NOT_INITIALIZED ;
68
+ private readonly _taskQueue = new DeferredTaskQueue < QueuedTestResult , TestInvocationMetadata > ( {
69
+ getThreadName : ( item ) => item . test . path ,
70
+ getPayloadKey : ( item ) => item . testInvocationMetadata ,
71
+ execute : ( item ) =>
72
+ log . trace . complete (
73
+ __TID_NAME ( item . test , item . testCaseResult ) ,
74
+ item . testCaseResult . title ,
75
+ ( ) => this . #writeTestResult( item ) ,
76
+ ) ,
77
+ } ) ;
55
78
56
79
constructor ( globalConfig : Config . GlobalConfig , options : ReporterOptions ) {
57
80
super ( globalConfig ) ;
@@ -102,7 +125,7 @@ export class JestAllure2Reporter extends JestMetadataReporter {
102
125
await super . onRunStart ( aggregatedResult , options ) ;
103
126
const attemptRunStart = this . #attempt. bind ( this , 'onRunStart()' , this . #onRunStart) ;
104
127
105
- await log . trace . begin ( __TID ( ) , 'jest-allure2-reporter' ) ;
128
+ log . trace . begin ( __TID ( ) , 'jest-allure2-reporter' ) ;
106
129
await log . trace . complete ( __TID ( ) , 'init' , this . #init. bind ( this ) ) ;
107
130
await log . trace . complete ( __TID ( ) , 'onRunStart' , attemptRunStart ) ;
108
131
}
@@ -171,24 +194,63 @@ export class JestAllure2Reporter extends JestMetadataReporter {
171
194
fallbacks . onTestFileStart ( test , testFileMetadata ) ;
172
195
}
173
196
174
- async onTestCaseResult ( test : Test , testCaseResult : TestCaseResult ) {
197
+ onTestCaseStart ( test : Test , testCaseResult : TestCaseResult ) {
198
+ super . onTestCaseStart ( test , testCaseResult ) ;
199
+ this . _taskQueue . startPending ( test . path ) ;
200
+ }
201
+
202
+ onTestCaseResult ( test : Test , testCaseResult : TestCaseResult ) {
175
203
super . onTestCaseResult ( test , testCaseResult ) ;
176
204
177
- const execute = this . #onTestCaseResult. bind ( this , test , testCaseResult ) ;
178
- const attempt = this . #attempt. bind ( this , 'onTestCaseResult()' , execute ) ;
179
- log . trace . complete ( __TID_NAME ( test , testCaseResult ) , testCaseResult . title , attempt ) ;
205
+ const testEntryMetadata = JestAllure2Reporter . query . testCaseResult ( testCaseResult ) ;
206
+ const testInvocationMetadata = testEntryMetadata . lastInvocation ! ;
207
+ fallbacks . onTestCaseResult (
208
+ test ,
209
+ testCaseResult ,
210
+ new AllureMetadataProxy < AllureTestCaseMetadata > ( testInvocationMetadata ) ,
211
+ ) ;
212
+
213
+ this . _taskQueue . enqueue ( {
214
+ test,
215
+ testCaseResult,
216
+ testInvocationMetadata,
217
+ } ) ;
180
218
}
181
219
182
- #onTestCaseResult( test : Test , testCaseResult : TestCaseResult ) {
183
- const testCaseMetadata = new AllureMetadataProxy < AllureTestCaseMetadata > (
184
- JestAllure2Reporter . query . testCaseResult ( testCaseResult ) . lastInvocation ! ,
185
- ) ;
220
+ async #writeTestResult( { test, testCaseResult, testInvocationMetadata } : QueuedTestResult ) {
221
+ await this . #scanSourceMaps( test . path ) ;
222
+ await postProcessMetadata ( this . _globalContext , testInvocationMetadata ) ;
186
223
187
- fallbacks . onTestCaseResult ( test , testCaseResult , testCaseMetadata ) ;
224
+ const squasher = new MetadataSquasher ( ) ;
225
+ const testCaseContext : PropertyExtractorContext < TestCaseExtractorContext , void > = {
226
+ ...this . _globalContext ,
227
+ filePath : path . relative ( this . _globalConfig . rootDir , test . path ) . split ( path . sep ) ,
228
+ result : { } ,
229
+ testCase : testCaseResult ,
230
+ testCaseMetadata : squasher . testInvocation ( testInvocationMetadata ) ,
231
+ testFileMetadata : squasher . testFile ( testInvocationMetadata . file ) ,
232
+ testRunMetadata : this . _globalMetadataProxy . get ( ) ,
233
+ value : undefined ,
234
+ } ;
235
+
236
+ const allureTest = await resolvePromisedTestCase ( testCaseContext , this . _config . testCase ) ;
237
+ if ( ! allureTest ) {
238
+ return ;
239
+ }
240
+
241
+ const invocationIndex =
242
+ testInvocationMetadata . definition . invocations . indexOf ( testInvocationMetadata ) ;
243
+
244
+ await writeTest ( {
245
+ resultsDir : this . _config . resultsDir ,
246
+ containerName : `${ testCaseResult . fullName } (${ invocationIndex } )` ,
247
+ writer : this . _writer ,
248
+ test : allureTest ,
249
+ } ) ;
188
250
}
189
251
190
252
async onTestFileResult ( test : Test , testResult : TestResult , aggregatedResult : AggregatedResult ) {
191
- await super . onTestFileResult ( test , testResult , aggregatedResult ) ;
253
+ super . onTestFileResult ( test , testResult , aggregatedResult ) ;
192
254
193
255
const execute = this . #onTestFileResult. bind ( this , test , testResult ) ;
194
256
const attempt = this . #attempt. bind ( this , 'onTestFileResult()' , execute ) ;
@@ -199,25 +261,29 @@ export class JestAllure2Reporter extends JestMetadataReporter {
199
261
async #onTestFileResult( test : Test , testResult : TestResult ) {
200
262
const rawMetadata = JestAllure2Reporter . query . test ( test ) ;
201
263
const testFileMetadata = new AllureMetadataProxy < AllureTestFileMetadata > ( rawMetadata ) ;
202
- const globalMetadataProxy = this . _globalMetadataProxy ;
264
+ fallbacks . onTestFileResult ( test , testFileMetadata ) ;
203
265
204
- for ( const loadedFile of globalMetadataProxy . get ( 'loadedFiles' , [ ] ) ) {
205
- await FileNavigatorCache . instance . scanSourcemap ( loadedFile ) ;
266
+ for ( const testCaseResult of testResult . testResults ) {
267
+ const invocations =
268
+ JestAllure2Reporter . query . testCaseResult ( testCaseResult ) . invocations || [ ] ;
269
+
270
+ for ( const testInvocationMetadata of invocations ) {
271
+ this . _taskQueue . enqueue ( {
272
+ test,
273
+ testCaseResult,
274
+ testInvocationMetadata,
275
+ } ) ;
276
+ }
206
277
}
207
278
208
- const allureWriter = this . _writer ;
209
-
210
- fallbacks . onTestFileResult ( test , testFileMetadata ) ;
211
- await postProcessMetadata ( this . _globalContext , rawMetadata ) ;
212
-
213
- // ---
279
+ await this . _taskQueue . awaitCompletion ( ) ;
214
280
215
281
const config = this . _config ;
216
282
const squasher = new MetadataSquasher ( ) ;
283
+ const globalMetadataProxy = this . _globalMetadataProxy ;
217
284
218
285
const testFileContext : PropertyExtractorContext < TestFileExtractorContext , void > = {
219
286
...this . _globalContext ,
220
-
221
287
filePath : path . relative ( this . _globalConfig . rootDir , testResult . testFilePath ) . split ( path . sep ) ,
222
288
result : { } ,
223
289
testFile : testResult ,
@@ -231,39 +297,10 @@ export class JestAllure2Reporter extends JestMetadataReporter {
231
297
await writeTest ( {
232
298
resultsDir : config . resultsDir ,
233
299
containerName : `${ testResult . testFilePath } ` ,
234
- writer : allureWriter ,
300
+ writer : this . _writer ,
235
301
test : allureFileTest ,
236
302
} ) ;
237
303
}
238
-
239
- for ( const testCaseResult of testResult . testResults ) {
240
- const allInvocations =
241
- JestAllure2Reporter . query . testCaseResult ( testCaseResult ) . invocations ?? [ ] ;
242
-
243
- for ( const testInvocationMetadata of allInvocations ) {
244
- const testCaseMetadata = squasher . testInvocation ( testInvocationMetadata ) ;
245
-
246
- const testCaseContext : PropertyExtractorContext < TestCaseExtractorContext , void > = {
247
- ...testFileContext ,
248
- testCase : testCaseResult ,
249
- testCaseMetadata,
250
- } ;
251
-
252
- const allureTest = await resolvePromisedTestCase ( testCaseContext , config . testCase ) ;
253
- if ( ! allureTest ) {
254
- continue ;
255
- }
256
-
257
- const invocationIndex = allInvocations . indexOf ( testInvocationMetadata ) ;
258
-
259
- await writeTest ( {
260
- resultsDir : config . resultsDir ,
261
- containerName : `${ testCaseResult . fullName } (${ invocationIndex } )` ,
262
- writer : allureWriter ,
263
- test : allureTest ,
264
- } ) ;
265
- }
266
- }
267
304
}
268
305
269
306
async onRunComplete (
@@ -305,4 +342,18 @@ export class JestAllure2Reporter extends JestMetadataReporter {
305
342
306
343
await allureWriter . cleanup ?.( ) ;
307
344
}
345
+
346
+ // Executing this once per file should be enough to scan source maps of auxiliary files
347
+ #scanSourceMaps = memoize ( async ( _testPath : string ) => {
348
+ const globalMetadataProxy = this . _globalMetadataProxy ;
349
+ const loadedFiles = globalMetadataProxy
350
+ . get < string [ ] > ( 'loadedFiles' , [ ] )
351
+ . filter ( FileNavigatorCache . instance . hasScannedSourcemap ) ;
352
+
353
+ if ( loadedFiles . length === 0 ) {
354
+ return ;
355
+ }
356
+
357
+ return Promise . all ( loadedFiles . map ( FileNavigatorCache . instance . scanSourcemap ) ) ;
358
+ } ) ;
308
359
}
0 commit comments