* Wraps an async Promise with a timeout. We use this to break down and * instrument `TraceLoader` to understand on CQ where timeouts occur. * * @param asyncPromise The Promise representing the async operation to be timed. * @param timeoutMs The timeout in milliseconds. * @param stepName An iden
(
mochaContext: Mocha.Context|Mocha.Suite|null, callback: () => Promise<T>| T, timeoutMs: number,
stepName: string)
| 322 | * @returns A promise that resolves with the operation's result, or rejects if it times out. |
| 323 | */ |
| 324 | async function wrapInTimeout<T>( |
| 325 | mochaContext: Mocha.Context|Mocha.Suite|null, callback: () => Promise<T>| T, timeoutMs: number, |
| 326 | stepName: string): Promise<T> { |
| 327 | const timeout = Promise.withResolvers<void>(); |
| 328 | const timeoutId = setTimeout(() => { |
| 329 | let testTitle = '(unknown test)'; |
| 330 | if (mochaContext) { |
| 331 | try { |
| 332 | if (isMochaContext(mochaContext)) { |
| 333 | testTitle = mochaContext.currentTest?.fullTitle() ?? testTitle; |
| 334 | } else { |
| 335 | // For unknown reasons, we cannot trust the Mocha.Suite types in TS. |
| 336 | // They may be out of sync with the karma-mocha plugin. |
| 337 | // But, `suite.test.title` is present. |
| 338 | testTitle = (mochaContext as unknown as {test: {title: string}}).test.title; |
| 339 | } |
| 340 | } catch (e) { |
| 341 | console.error('Determining Mocha test context for trace timeout failed', e); |
| 342 | } |
| 343 | } |
| 344 | console.error(`TraceLoader: [${stepName}]: took longer than ${timeoutMs}ms in test "${testTitle}"`); |
| 345 | timeout.reject(new Error(`Timeout for TraceLoader: '${stepName}' after ${timeoutMs}ms.`)); |
| 346 | }, timeoutMs); |
| 347 | |
| 348 | // Race the original promise against the timeout promise |
| 349 | try { |
| 350 | const cbResult = await Promise.race([callback(), timeout.promise]); |
| 351 | timeout.resolve(); |
| 352 | return cbResult as T; |
| 353 | } finally { |
| 354 | // Clear the timeout if the original promise resolves/rejects, |
| 355 | // or if the timeout promise wins the race. |
| 356 | clearTimeout(timeoutId); |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | function isMochaContext(arg: unknown): arg is Mocha.Context { |
| 361 | return typeof arg === 'object' && arg !== null && 'currentTest' in arg; |
no test coverage detected