'use strict'; describe('ngIf', function () { var $scope, $compile, element, $compileProvider; beforeEach(module(function(_$compileProvider_) { $compileProvider = _$compileProvider_; })); beforeEach(inject(function ($rootScope, _$compile_) { $scope = $rootScope.$new(); $compile = _$compile_; element = $compile('
')($scope); })); afterEach(function () { dealoc(element); }); function makeIf(expr) { element.append($compile('
Hi
')($scope)); $scope.$apply(); } it('should immediately remove element if condition is false', function () { makeIf('false'); expect(element.children().length).toBe(0); }); it('should leave the element if condition is true', function () { makeIf('true'); expect(element.children().length).toBe(1); }); it('should not add the element twice if the condition goes from true to true', function () { $scope.hello = 'true1'; makeIf('hello'); expect(element.children().length).toBe(1); $scope.$apply('hello = "true2"'); expect(element.children().length).toBe(1); }); it('should not recreate the element if the condition goes from true to true', function () { $scope.hello = 'true1'; makeIf('hello'); element.children().data('flag', true); $scope.$apply('hello = "true2"'); expect(element.children().data('flag')).toBe(true); }); it('should create then remove the element if condition changes', function () { $scope.hello = true; makeIf('hello'); expect(element.children().length).toBe(1); $scope.$apply('hello = false'); expect(element.children().length).toBe(0); }); it('should create a new scope every time the expression evaluates to true', function () { $scope.$apply('value = true'); element.append($compile( '
' )($scope)); $scope.$apply(); expect(element.children('div').length).toBe(1); }); it('should destroy the child scope every time the expression evaluates to false', function() { $scope.value = true; element.append($compile( '
' )($scope)); $scope.$apply(); var childScope = element.children().scope(); var destroyed = false; childScope.$on('$destroy', function() { destroyed = true; }); $scope.value = false; $scope.$apply(); expect(destroyed).toBe(true); }); it('should play nice with other elements beside it', function () { $scope.values = [1, 2, 3, 4]; element.append($compile( '
' + '
' + '
' )($scope)); $scope.$apply(); expect(element.children().length).toBe(9); $scope.$apply('values.splice(0,1)'); expect(element.children().length).toBe(6); $scope.$apply('values.push(1)'); expect(element.children().length).toBe(9); }); it('should play nice with ngInclude on the same element', inject(function($templateCache) { $templateCache.put('test.html', [200, '{{value}}', {}]); $scope.value = 'first'; element.append($compile( '
' )($scope)); $scope.$apply(); expect(element.text()).toBe('first'); $scope.value = 'later'; $scope.$apply(); expect(element.text()).toBe(''); })); it('should work with multiple elements', function() { $scope.show = true; $scope.things = [1, 2, 3]; element.append($compile( '
before;
' + '
start;
' + '
{{thing}};
' + '
end;
' + '
after;
' )($scope)); $scope.$apply(); expect(element.text()).toBe('before;start;1;2;3;end;after;'); $scope.things.push(4); $scope.$apply(); expect(element.text()).toBe('before;start;1;2;3;4;end;after;'); $scope.show = false; $scope.$apply(); expect(element.text()).toBe('before;after;'); }); it('should restore the element to its compiled state', function() { $scope.value = true; makeIf('value'); expect(element.children().length).toBe(1); jqLite(element.children()[0]).removeClass('my-class'); expect(element.children()[0].className).not.toContain('my-class'); $scope.$apply('value = false'); expect(element.children().length).toBe(0); $scope.$apply('value = true'); expect(element.children().length).toBe(1); expect(element.children()[0].className).toContain('my-class'); }); it('should work when combined with an ASYNC template that loads after the first digest', inject(function($httpBackend, $compile, $rootScope) { $compileProvider.directive('test', function() { return { templateUrl: 'test.html' }; }); $httpBackend.whenGET('test.html').respond('hello'); element.append('
'); $compile(element)($rootScope); $rootScope.show = true; $rootScope.$apply(); expect(element.text()).toBe(''); $httpBackend.flush(); expect(element.text()).toBe('hello'); $rootScope.show = false; $rootScope.$apply(); // Note: there are still comments in element! expect(element.children().length).toBe(0); expect(element.text()).toBe(''); })); }); describe('ngIf and transcludes', function() { it('should allow access to directive controller from children when used in a replace template', function() { var controller; module(function($compileProvider) { var directive = $compileProvider.directive; directive('template', valueFn({ template: '
', replace: true, controller: function() { this.flag = true; } })); directive('test', valueFn({ require: '^template', link: function(scope, el, attr, ctrl) { controller = ctrl; } })); }); inject(function($compile, $rootScope) { var element = $compile('
')($rootScope); $rootScope.$apply(); expect(controller.flag).toBe(true); dealoc(element); }); }); }); describe('ngIf animations', function () { var body, element, $rootElement; function html(html) { $rootElement.html(html); element = $rootElement.children().eq(0); return element; } beforeEach(module('ngAnimateMock')); beforeEach(module(function() { // we need to run animation on attached elements; return function(_$rootElement_) { $rootElement = _$rootElement_; body = jqLite(document.body); body.append($rootElement); }; })); afterEach(function(){ dealoc(body); dealoc(element); }); beforeEach(module(function($animateProvider, $provide) { return function($animate) { $animate.enabled(true); }; })); it('should fire off the enter animation', inject(function($compile, $rootScope, $animate) { var item; var $scope = $rootScope.$new(); element = $compile(html( '
' + '
Hi
' + '
' ))($scope); $rootScope.$digest(); $scope.$apply('value = true'); item = $animate.queue.shift(); expect(item.event).toBe('enter'); expect(item.element.text()).toBe('Hi'); expect(element.children().length).toBe(1); })); it('should fire off the leave animation', inject(function ($compile, $rootScope, $animate) { var item; var $scope = $rootScope.$new(); element = $compile(html( '
' + '
Hi
' + '
' ))($scope); $scope.$apply('value = true'); item = $animate.queue.shift(); expect(item.event).toBe('enter'); expect(item.element.text()).toBe('Hi'); expect(element.children().length).toBe(1); $scope.$apply('value = false'); item = $animate.queue.shift(); expect(item.event).toBe('leave'); expect(item.element.text()).toBe('Hi'); expect(element.children().length).toBe(0); })); it('should destroy the previous leave animation if a new one takes place', function() { module(function($provide) { $provide.value('$animate', { enabled : function() { return true; }, leave : function() { //DOM operation left blank }, enter : function(element, parent) { parent.append(element); } }); }); inject(function ($compile, $rootScope, $animate) { var item; var $scope = $rootScope.$new(); element = $compile(html( '
' + '
Yo
' + '
' ))($scope); $scope.$apply('value = true'); var destroyed, inner = element.children(0); inner.on('$destroy', function() { destroyed = true; }); $scope.$apply('value = false'); $scope.$apply('value = true'); $scope.$apply('value = false'); expect(destroyed).toBe(true); }); }); });