11import * as faker from 'faker' ;
2+ import { ErrorHandlingType , SimpleWebRequestBase , WebErrorResponse } from '../src/SimpleWebRequest' ;
23import { GenericRestClient , ApiCallOptions } from '../src/GenericRestClient' ;
34import { DETAILED_RESPONSE , REQUEST_OPTIONS } from './helpers' ;
45import * as SyncTasks from 'synctasks' ;
@@ -8,6 +9,22 @@ const BASE_URL = faker.internet.url();
89const http = new RestClient ( BASE_URL ) ;
910
1011describe ( 'GenericRestClient' , ( ) => {
12+ beforeAll ( ( ) => {
13+ jasmine . Ajax . install ( ) ;
14+ // Run an initial request to finish feature detection - this is needed so we can directly call onLoad
15+ const statusCode = 200 ;
16+ const onSuccess = jasmine . createSpy ( 'onSuccess' ) ;
17+ const path = '/auth' ;
18+
19+ http . performApiGet ( path )
20+ . then ( onSuccess ) ;
21+
22+ const request = jasmine . Ajax . requests . mostRecent ( ) ;
23+ request . respondWith ( { status : statusCode } ) ;
24+ expect ( onSuccess ) . toHaveBeenCalled ( ) ;
25+ jasmine . Ajax . uninstall ( ) ;
26+ } ) ;
27+
1128 beforeEach ( ( ) => jasmine . Ajax . install ( ) ) ;
1229 afterEach ( ( ) => jasmine . Ajax . uninstall ( ) ) ;
1330
@@ -372,7 +389,7 @@ describe('GenericRestClient', () => {
372389 expect ( onSuccess ) . toHaveBeenCalledWith ( body . map ( ( str : string ) => str . trim ( ) ) ) ;
373390 } ) ;
374391
375- it ( 'blocks the request with custom method' , ( ) => {
392+ it ( 'blocks the request with custom method' , ( ) => {
376393 const blockDefer = SyncTasks . Defer < void > ( ) ;
377394
378395 class Http extends GenericRestClient {
@@ -398,4 +415,108 @@ describe('GenericRestClient', () => {
398415 request . respondWith ( { status : statusCode } ) ;
399416 expect ( onSuccess ) . toHaveBeenCalled ( ) ;
400417 } ) ;
418+
419+ it ( 'aborting request after failure w/retry' , ( ) => {
420+ let blockDefer = SyncTasks . Defer < void > ( ) ;
421+
422+ class Http extends GenericRestClient {
423+ constructor ( endpointUrl : string ) {
424+ super ( endpointUrl ) ;
425+ this . _defaultOptions . customErrorHandler = this . _customErrorHandler ;
426+ this . _defaultOptions . timeout = 1 ;
427+ }
428+ protected _blockRequestUntil ( ) {
429+ return blockDefer . promise ( ) ;
430+ }
431+
432+ protected _customErrorHandler = ( webRequest : SimpleWebRequestBase , errorResponse : WebErrorResponse ) => {
433+ if ( errorResponse . canceled ) {
434+ return ErrorHandlingType . DoNotRetry ;
435+ }
436+ return ErrorHandlingType . RetryUncountedImmediately ;
437+ }
438+ }
439+
440+ const statusCode = 400 ;
441+ const onSuccess = jasmine . createSpy ( 'onSuccess' ) ;
442+ const onFailure = jasmine . createSpy ( 'onFailure' ) ;
443+ const http = new Http ( BASE_URL ) ;
444+ const path = '/auth' ;
445+
446+ const req = http . performApiGet ( path )
447+ . then ( onSuccess )
448+ . catch ( onFailure ) ;
449+
450+ blockDefer . resolve ( void 0 ) ;
451+ const request1 = jasmine . Ajax . requests . mostRecent ( ) ;
452+
453+ // Reset blockuntil so retries may block
454+ blockDefer = SyncTasks . Defer < void > ( ) ;
455+
456+ request1 . respondWith ( { status : statusCode } ) ;
457+ expect ( onSuccess ) . not . toHaveBeenCalled ( ) ;
458+ expect ( onFailure ) . not . toHaveBeenCalled ( ) ;
459+
460+ // Calls abort function
461+ req . cancel ( ) ;
462+
463+ expect ( onSuccess ) . not . toHaveBeenCalled ( ) ;
464+ expect ( onFailure ) . toHaveBeenCalled ( ) ;
465+ } ) ;
466+
467+ describe ( 'Timing related tests' , ( ) => {
468+ beforeEach ( ( ) => {
469+ jasmine . clock ( ) . install ( ) ;
470+ } ) ;
471+
472+ afterEach ( ( ) => {
473+ jasmine . clock ( ) . uninstall ( ) ;
474+ } ) ;
475+
476+ it ( 'failed request with retry handles multiple _respond calls' , ( ) => {
477+ let blockDefer = SyncTasks . Defer < void > ( ) ;
478+
479+ class Http extends GenericRestClient {
480+ constructor ( endpointUrl : string ) {
481+ super ( endpointUrl ) ;
482+ this . _defaultOptions . customErrorHandler = this . _customErrorHandler ;
483+ this . _defaultOptions . timeout = 1 ;
484+ }
485+ protected _blockRequestUntil ( ) {
486+ return blockDefer . promise ( ) ;
487+ }
488+
489+ protected _customErrorHandler = ( ) => {
490+ return ErrorHandlingType . RetryUncountedImmediately ;
491+ }
492+ }
493+
494+ const statusCode = 400 ;
495+ const onSuccess = jasmine . createSpy ( 'onSuccess' ) ;
496+ const http = new Http ( BASE_URL ) ;
497+ const path = '/auth' ;
498+
499+ http . performApiGet ( path )
500+ . then ( onSuccess ) ;
501+
502+ blockDefer . resolve ( void 0 ) ;
503+ const request1 = jasmine . Ajax . requests . mostRecent ( ) ;
504+
505+ // Reset blockuntil so retries may block
506+ blockDefer = SyncTasks . Defer < void > ( ) ;
507+
508+ // Store this so we're able to emulate double-request callbacks
509+ const onloadToCall = request1 . onload as any ;
510+ request1 . respondWith ( { status : statusCode } ) ;
511+ onloadToCall ( undefined ) ;
512+ expect ( onSuccess ) . not . toHaveBeenCalled ( ) ;
513+ blockDefer . resolve ( void 0 ) ;
514+
515+ jasmine . clock ( ) . tick ( 100 ) ;
516+
517+ const request2 = jasmine . Ajax . requests . mostRecent ( ) ;
518+ request2 . respondWith ( { status : 200 } ) ;
519+ expect ( onSuccess ) . toHaveBeenCalled ( ) ;
520+ } ) ;
521+ } ) ;
401522} ) ;
0 commit comments