Reputation: 37338
in order to easily create a modal, i want a directive that simply takes a template and then creates a button that opens a modal with the template as the content.
<script type="text/ng-template" id="myTemplate.html">
<h1>hello world</h1>
</script>
<div my-modal="myTemplate.html"></div>
Now, i create a new angularJS directive in my module that simply returns a template that has a ng-click
that then opens the modal:
angular.module('myApp.directives').directive('myModal', ['$modal',
function($modal) {
return {
link: function(scope, elem, attrs) {
scope.modalController = function ($scope, $modalInstance) {
};
scope.openModal = function() {
var modalInstance = $modal.open({
templateUrl: attrs.myModal,
controller: scope.modalController
});
modalInstance.result.then(function () {}, function () {});
return modalInstance;
};
},
restrict: 'A',
scope: {
myModal: '='
},
transclude: false,
template: '<button ng-click="openModal()">open</button>'
};
}]);
This works in my app. You can see the plunkr here.
The Problem is that i can not get the test to work. It tried both the jasmine.clock and the $timeout approach but it still does not seem to work.
Here is my test:
(function () {
"use strict";
describe('my-modal', function() {
var element,
scope,
apply,
triggerClick,
$timeout;
beforeEach(module('myApp.services'));
beforeEach(module('myApp.directives'));
beforeEach(module('pascalprecht.translate'));
beforeEach(module('ui.bootstrap'));
describe('directive', function() {
beforeEach(function(){
jasmine.Clock.useMock();
});
beforeEach(inject(function($injector,$compile) {
var $rootScope = $injector.get('$rootScope');
scope = $rootScope.$new();
$timeout = $injector.get('$timeout');
apply = function () {
/* This is a workaround because. Read up on it here: http://tinyurl.com/ng8zzub */
if(!scope.$$phase) {
scope.$apply();
}
};
triggerClick = function(element){
$(element).trigger('click');
apply();
};
var html =
'<html><body>' +
'<h1>PETER?</h1>' +
'<script type="text/ng-template" id="myModalTemplate.html">' +
'<h1>Hallo Peter</h1>' +
'<p>Was geht?</p>' +
'</script>' +
'<div my-modal="myModalTemplate.html"></div>'
'</body></html>';
element = $compile(html)(scope);
scope.$digest();
}));
it('should open uppon click on directive element', function() {
triggerClick($(element).find('button'));
jasmine.Clock.tick(9000);
$timeout.flush();
apply();
expect($(element).find('.modal').length > 0).toBeTruthy();
});
});
});
}());
Sadly, the test fails.
In the unit-tests that ui-bootstrap itself uses to prove that it's modal component is working, they directly check the $document which is not an option for me.
So one weird thing is, when i use console.log()
to see if element
has changed at all, i see that the html
and body
tag has been stripped. But modal uses the body to append elements to it.
Upvotes: 1
Views: 4307
Reputation: 37338
So the Problem was that ui-bootstrap.modal uses $document to append it's html, rather than using the directive that called it as a refference.
So to test weather or not the modal is called by the directive, we have to search for it in the $document. I injected that in my tests in beforeEach:
var $document;
beforeEach(inject(function(_$document_) {
$document = _$document_;
}));
Then in my actual test i used it to find the modal elements like this:
it('should open uppon click on directive element', function() {
expect($document.find('.modal-open').length > 0).toBeFalsy();
expect($document.find('.modal').length > 0).toBeFalsy();
triggerClick(element.find('button'));
expect($document.find('.modal-open').length > 0).toBeTruthy();
expect($document.find('.modal').length > 0).toBeTruthy();
}
It works!
Upvotes: 2