@@ -328,4 +328,267 @@ describe("await-remote-run", () => {
328
328
expect ( coreErrorLogMock . mock . calls [ 1 ] ?. [ 0 ] ) . toMatchSnapshot ( ) ;
329
329
} ) ;
330
330
} ) ;
331
+
332
+ describe ( "getWorkflowRunResult" , ( ) => {
333
+ let apiFetchWorkflowRunStateMock : MockInstance <
334
+ typeof api . fetchWorkflowRunState
335
+ > ;
336
+ let apiRetryOnErrorMock : MockInstance < typeof api . retryOnError > ;
337
+
338
+ beforeEach ( ( ) => {
339
+ vi . useFakeTimers ( ) ;
340
+
341
+ apiFetchWorkflowRunStateMock = vi . spyOn ( api , "fetchWorkflowRunState" ) ;
342
+ apiRetryOnErrorMock = vi . spyOn ( api , "retryOnError" ) ;
343
+ } ) ;
344
+
345
+ afterEach ( ( ) => {
346
+ vi . useRealTimers ( ) ;
347
+ } ) ;
348
+
349
+ it ( "succeeds on the completion of a run" , async ( ) => {
350
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
351
+ status : WorkflowRunStatus . Completed ,
352
+ conclusion : WorkflowRunConclusion . Success ,
353
+ } ) ;
354
+ apiRetryOnErrorMock . mockImplementation ( async ( toTry ) => ( {
355
+ success : true ,
356
+ value : await toTry ( ) ,
357
+ } ) ) ;
358
+
359
+ // Behaviour
360
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
361
+ startTime : Date . now ( ) ,
362
+ pollIntervalMs : 100 ,
363
+ runId : 0 ,
364
+ runTimeoutMs : 10_000 ,
365
+ } ) ;
366
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
367
+ const result = await getWorkflowRunResultPromise ;
368
+ expect ( result ) . toStrictEqual ( {
369
+ success : true ,
370
+ value : {
371
+ conclusion : WorkflowRunConclusion . Success ,
372
+ status : WorkflowRunStatus . Completed ,
373
+ } ,
374
+ } ) ;
375
+
376
+ // Logging
377
+ assertNoneCalled ( ) ;
378
+ } ) ;
379
+
380
+ it ( "retries on request failures" , async ( ) => {
381
+ const pollIntervalMs = 100 ;
382
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
383
+ status : WorkflowRunStatus . Completed ,
384
+ conclusion : WorkflowRunConclusion . Success ,
385
+ } ) ;
386
+ apiRetryOnErrorMock
387
+ . mockImplementation ( async ( toTry ) => ( {
388
+ success : true ,
389
+ value : await toTry ( ) ,
390
+ } ) )
391
+ . mockResolvedValueOnce ( { success : false , reason : "timeout" } )
392
+ . mockResolvedValueOnce ( { success : false , reason : "timeout" } ) ;
393
+
394
+ // Behaviour
395
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
396
+ startTime : Date . now ( ) ,
397
+ pollIntervalMs : pollIntervalMs ,
398
+ runId : 0 ,
399
+ runTimeoutMs : 10_000 ,
400
+ } ) ;
401
+
402
+ // First iteration
403
+ await vi . advanceTimersByTimeAsync ( 1 ) ;
404
+ expect ( coreDebugLogMock ) . toHaveBeenCalledOnce ( ) ;
405
+
406
+ // Second iteration
407
+ await vi . advanceTimersByTimeAsync ( 100 ) ;
408
+ expect ( coreDebugLogMock ) . toHaveBeenCalledTimes ( 2 ) ;
409
+
410
+ // Final iteration
411
+ await vi . advanceTimersByTimeAsync ( 100 ) ;
412
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
413
+ const result = await getWorkflowRunResultPromise ;
414
+ expect ( result ) . toStrictEqual ( {
415
+ success : true ,
416
+ value : {
417
+ conclusion : WorkflowRunConclusion . Success ,
418
+ status : WorkflowRunStatus . Completed ,
419
+ } ,
420
+ } ) ;
421
+
422
+ assertOnlyCalled ( coreDebugLogMock ) ;
423
+ expect ( coreDebugLogMock ) . toBeCalledTimes ( 2 ) ;
424
+ expect ( coreDebugLogMock . mock . calls ) . toMatchSnapshot ( ) ;
425
+ } ) ;
426
+
427
+ it ( "returns the conclusion if available" , async ( ) => {
428
+ const expectedConclusion = WorkflowRunConclusion . Skipped ;
429
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
430
+ status : WorkflowRunStatus . Completed ,
431
+ conclusion : expectedConclusion ,
432
+ } ) ;
433
+ apiRetryOnErrorMock . mockImplementation ( async ( toTry ) => ( {
434
+ success : true ,
435
+ value : await toTry ( ) ,
436
+ } ) ) ;
437
+
438
+ // Behaviour
439
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
440
+ startTime : Date . now ( ) ,
441
+ pollIntervalMs : 100 ,
442
+ runId : 0 ,
443
+ runTimeoutMs : 10_000 ,
444
+ } ) ;
445
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
446
+ const result = await getWorkflowRunResultPromise ;
447
+ expect ( result ) . toStrictEqual ( {
448
+ success : true ,
449
+ value : {
450
+ conclusion : expectedConclusion ,
451
+ status : WorkflowRunStatus . Completed ,
452
+ } ,
453
+ } ) ;
454
+
455
+ // Logging
456
+ assertOnlyCalled ( coreErrorLogMock ) ;
457
+ expect ( coreErrorLogMock ) . toHaveBeenCalledOnce ( ) ;
458
+ expect ( coreErrorLogMock . mock . calls ) . toMatchSnapshot ( ) ;
459
+ } ) ;
460
+
461
+ it ( "returns a failure on timeout conclusion" , async ( ) => {
462
+ const expectedConclusion = WorkflowRunConclusion . TimedOut ;
463
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
464
+ status : WorkflowRunStatus . Completed ,
465
+ conclusion : expectedConclusion ,
466
+ } ) ;
467
+ apiRetryOnErrorMock . mockImplementation ( async ( toTry ) => ( {
468
+ success : true ,
469
+ value : await toTry ( ) ,
470
+ } ) ) ;
471
+
472
+ // Behaviour
473
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
474
+ startTime : Date . now ( ) ,
475
+ pollIntervalMs : 100 ,
476
+ runId : 0 ,
477
+ runTimeoutMs : 10_000 ,
478
+ } ) ;
479
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
480
+ const result = await getWorkflowRunResultPromise ;
481
+ expect ( result ) . toStrictEqual ( {
482
+ success : false ,
483
+ reason : "timeout" ,
484
+ } ) ;
485
+
486
+ // Logging
487
+ assertOnlyCalled ( coreErrorLogMock ) ;
488
+ expect ( coreErrorLogMock ) . toHaveBeenCalledOnce ( ) ;
489
+ expect ( coreErrorLogMock . mock . calls ) . toMatchSnapshot ( ) ;
490
+ } ) ;
491
+
492
+ it ( "returns a failure on an unsupported conclusion" , async ( ) => {
493
+ const expectedConclusion = "weird" ;
494
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
495
+ status : WorkflowRunStatus . Completed ,
496
+ conclusion : expectedConclusion as any ,
497
+ } ) ;
498
+ apiRetryOnErrorMock . mockImplementation ( async ( toTry ) => ( {
499
+ success : true ,
500
+ value : await toTry ( ) ,
501
+ } ) ) ;
502
+
503
+ // Behaviour
504
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
505
+ startTime : Date . now ( ) ,
506
+ pollIntervalMs : 100 ,
507
+ runId : 0 ,
508
+ runTimeoutMs : 10_000 ,
509
+ } ) ;
510
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
511
+ const result = await getWorkflowRunResultPromise ;
512
+ expect ( result ) . toStrictEqual ( {
513
+ success : false ,
514
+ reason : "unsupported" ,
515
+ value : expectedConclusion ,
516
+ } ) ;
517
+
518
+ // Logging
519
+ assertOnlyCalled ( coreErrorLogMock , coreInfoLogMock ) ;
520
+ expect ( coreErrorLogMock ) . toHaveBeenCalledOnce ( ) ;
521
+ expect ( coreErrorLogMock . mock . calls ) . toMatchSnapshot ( ) ;
522
+ expect ( coreInfoLogMock ) . toHaveBeenCalledOnce ( ) ;
523
+ expect ( coreInfoLogMock . mock . calls ) . toMatchSnapshot ( ) ;
524
+ } ) ;
525
+
526
+ it ( "returns a failure if the status is unsupported" , async ( ) => {
527
+ const expectedStatus = "weird" ;
528
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
529
+ status : expectedStatus as any ,
530
+ conclusion : WorkflowRunConclusion . Failure ,
531
+ } ) ;
532
+ apiRetryOnErrorMock . mockImplementation ( async ( toTry ) => ( {
533
+ success : true ,
534
+ value : await toTry ( ) ,
535
+ } ) ) ;
536
+
537
+ // Behaviour
538
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
539
+ startTime : Date . now ( ) ,
540
+ pollIntervalMs : 100 ,
541
+ runId : 0 ,
542
+ runTimeoutMs : 10_000 ,
543
+ } ) ;
544
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
545
+ const result = await getWorkflowRunResultPromise ;
546
+ expect ( result ) . toStrictEqual ( {
547
+ success : false ,
548
+ reason : "unsupported" ,
549
+ value : "weird" ,
550
+ } ) ;
551
+
552
+ // Logging
553
+ assertOnlyCalled ( coreErrorLogMock , coreInfoLogMock ) ;
554
+ expect ( coreErrorLogMock ) . toHaveBeenCalledOnce ( ) ;
555
+ expect ( coreErrorLogMock . mock . calls ) . toMatchSnapshot ( ) ;
556
+ expect ( coreInfoLogMock ) . toHaveBeenCalledOnce ( ) ;
557
+ expect ( coreInfoLogMock . mock . calls ) . toMatchSnapshot ( ) ;
558
+ } ) ;
559
+
560
+ it ( "returns a timeout" , async ( ) => {
561
+ const pollIntervalMs = 100 ;
562
+ const runTimeoutMs = 1000 ;
563
+ const expectedIterations = runTimeoutMs / pollIntervalMs ;
564
+ apiFetchWorkflowRunStateMock . mockResolvedValue ( {
565
+ status : WorkflowRunStatus . InProgress ,
566
+ conclusion : null ,
567
+ } ) ;
568
+ apiRetryOnErrorMock . mockImplementation ( async ( toTry ) => ( {
569
+ success : true ,
570
+ value : await toTry ( ) ,
571
+ } ) ) ;
572
+
573
+ // Behaviour
574
+ const getWorkflowRunResultPromise = getWorkflowRunResult ( {
575
+ startTime : Date . now ( ) ,
576
+ pollIntervalMs : pollIntervalMs ,
577
+ runId : 0 ,
578
+ runTimeoutMs : runTimeoutMs ,
579
+ } ) ;
580
+ await vi . advanceTimersByTimeAsync ( 1000 ) ;
581
+ await expect ( getWorkflowRunResultPromise ) . resolves . not . toThrow ( ) ;
582
+ const result = await getWorkflowRunResultPromise ;
583
+ expect ( result ) . toStrictEqual ( {
584
+ success : false ,
585
+ reason : "timeout" ,
586
+ } ) ;
587
+
588
+ // Logging
589
+ assertOnlyCalled ( coreDebugLogMock ) ;
590
+ expect ( coreDebugLogMock ) . toHaveBeenCalledTimes ( expectedIterations ) ;
591
+ expect ( coreDebugLogMock . mock . calls ) . toMatchSnapshot ( ) ;
592
+ } ) ;
593
+ } ) ;
331
594
} ) ;
0 commit comments