')($rootScope);
$rootScope.$apply();
expect(element).not.toHaveClass('x');
$rootScope.$apply('testObj.a = true');
expect(element).toHaveClass('x');
});
});
describe('large objects', function() {
var getProp;
var veryLargeObj;
beforeEach(function() {
getProp = jasmine.createSpy('getProp');
veryLargeObj = {};
Object.defineProperty(veryLargeObj, 'prop', {
get: getProp,
enumerable: true
});
});
it('should not be copied when using an expression', inject(function($compile, $rootScope) {
element = $compile('
')($rootScope);
$rootScope.fooClass = {foo: veryLargeObj};
$rootScope.$digest();
expect(element).toHaveClass('foo');
expect(getProp).not.toHaveBeenCalled();
}));
it('should not be copied when using a literal', inject(function($compile, $rootScope) {
element = $compile('
')($rootScope);
$rootScope.veryLargeObj = veryLargeObj;
$rootScope.$digest();
expect(element).toHaveClass('foo');
expect(getProp).not.toHaveBeenCalled();
}));
it('should not be copied when inside an array', inject(function($compile, $rootScope) {
element = $compile('
')($rootScope);
$rootScope.veryLargeObj = veryLargeObj;
$rootScope.$digest();
expect(element).toHaveClass('foo');
expect(getProp).not.toHaveBeenCalled();
}));
it('should not be copied when using one-time binding', inject(function($compile, $rootScope) {
element = $compile('
')($rootScope);
$rootScope.veryLargeObj = veryLargeObj;
$rootScope.$digest();
expect(element).toHaveClass('foo');
expect(element).not.toHaveClass('bar');
expect(getProp).not.toHaveBeenCalled();
$rootScope.$apply('veryLargeObj.bar = "bar"');
expect(element).toHaveClass('foo');
expect(element).not.toHaveClass('bar');
expect(getProp).not.toHaveBeenCalled();
$rootScope.$apply('bar = "bar"');
expect(element).toHaveClass('foo');
expect(element).toHaveClass('bar');
expect(getProp).not.toHaveBeenCalled();
$rootScope.$apply('veryLargeObj.bar = "qux"');
expect(element).toHaveClass('foo');
expect(element).toHaveClass('bar');
expect(getProp).not.toHaveBeenCalled();
}));
});
});
describe('ngClass animations', function() {
var body, element, $rootElement;
afterEach(function() {
dealoc(element);
});
it('should avoid calling addClass accidentally when removeClass is going on', function() {
module('ngAnimateMock');
inject(function($compile, $rootScope, $animate, $timeout) {
element = angular.element('
');
var body = jqLite(window.document.body);
body.append(element);
$compile(element)($rootScope);
expect($animate.queue.length).toBe(0);
$rootScope.val = 'one';
$rootScope.$digest();
expect($animate.queue.shift().event).toBe('addClass');
expect($animate.queue.length).toBe(0);
$rootScope.val = '';
$rootScope.$digest();
expect($animate.queue.shift().event).toBe('removeClass'); //only removeClass is called
expect($animate.queue.length).toBe(0);
$rootScope.val = 'one';
$rootScope.$digest();
expect($animate.queue.shift().event).toBe('addClass');
expect($animate.queue.length).toBe(0);
$rootScope.val = 'two';
$rootScope.$digest();
expect($animate.queue.shift().event).toBe('addClass');
expect($animate.queue.shift().event).toBe('removeClass');
expect($animate.queue.length).toBe(0);
});
});
it('should combine the ngClass evaluation with the enter animation', function() {
//mocks are not used since the enter delegation method is called before addClass and
//it makes it impossible to test to see that addClass is called first
module('ngAnimate');
module('ngAnimateMock');
module(function($animateProvider) {
$animateProvider.register('.crazy', function() {
return {
enter: function(element, done) {
element.data('state', 'crazy-enter');
done();
}
};
});
});
inject(function($compile, $rootScope, $browser, $rootElement, $animate, $document) {
$animate.enabled(true);
$rootScope.val = 'crazy';
element = angular.element('
');
jqLite($document[0].body).append($rootElement);
$compile(element)($rootScope);
var enterComplete = false;
$animate.enter(element, $rootElement, null).then(function() {
enterComplete = true;
});
//jquery doesn't compare both elements properly so let's use the nodes
expect(element.parent()[0]).toEqual($rootElement[0]);
expect(element.hasClass('crazy')).toBe(false);
expect(enterComplete).toBe(false);
$rootScope.$digest();
$animate.flush();
$rootScope.$digest();
expect(element.hasClass('crazy')).toBe(true);
expect(enterComplete).toBe(true);
expect(element.data('state')).toBe('crazy-enter');
});
});
it('should not remove classes if they\'re going to be added back right after', function() {
module('ngAnimateMock');
inject(function($rootScope, $compile, $animate) {
var className;
$rootScope.one = true;
$rootScope.two = true;
$rootScope.three = true;
element = angular.element('
');
$compile(element)($rootScope);
$rootScope.$digest();
//this fires twice due to the class observer firing
var item = $animate.queue.shift();
expect(item.event).toBe('addClass');
expect(item.args[1]).toBe('one two three');
expect($animate.queue.length).toBe(0);
$rootScope.three = false;
$rootScope.$digest();
item = $animate.queue.shift();
expect(item.event).toBe('removeClass');
expect(item.args[1]).toBe('three');
expect($animate.queue.length).toBe(0);
$rootScope.two = false;
$rootScope.three = true;
$rootScope.$digest();
item = $animate.queue.shift();
expect(item.event).toBe('addClass');
expect(item.args[1]).toBe('three');
item = $animate.queue.shift();
expect(item.event).toBe('removeClass');
expect(item.args[1]).toBe('two');
expect($animate.queue.length).toBe(0);
});
});
});