2017-04-10 1 views
1

Je souhaite pouvoir activer et désactiver une application $ httpBackend dans mon application angularJS.

Cela signifie que je veux injecter le $ httpBackend paresseusement/à la demande. Il serait également agréable de pouvoir l'allumer et l'éteindre à nouveau. Par exemple, pour fournir des données d'entrée pour une application AngularJS prévisualisée à partir d'un système de gestion de contenu (CMS).

Le code ci-dessous ne fonctionne que si je déplace la ngMockE2E à une dépendance ordinaire, et injectent httpBackend $ à mon usine de manière standard.

Le code définit UPP $ httpBackend sur tous les appels à partir d'un fichier de configuration, et répond alors à tous ...

const registerCalls =() => { 
    const injectormock = angular.injector(['ngMockE2E']); //lazy load not working as expected 
    const $httpBackend = injectormock.get('$httpBackend'); //lazy load not working as expected. 
    //Pass through for resources: 
    $httpBackend.whenGET(/.*.html/).passThrough(); 
    $httpBackend.whenGET(/.*.json/).passThrough(); 
    //API calls should be mocked: 
    const apiCalls = {}; 
    for (var call in apiConfig) { 
     if ({}.hasOwnProperty.call(apiConfig, call)) { 
      const callConfig = apiConfig[call]; 
      const url = angular.isDefined(callConfig.regex) ? callConfig.regex : callConfig.url(); 
      if (callConfig.method === 'GET') { 
       apiCalls[call] = $httpBackend.whenGET(url); 
      } else if (callConfig.method === 'POST') { 
       apiCalls[call] = $httpBackend.whenPOST(url); 
      } 
     } 
    } 
    return apiCalls; 

} 

const success = function() { 
    const apiCalls = registerCalls(); 
    for (var call in apiConfig) { 
     let response = {}; 
     if (angular.isDefined(apiConfig[call].response)) { 
      response = apiConfig[call].response(); 
     } 
     apiCalls[call].respond(200, response); 
    } 
}; 

Comment puis-je configurer le httpBackend $ afin qu'il puisse être activé/désactivé alors que l'application AngularJS est en cours d'exécution?

Répondre

1

Les services angulaires sont des singletons qui sont instanciés paresseusement lors de la première injection. Si l'injection de $httpBackend est effectuée sur bootstrap d'application (ce qui est généralement le cas lorsque $http est utilisé), il est impossible de se moquer d'un service. Obtenir la version E2E $httpBackend en passant par angular.injector est une évidence, mais c'est une mauvaise façon de le faire. Cela aura pour résultat d'avoir une nouvelle instance d'injecteur qui utilise ses propres singletons de service principal ($browser, etc.).

La méthode la plus propre pour ce faire est angular.mock.e2e global, comme indiqué dans this example. Il sera disponible once angular-mocks.js is loaded. Le point est de décorer $httpBackend (qui est une fonction) pour envelopper les implémentations originales et E2E et les utiliser conditionnellement.

Il peut être fait comme cela:

angular.module('mockableHttp', []) 
.decorator('$httpBackend', function ($injector, $delegate) { 
    var $httpBackendOriginal = $delegate; 
    var $httpBackendE2E = $injector.invoke(angular.mock.e2e.$httpBackendDecorator, null, { 
    $delegate: $delegate 
    }); 

    function $httpBackend() { 
    var $httpBackendImplementation = $httpBackend.isMocking 
     ? $httpBackendE2E 
     : $httpBackendOriginal; 

    return $httpBackendImplementation.apply(this, arguments); 
    } 

    return Object.assign($httpBackend, $httpBackendE2E, { 
    enableMocking: function() { 
     $httpBackend.isMocking = true; 
    }, 
    disableMocking: function() { 
     $httpBackend.isMocking = false; 
    } 
    }); 
}); 

Lorsque mockableHttp est chargé dans le module d'application (peut être totalement exclue dans la production) et raille HTTP sont activés avec $httpBackend.enableMocking().

+0

Très bonne réponse, le motif a fonctionné parfaitement –

+0

Heureux que ça a marché pour vous. – estus