AngularJS 단위 테스트에서 $ modal 조롱
나는 a를 시작 $modal
하고 몇 가지 논리를 실행하기 위해 반환 된 promise를 사용 하는 컨트롤러에 대한 단위 테스트를 작성하고 있습니다. $ modal을 실행하는 부모 컨트롤러를 테스트 할 수는 있지만 성공적인 약속을 조롱하는 방법을 알아낼 수는 없습니다.
약속의 해결을 사용 $q
하고 $scope.$apply()
강제하는 등 여러 가지 방법을 시도했습니다 . 그러나 내가 얻은 가장 가까운 것은 이 SO 게시물 의 마지막 답변과 비슷한 것을 모으는 것입니다 .
나는 이것이 "오래된" $dialog
모달 로 몇 번 물었다는 것을 보았다 . "새로운" $dialog
모달 을 사용하는 방법에 대해서는 많이 찾을 수 없습니다 .
일부 포인터는 감사하겠습니다.
문제를 설명하기 위해 UI Bootstrap 문서에 제공된 예제를 약간의 수정을 통해 사용하고 있습니다.
컨트롤러 (메인 및 모달)
'use strict';
angular.module('angularUiModalApp')
.controller('MainCtrl', function($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function() {
$scope.modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
items: function() {
return $scope.items;
}
}
});
$scope.modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
})
.controller('ModalInstanceCtrl', function($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function() {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
});
보기 (main.html)
<div ng-controller="MainCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>I is a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn btn-default" ng-click="open()">Open me!</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
시험
'use strict';
describe('Controller: MainCtrl', function() {
// load the controller's module
beforeEach(module('angularUiModalApp'));
var MainCtrl,
scope;
var fakeModal = {
open: function() {
return {
result: {
then: function(callback) {
callback("item1");
}
}
};
}
};
beforeEach(inject(function($modal) {
spyOn($modal, 'open').andReturn(fakeModal);
}));
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope, _$modal_) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$modal: _$modal_
});
}));
it('should show success when modal login returns success response', function() {
expect(scope.items).toEqual(['item1', 'item2', 'item3']);
// Mock out the modal closing, resolving with a selected item, say 1
scope.open(); // Open the modal
scope.modalInstance.close('item1');
expect(scope.selected).toEqual('item1');
// No dice (scope.selected) is not defined according to Jasmine.
});
});
beforeEach에서 $ modal.open 함수를 염탐하면
spyOn($modal, 'open').andReturn(fakeModal);
or
spyOn($modal, 'open').and.returnValue(fakeModal); //For Jasmine 2.0+
mock에 open
배치 한 함수를 포함하지 않는 $ modal의 모의가 아니라 $ modal.open이 일반적으로 반환하는 모의를 반환해야합니다 fakeModal
. 가짜 모달 result
에는 then
콜백을 저장 하는 함수 가 포함 된 객체가 있어야합니다 (확인 또는 취소 버튼을 클릭 할 때 호출 됨). 또한 close
기능 (모달에서 확인 버튼 클릭 시뮬레이션)과 dismiss
기능 ( 모달 에서 취소 버튼 클릭 시뮬레이션)이 필요합니다. close
및 dismiss
호출하면 기능이 필요한 전화 다시 함수를 호출.
을 fakeModal
다음으로 변경하면 단위 테스트가 통과됩니다.
var fakeModal = {
result: {
then: function(confirmCallback, cancelCallback) {
//Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
this.confirmCallBack = confirmCallback;
this.cancelCallback = cancelCallback;
}
},
close: function( item ) {
//The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
this.result.confirmCallBack( item );
},
dismiss: function( type ) {
//The user clicked cancel on the modal dialog, call the stored cancel callback
this.result.cancelCallback( type );
}
};
또한 취소 처리기에서 테스트 할 속성을 추가하여 취소 대화 상자 케이스를 테스트 할 수 있습니다 $scope.canceled
.
$scope.modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$scope.canceled = true; //Mark the modal as canceled
$log.info('Modal dismissed at: ' + new Date());
});
취소 플래그가 설정되면 단위 테스트는 다음과 같습니다.
it("should cancel the dialog when dismiss is called, and $scope.canceled should be true", function () {
expect( scope.canceled ).toBeUndefined();
scope.open(); // Open the modal
scope.modalInstance.dismiss( "cancel" ); //Call dismiss (simulating clicking the cancel button on the modal)
expect( scope.canceled ).toBe( true );
});
Brant의 답변에 추가하기 위해 다른 시나리오를 처리 할 수 있도록 약간 개선 된 모의가 있습니다.
var fakeModal = {
result: {
then: function (confirmCallback, cancelCallback) {
this.confirmCallBack = confirmCallback;
this.cancelCallback = cancelCallback;
return this;
},
catch: function (cancelCallback) {
this.cancelCallback = cancelCallback;
return this;
},
finally: function (finallyCallback) {
this.finallyCallback = finallyCallback;
return this;
}
},
close: function (item) {
this.result.confirmCallBack(item);
},
dismiss: function (item) {
this.result.cancelCallback(item);
},
finally: function () {
this.result.finallyCallback();
}
};
이것은 모의가 다음과 같은 상황을 처리 할 수 있도록합니다.
두 개의 함수 ( )를에 전달하는 대신 .then()
, .catch()
및 .finally()
핸들러 스타일 과 함께 모달을 사용합니다 . 예를 들면 다음과 같습니다.successCallback, errorCallback
.then()
modalInstance
.result
.then(function () {
// close hander
})
.catch(function () {
// dismiss handler
})
.finally(function () {
// finally handler
});
모달 은 약속을 사용 하기 때문에 그런 일에 $ q 를 사용해야 합니다.
코드는 다음과 같습니다.
function FakeModal(){
this.resultDeferred = $q.defer();
this.result = this.resultDeferred.promise;
}
FakeModal.prototype.open = function(options){ return this; };
FakeModal.prototype.close = function (item) {
this.resultDeferred.resolve(item);
$rootScope.$apply(); // Propagate promise resolution to 'then' functions using $apply().
};
FakeModal.prototype.dismiss = function (item) {
this.resultDeferred.reject(item);
$rootScope.$apply(); // Propagate promise resolution to 'then' functions using $apply().
};
// ....
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
fakeModal = new FakeModal();
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$modal: fakeModal
});
}));
// ....
it("should cancel the dialog when dismiss is called, and $scope.canceled should be true", function () {
expect( scope.canceled ).toBeUndefined();
fakeModal.dismiss( "cancel" ); //Call dismiss (simulating clicking the cancel button on the modal)
expect( scope.canceled ).toBe( true );
});
브랜트의 대답은 분명히 굉장했지만,이 변화는 나를 위해 더 나아졌습니다.
fakeModal =
opened:
then: (openedCallback) ->
openedCallback()
result:
finally: (callback) ->
finallyCallback = callback
then in the test area:
finallyCallback()
expect (thing finally callback does)
.toEqual (what you would expect)
참고URL : https://stackoverflow.com/questions/21214868/mocking-modal-in-angularjs-unit-tests
'IT박스' 카테고리의 다른 글
Scala에서 여러 유형 경계를 어떻게 설정합니까? (0) | 2020.11.15 |
---|---|
테스트 구성을위한 PHPUnit 모범 사례 (0) | 2020.11.15 |
콜백이 반환 될 때까지 "대기"하는 방법은 무엇입니까? (0) | 2020.11.15 |
속성에 대한 잠재적 자식 요소 및 특성을 사용하여 사용자 지정 web.config 섹션을 어떻게 정의합니까? (0) | 2020.11.15 |
LLVM과 Java 바이트 코드의 차이점은 무엇입니까? (0) | 2020.11.15 |