'use strict';
describe('ngMessages', function() {
beforeEach(inject.strictDi());
beforeEach(module('ngMessages'));
function messageChildren(element) {
return (element.length ? element[0] : element).querySelectorAll('[ng-message], [ng-message-exp]');
}
function s(str) {
return str.replace(/\s+/g,'');
}
function trim(value) {
return isString(value) ? value.trim() : value;
}
var element;
afterEach(function() {
dealoc(element);
});
it('should render based off of a hashmap collection', inject(function($rootScope, $compile) {
element = $compile('
' +
'
Message is set
' +
'
')($rootScope);
$rootScope.$digest();
expect(element.text()).not.toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { val: true };
});
expect(element.text()).toContain('Message is set');
}));
it('should render the same message if multiple message keys match', inject(function($rootScope, $compile) {
element = $compile('' +
'
Message is set
' +
'
')($rootScope);
$rootScope.$digest();
expect(element.text()).not.toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { one: true };
});
expect(element.text()).toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { two: true, one: false };
});
expect(element.text()).toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { three: true, two: false };
});
expect(element.text()).toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { three: false };
});
expect(element.text()).not.toContain('Message is set');
}));
it('should use the when attribute when an element directive is used',
inject(function($rootScope, $compile) {
element = $compile('' +
' Message is set' +
'')($rootScope);
$rootScope.$digest();
expect(element.text()).not.toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { val: true };
});
expect(element.text()).toContain('Message is set');
}));
it('should render the same message if multiple message keys match based on the when attribute', inject(function($rootScope, $compile) {
element = $compile('' +
' Message is set' +
'')($rootScope);
$rootScope.$digest();
expect(element.text()).not.toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { one: true };
});
expect(element.text()).toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { two: true, one: false };
});
expect(element.text()).toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { three: true, two: false };
});
expect(element.text()).toContain('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { three: false };
});
expect(element.text()).not.toContain('Message is set');
}));
it('should allow a dynamic expression to be set when ng-message-exp is used',
inject(function($rootScope, $compile) {
element = $compile('' +
'
Message is crazy
' +
'
')($rootScope);
$rootScope.$digest();
expect(element.text()).not.toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.variable = 'error';
$rootScope.col = { error: true };
});
expect(element.text()).toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.col = { error: false, failure: true };
});
expect(element.text()).not.toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.variable = ['failure'];
});
expect(element.text()).toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.variable = null;
});
expect(element.text()).not.toContain('Message is crazy');
}));
it('should allow a dynamic expression to be set when the when-exp attribute is used',
inject(function($rootScope, $compile) {
element = $compile('' +
' Message is crazy' +
'')($rootScope);
$rootScope.$digest();
expect(element.text()).not.toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.variable = 'error, failure';
$rootScope.col = { error: true };
});
expect(element.text()).toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.col = { error: false, failure: true };
});
expect(element.text()).toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.variable = [];
});
expect(element.text()).not.toContain('Message is crazy');
$rootScope.$apply(function() {
$rootScope.variable = null;
});
expect(element.text()).not.toContain('Message is crazy');
}));
they('should render empty when $prop is used as a collection value',
{ 'null': null,
'false': false,
'0': 0,
'[]': [],
'[{}]': [{}],
'': '',
'{ val2 : true }': { val2: true } },
function(prop) {
inject(function($rootScope, $compile) {
element = $compile('' +
'
Message is set
' +
'
')($rootScope);
$rootScope.$digest();
$rootScope.$apply(function() {
$rootScope.col = prop;
});
expect(element.text()).not.toContain('Message is set');
});
});
they('should insert and remove matching inner elements when $prop is used as a value',
{ 'true': true,
'1': 1,
'{}': {},
'[]': [],
'[null]': [null] },
function(prop) {
inject(function($rootScope, $compile) {
element = $compile('' +
'
This message is blue
' +
'
This message is red
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {};
});
expect(messageChildren(element).length).toBe(0);
expect(trim(element.text())).toEqual('');
$rootScope.$apply(function() {
$rootScope.col = {
blue: true,
red: false
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('This message is blue');
$rootScope.$apply(function() {
$rootScope.col = {
red: prop
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('This message is red');
$rootScope.$apply(function() {
$rootScope.col = null;
});
expect(messageChildren(element).length).toBe(0);
expect(trim(element.text())).toEqual('');
$rootScope.$apply(function() {
$rootScope.col = {
blue: 0,
red: null
};
});
expect(messageChildren(element).length).toBe(0);
expect(trim(element.text())).toEqual('');
});
});
it('should display the elements in the order defined in the DOM',
inject(function($rootScope, $compile) {
element = $compile('' +
'
Message#one
' +
'
Message#two
' +
'
Message#three
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {
three: true,
one: true,
two: true
};
});
angular.forEach(['one','two','three'], function(key) {
expect(s(element.text())).toEqual('Message#' + key);
$rootScope.$apply(function() {
$rootScope.col[key] = false;
});
});
expect(s(element.text())).toEqual('');
}));
it('should add ng-active/ng-inactive CSS classes to the element when errors are/aren\'t displayed',
inject(function($rootScope, $compile) {
element = $compile('' +
'
This message is ready
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {};
});
expect(element.hasClass('ng-active')).toBe(false);
expect(element.hasClass('ng-inactive')).toBe(true);
$rootScope.$apply(function() {
$rootScope.col = { ready: true };
});
expect(element.hasClass('ng-active')).toBe(true);
expect(element.hasClass('ng-inactive')).toBe(false);
}));
it('should automatically re-render the messages when other directives dynamically change them',
inject(function($rootScope, $compile) {
element = $compile('' +
'
Enter something
' +
'
' +
'
{{ item.text }}
' +
'
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {};
$rootScope.items = [
{ text: 'Your age is incorrect', name: 'age' },
{ text: 'You\'re too tall man!', name: 'height' },
{ text: 'Your hair is too long', name: 'hair' }
];
});
expect(messageChildren(element).length).toBe(0);
expect(trim(element.text())).toEqual('');
$rootScope.$apply(function() {
$rootScope.col = { hair: true };
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Your hair is too long');
$rootScope.$apply(function() {
$rootScope.col = { age: true, hair: true};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Your age is incorrect');
$rootScope.$apply(function() {
// remove the age!
$rootScope.items.shift();
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Your hair is too long');
$rootScope.$apply(function() {
// remove the hair!
$rootScope.items.length = 0;
$rootScope.col.primary = true;
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Enter something');
}));
it('should be compatible with ngBind',
inject(function($rootScope, $compile) {
element = $compile('')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {
required: true,
extra: true
};
$rootScope.errorMessages = {
required: 'Fill in the text field.',
extra: 'Extra error message.'
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Fill in the text field.');
$rootScope.$apply(function() {
$rootScope.col.required = false;
$rootScope.col.extra = true;
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Extra error message.');
$rootScope.$apply(function() {
$rootScope.errorMessages.extra = 'New error message.';
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('New error message.');
}));
// issue #12856
it('should only detach the message object that is associated with the message node being removed',
inject(function($rootScope, $compile, $animate) {
// We are going to spy on the `leave` method to give us control over
// when the element is actually removed
spyOn($animate, 'leave');
// Create a basic ng-messages set up
element = $compile('' +
'
Enter something
' +
'
')($rootScope);
// Trigger the message to be displayed
$rootScope.col = { primary: true };
$rootScope.$digest();
expect(messageChildren(element).length).toEqual(1);
var oldMessageNode = messageChildren(element)[0];
// Remove the message
$rootScope.col = { primary: undefined };
$rootScope.$digest();
// Since we have spied on the `leave` method, the message node is still in the DOM
expect($animate.leave).toHaveBeenCalledOnce();
var nodeToRemove = $animate.leave.calls.mostRecent().args[0][0];
expect(nodeToRemove).toBe(oldMessageNode);
$animate.leave.calls.reset();
// Add the message back in
$rootScope.col = { primary: true };
$rootScope.$digest();
// Simulate the animation completing on the node
jqLite(nodeToRemove).remove();
// We should not get another call to `leave`
expect($animate.leave).not.toHaveBeenCalled();
// There should only be the new message node
expect(messageChildren(element).length).toEqual(1);
var newMessageNode = messageChildren(element)[0];
expect(newMessageNode).not.toBe(oldMessageNode);
}));
it('should render animations when the active/inactive classes are added/removed', function() {
module('ngAnimate');
module('ngAnimateMock');
inject(function($rootScope, $compile, $animate) {
element = $compile('' +
'
This message is ready
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {};
});
var event = $animate.queue.pop();
expect(event.event).toBe('setClass');
expect(event.args[1]).toBe('ng-inactive');
expect(event.args[2]).toBe('ng-active');
$rootScope.$apply(function() {
$rootScope.col = { ready: true };
});
event = $animate.queue.pop();
expect(event.event).toBe('setClass');
expect(event.args[1]).toBe('ng-active');
expect(event.args[2]).toBe('ng-inactive');
});
});
describe('ngMessage nested nested inside elements', function() {
it('should not crash or leak memory when the messages are transcluded, the first message is ' +
'visible, and ngMessages is removed by ngIf', function() {
module(function($compileProvider) {
$compileProvider.directive('messageWrap', function() {
return {
transclude: true,
scope: {
col: '=col'
},
template: '
'
};
});
});
inject(function($rootScope, $compile) {
element = $compile('')($rootScope);
$rootScope.$apply(function() {
$rootScope.show = true;
$rootScope.col = {
a: true,
b: true
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('A');
$rootScope.$apply('show = false');
expect(messageChildren(element).length).toBe(0);
});
});
it('should not crash when the first of two nested messages is removed', function() {
inject(function($rootScope, $compile) {
element = $compile(
''
)($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {
a: true,
b: false
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('A');
var ctrl = element.controller('ngMessages');
var deregisterSpy = spyOn(ctrl, 'deregister').and.callThrough();
var nodeA = element[0].querySelector('[ng-message="a"]');
jqLite(nodeA).remove();
$rootScope.$digest(); // The next digest triggers the error
// Make sure removing the element triggers the deregistration in ngMessages
expect(trim(deregisterSpy.calls.mostRecent().args[0].nodeValue)).toBe('ngMessage: a');
expect(messageChildren(element).length).toBe(0);
});
});
it('should not crash, but show deeply nested messages correctly after a message ' +
'has been removed', function() {
inject(function($rootScope, $compile) {
element = $compile(
''
)($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {
a: true,
b: true
};
});
expect(messageChildren(element).length).toBe(2);
expect(trim(element.text())).toEqual('AB');
var ctrl = element.controller('ngMessages');
var deregisterSpy = spyOn(ctrl, 'deregister').and.callThrough();
var nodeB = element[0].querySelector('[ng-message="b"]');
jqLite(nodeB).remove();
$rootScope.$digest(); // The next digest triggers the error
// Make sure removing the element triggers the deregistration in ngMessages
expect(trim(deregisterSpy.calls.mostRecent().args[0].nodeValue)).toBe('ngMessage: b');
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('A');
});
});
});
it('should clean-up the ngMessage scope when a message is removed',
inject(function($compile, $rootScope) {
var html =
'';
element = $compile(html)($rootScope);
$rootScope.$apply(function() {
$rootScope.forA = 'A';
$rootScope.items = {a: true};
});
expect(element.text()).toBe('A');
var watchers = $rootScope.$countWatchers();
$rootScope.$apply('items.a = false');
expect(element.text()).toBe('');
// We don't know exactly how many watchers are on the scope, only that there should be
// one less now
expect($rootScope.$countWatchers()).toBe(watchers - 1);
})
);
it('should unregister the ngMessage even if it was never attached',
inject(function($compile, $rootScope) {
var html =
'';
element = $compile(html)($rootScope);
var ctrl = element.controller('ngMessages');
expect(messageChildren(element).length).toBe(0);
expect(Object.keys(ctrl.messages).length).toEqual(0);
$rootScope.$apply('show = true');
expect(messageChildren(element).length).toBe(0);
expect(Object.keys(ctrl.messages).length).toEqual(1);
$rootScope.$apply('show = false');
expect(messageChildren(element).length).toBe(0);
expect(Object.keys(ctrl.messages).length).toEqual(0);
})
);
describe('default message', function() {
it('should render a default message when no message matches', inject(function($rootScope, $compile) {
element = $compile('' +
'
Message is set
' +
'
Default message is set
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = { unexpected: false };
});
$rootScope.$digest();
expect(element.text().trim()).toBe('');
expect(element).not.toHaveClass('ng-active');
$rootScope.$apply(function() {
$rootScope.col = { unexpected: true };
});
expect(element.text().trim()).toBe('Default message is set');
expect(element).toHaveClass('ng-active');
$rootScope.$apply(function() {
$rootScope.col = { unexpected: false };
});
expect(element.text().trim()).toBe('');
expect(element).not.toHaveClass('ng-active');
$rootScope.$apply(function() {
$rootScope.col = { val: true, unexpected: true };
});
expect(element.text().trim()).toBe('Message is set');
expect(element).toHaveClass('ng-active');
}));
it('should not render a default message with ng-messages-multiple if another error matches',
inject(function($rootScope, $compile) {
element = $compile('' +
'
Message is set
' +
'
Other message is set
' +
'
Default message is set
' +
'
')($rootScope);
expect(element.text().trim()).toBe('');
$rootScope.$apply(function() {
$rootScope.col = { val: true, other: false, unexpected: false };
});
expect(element.text().trim()).toBe('Message is set');
$rootScope.$apply(function() {
$rootScope.col = { val: true, other: true, unexpected: true };
});
expect(element.text().trim()).toBe('Message is set Other message is set');
$rootScope.$apply(function() {
$rootScope.col = { val: false, other: false, unexpected: true };
});
expect(element.text().trim()).toBe('Default message is set');
})
);
it('should handle a default message with ngIf', inject(function($rootScope, $compile) {
element = $compile('' +
'
Message is set
' +
'
Default message is set
' +
'
')($rootScope);
$rootScope.default = true;
$rootScope.col = {unexpected: true};
$rootScope.$digest();
expect(element.text().trim()).toBe('Default message is set');
$rootScope.$apply('default = false');
expect(element.text().trim()).toBe('');
$rootScope.$apply('default = true');
expect(element.text().trim()).toBe('Default message is set');
$rootScope.$apply(function() {
$rootScope.col = { val: true };
});
expect(element.text().trim()).toBe('Message is set');
}));
});
describe('when including templates', function() {
they('should work with a dynamic collection model which is managed by ngRepeat',
{'': '
',
'
': '' +
'' +
''},
function(html) {
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', 'A
' +
'B
' +
'C
');
html = '';
$rootScope.items = [{},{},{}];
element = $compile(html)($rootScope);
$rootScope.$apply(function() {
$rootScope.items[0].a = true;
$rootScope.items[1].b = true;
$rootScope.items[2].c = true;
});
var elements = element[0].querySelectorAll('[ng-repeat]');
// all three collections should have at least one error showing up
expect(messageChildren(element).length).toBe(3);
expect(messageChildren(elements[0]).length).toBe(1);
expect(messageChildren(elements[1]).length).toBe(1);
expect(messageChildren(elements[2]).length).toBe(1);
// this is the standard order of the displayed error messages
expect(element.text().trim()).toBe('ABC');
$rootScope.$apply(function() {
$rootScope.items[0].a = false;
$rootScope.items[0].c = true;
$rootScope.items[1].b = false;
$rootScope.items[2].c = false;
$rootScope.items[2].a = true;
});
// with the 2nd item gone and the values changed
// we should see both 1 and 3 changed
expect(element.text().trim()).toBe('CA');
$rootScope.$apply(function() {
// add the value for the 2nd item back
$rootScope.items[1].b = true;
$rootScope.items.reverse();
});
// when reversed we get back to our original value
expect(element.text().trim()).toBe('ABC');
});
});
they('should remove the $prop element and place a comment anchor node where it used to be',
{'': '
',
'
': '' +
'' +
''},
function(html) {
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', '');
element = $compile(html)($rootScope);
$rootScope.$digest();
var includeElement = element[0].querySelector('[ng-messages-include], ng-messages-include');
expect(includeElement).toBeFalsy();
var comment = element[0].childNodes[0];
expect(comment.nodeType).toBe(8);
expect(comment.nodeValue).toBe(' ngMessagesInclude: abc.html ');
});
});
they('should load a remote template using $prop',
{'': '
',
'
': '' +
'' +
''},
function(html) {
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', 'A
' +
'B
' +
'C
');
element = $compile(html)($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'a': 1,
'b': 2,
'c': 3
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('A');
$rootScope.$apply(function() {
$rootScope.data = {
'c': 3
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('C');
});
});
it('should cache the template after download',
inject(function($rootScope, $compile, $templateCache, $httpBackend) {
$httpBackend.expect('GET', 'tpl').respond(201, 'abc
');
expect($templateCache.get('tpl')).toBeUndefined();
element = $compile('')($rootScope);
$rootScope.$digest();
$httpBackend.flush();
expect($templateCache.get('tpl')).toBeDefined();
}));
it('should re-render the messages after download without an extra digest',
inject(function($rootScope, $compile, $httpBackend) {
$httpBackend.expect('GET', 'my-messages').respond(201,
'You did not enter a value
');
element = $compile('' +
'
' +
'
Your value is that of failure
' +
'
')($rootScope);
$rootScope.data = {
required: true,
failed: true
};
$rootScope.$digest();
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('Your value is that of failure');
$httpBackend.flush();
$rootScope.$digest();
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('You did not enter a value');
}));
it('should allow for overriding the remote template messages within the element depending on where the remote template is placed',
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', 'A
' +
'B
' +
'C
');
element = $compile('' +
'
AAA
' +
'
' +
'
CCC
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'a': 1,
'b': 2,
'c': 3
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('AAA');
$rootScope.$apply(function() {
$rootScope.data = {
'b': 2,
'c': 3
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('B');
$rootScope.$apply(function() {
$rootScope.data = {
'c': 3
};
});
expect(messageChildren(element).length).toBe(1);
expect(trim(element.text())).toEqual('C');
}));
it('should properly detect a previous message, even if it was registered later',
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('include.html', 'A
');
var html =
'';
element = $compile(html)($rootScope);
$rootScope.$apply('items = {b: true, c: true}');
expect(element.text()).toBe('B');
var ctrl = element.controller('ngMessages');
var deregisterSpy = spyOn(ctrl, 'deregister').and.callThrough();
var nodeB = element[0].querySelector('[ng-message="b"]');
jqLite(nodeB).remove();
// Make sure removing the element triggers the deregistration in ngMessages
expect(trim(deregisterSpy.calls.mostRecent().args[0].nodeValue)).toBe('ngMessage: b');
$rootScope.$apply('items.a = true');
expect(element.text()).toBe('A');
})
);
it('should not throw if scope has been destroyed when template request is ready',
inject(function($rootScope, $httpBackend, $compile) {
$httpBackend.expectGET('messages.html').respond('A
');
$rootScope.show = true;
var html =
'';
element = $compile(html)($rootScope);
$rootScope.$digest();
$rootScope.show = false;
$rootScope.$digest();
expect(function() {
$httpBackend.flush();
}).not.toThrow();
}));
it('should not throw if the template is empty',
inject(function($compile, $rootScope, $templateCache) {
var html =
'';
$templateCache.put('messages1.html', '');
$templateCache.put('messages2.html', ' ');
element = $compile(html)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('');
expect(element.children().length).toBe(0);
expect(element.contents().length).toBe(2);
})
);
});
describe('when multiple', function() {
they('should show all truthy messages when the $prop attr is present',
{ 'multiple': 'multiple',
'ng-messages-multiple': 'ng-messages-multiple' },
function(prop) {
inject(function($rootScope, $compile) {
element = $compile('' +
'
1
' +
'
2
' +
'
3
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'one': true,
'two': false,
'three': true
};
});
expect(messageChildren(element).length).toBe(2);
expect(s(element.text())).toContain('13');
});
});
it('should render all truthy messages from a remote template',
inject(function($rootScope, $compile, $templateCache) {
$templateCache.put('xyz.html', 'X
' +
'Y
' +
'Z
');
element = $compile('')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'x': 'a',
'y': null,
'z': true
};
});
expect(messageChildren(element).length).toBe(2);
expect(s(element.text())).toEqual('XZ');
$rootScope.$apply(function() {
$rootScope.data.y = {};
});
expect(messageChildren(element).length).toBe(3);
expect(s(element.text())).toEqual('XYZ');
}));
it('should render and override all truthy messages from a remote template',
inject(function($rootScope, $compile, $templateCache) {
$templateCache.put('xyz.html', 'X
' +
'Y
' +
'Z
');
element = $compile('' +
'
YYY
' +
'
ZZZ
' +
'
' +
'
')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'x': 'a',
'y': null,
'z': true
};
});
expect(messageChildren(element).length).toBe(2);
expect(s(element.text())).toEqual('ZZZX');
$rootScope.$apply(function() {
$rootScope.data.y = {};
});
expect(messageChildren(element).length).toBe(3);
expect(s(element.text())).toEqual('YYYZZZX');
}));
});
});