80

में यूनिट परीक्षा पृथक स्कोप निर्देशक क्या AngularJS में इकाई परीक्षण पृथक गुंजाइश के लिए एक अच्छा तरीका है करने के लिएकैसे AngularJS

JSFiddle showing unit test

निर्देशक झलकी

scope: {name: '=myGreet'}, 
    link: function (scope, element, attrs) { 
     //show the initial state 
     greet(element, scope[attrs.myGreet]); 

     //listen for changes in the model 
     scope.$watch(attrs.myGreet, function (name) { 
      greet(element, name); 
     }); 
    } 

मैं निर्देश सुनिश्चित करना चाहते हैं सुन रहा है परिवर्तनों के लिए - यह नहीं एक अलग दायरे के साथ काम करता है:

it('should watch for changes in the model', function() { 
     var elm; 
     //arrange 
     spyOn(scope, '$watch'); 
     //act 
     elm = compile(validHTML)(scope); 
     //assert 
     expect(scope.$watch.callCount).toBe(1); 
     expect(scope.$watch).toHaveBeenCalledWith('name', jasmine.any(Function)); 
    }); 

अद्यतन: मैं इसे अगर उम्मीद नजर रखने वालों बच्चे दायरे में शामिल किया गया की जाँच करके काम मिल गया है, लेकिन यह बहुत भंगुर और शायद एक गैर-दस्तावेजी तरह से accessors का उपयोग कर (उर्फ सूचना के बिना परिवर्तन के अधीन!)।

//this is super brittle, is there a better way!? 
elm = compile(validHTML)(scope); 
expect(elm.scope().$$watchers[0].exp).toBe('name'); 

अद्यतन 2: मैंने कहा यह भंगुर है! विचार अभी भी काम करता है लेकिन AngularJS के नए संस्करण में एक्सेसर scope() से isolateScope() में बदल गया है:

//this is STILL super brittle, is there a better way!? 
elm = compile(validHTML)(scope);      
expect(elm.isolateScope().$$watchers[0].exp).toBe('name'); 
+0

आप सेटअप करने के लिए एक तरह से जासूसी मिला? – Tushar

+0

@ तुषार वास्तव में नहीं, जैसा कि पहले काम करने के लिए एक तरीका है लेकिन यह बिना किसी सूचना के बदल सकता है, इसलिए अपने जोखिम पर उपयोग करें। – daniellmb

उत्तर

99

angular element api docs देखें। यदि आप element.scope() का उपयोग करते हैं तो आपको तत्व का दायरा मिलता है जिसे आपने अपने निर्देश की दायरे की संपत्ति में परिभाषित किया है। यदि आप element.isolateScope() का उपयोग करते हैं तो आपको संपूर्ण पृथक दायरा मिलता है। उदाहरण के लिए, अपने निर्देश कुछ इस तरह दिखता है, तो: अपने परीक्षण में

scope : { 
myScopeThingy : '=' 
}, 
controller : function($scope){ 
$scope.myIsolatedThingy = 'some value'; 
} 

फिर बुला element.scope()

{ myScopeThingy : 'whatever value this is bound to' } 

लेकिन अगर आप element.isolateScope() फोन आप हूँ वापस आ जाएगी

{ 
    myScopeThingy : 'whatever value this is bound to', 
    myIsolatedThingy : 'some value' 
} 

यह कोणीय 1.2.2 या 1.2.3 के रूप में सच है, बिल्कुल सुनिश्चित नहीं है। पिछले संस्करणों में आपके पास केवल element.scope() था।

+1

v1.2.3 feat (jqLite): अलगाव का पर्दाफाश करें() गेट स्कोप के समान () https://github.com/angular/angular.js/commit/27e9340b3c25b512e45213b39811098d07e12e3b – daniellmb

+1

लेकिन आप $ घड़ी विधि पर कहां जासूसी करते हैं? – Tushar

+1

आप $ घड़ी पर चलने वाले फ़ंक्शन का पर्दाफाश कर सकते हैं और फिर उस पर जासूसी कर सकते हैं। निर्देश में, "scope.myfunc = function() ..." सेट करें, फिर $ घड़ी में "$ scope। $ Watch ('myName', scope.myfunc);"। अब परीक्षण में आप अलग-अलग गुंजाइश से मेरी फनक प्राप्त कर सकते हैं और उस पर जासूसी कर सकते हैं। –

0

मुझे यकीन है कि यह अलग गुंजाइश के साथ संभव है नहीं कर रहा हूँ (हालांकि मुझे आशा है कि किसी ने मुझे गलत साबित होता है)। निर्देश में बनाए गए अलग-अलग दायरे को अच्छी तरह से अलग किया जाता है, इसलिए निर्देश में $ घड़ी विधि उस इकाई से अलग होती है जिसे आप इकाई परीक्षण में जासूसी कर रहे हैं। यदि आप गुंजाइश बदलते हैं: {} दायरे के लिए: सत्य, निर्देश का दायरा प्रोटोटाइपिक रूप से प्राप्त होगा और आपके परीक्षण पास होना चाहिए।

मुझे लगता है कि यह सबसे आदर्श समाधान नहीं है, क्योंकि कभी-कभी (बहुत समय), अलग-अलग गुंजाइश अच्छी बात है।

11

आप अलग-अलग क्षेत्र प्राप्त करने के लिए var isolateScope = myDirectiveElement.scope() कर सकते हैं।

आपको वास्तव में परीक्षण करने की आवश्यकता नहीं है कि $ घड़ी को बुलाया गया था .. यह आपके ऐप का परीक्षण करने से अधिक परीक्षण कोणीय है। लेकिन मुझे लगता है कि यह सवाल के लिए सिर्फ एक उदाहरण है।

+2

मुझे यकीन नहीं है कि मैं इसे "परीक्षण कोणीय" से सहमत हूं, मैं परीक्षण नहीं कर रहा हूं कि $ घड़ी काम करता है लेकिन बस यह निर्देश संपत्ति के लिए "वायर्ड-अप" संपत्ति है। – daniellmb

+1

इसके अलावा, डैनियलम, इसका परीक्षण करने का तरीका आपके 'बधाई' समारोह और उस पर जासूसी का खुलासा करना होगा, और जांचें कि क्या इसे कहा जाता है - $ घड़ी नहीं। –

+0

ठीक है, यह एक संक्षिप्त उदाहरण है, लेकिन मुझे दिलचस्पी है कि अलग-अलग क्षेत्र का परीक्षण करने का एक साफ तरीका है। गुंजाइश को तोड़ना और दायरे पर विधियां डालना इस मामले में काम नहीं करेगा क्योंकि इसे बुलाए जाने से पहले जासूस जोड़ने के लिए कोई हुक नहीं है। – daniellmb

1

कदम एक अलग नियंत्रक से तर्क, अर्थात्: आप के रूप में

//will get your isolate scope 
function MyCtrl($scope) 
{ 
    //non-DOM manipulating ctrl logic here 
} 
app.controller(MyCtrl); 

function MyDirective() 
{ 
    return { 
    scope  : {}, 
    controller: MyCtrl, 
    link  : function (scope, element, attrs) 
    { 
     //moved non-DOM manipulating logic to ctrl 
    } 
    } 
} 
app.directive('myDirective', MyDirective); 

और परीक्षण बाद किसी भी नियंत्रक होगा - में गुंजाइश वस्तु गुजर सीधे (नियंत्रकोंsection here एक उदाहरण के लिए देखें)।

अगर आप अपने परीक्षण में $ घड़ी को गति प्रदान करने की आवश्यकता है:

describe('MyCtrl test', function() 
{ 
    var $rootScope, $controller, $scope; 

    beforeEach(function() 
    { 
    inject(function (_$rootScope_, _$controller_) 
    { 
     // The injector unwraps the underscores (_) from around the parameter names when matching 
     $rootScope = _$rootScope_; 
     $controller = _$controller_; 
    }); 

    $scope = $rootScope.$new({}); 
    $scope.foo = {x: 1}; //initial scope state as desired 
    $controller(MyCtrl, {$scope: $scope}); //or by name as 'MyCtrl' 
    }); 

    it('test scope property altered on $digest', function() 
    { 
    $scope.$digest(); //trigger $watch 
    expect($scope.foo.x).toEqual(1); //or whatever 
    }); 
});