Files
angular.js/test/ngMessages/messagesSpec.js
Matias Niemelä 0f4016c84a feat(NgMessages): introduce the NgMessages module and directives
The ngMessages module provides directives designed to better support
handling and reusing error messages within forms without the need to
rely on complex structural directives.

Please note that the API for ngMessages is experimental and may possibly change with
future releases.
2014-05-02 16:31:34 -04:00

472 lines
14 KiB
JavaScript

'use strict';
describe('ngMessages', function() {
beforeEach(module('ngMessages'));
function they(msg, vals, spec, focus) {
forEach(vals, function(val, key) {
var m = msg.replace('$prop', key);
(focus ? iit : it)(m, function() {
spec(val);
});
});
}
function tthey(msg, vals, spec) {
they(msg, vals, spec, true);
}
function s(str) {
return str.replace(/\s+/g,'');
}
var element;
afterEach(function() {
dealoc(element);
});
it('should render based off of a hashmap collection', inject(function($rootScope, $compile) {
element = $compile('<div ng-messages="col">' +
' <div ng-message="val">Message is set</div>' +
'</div>')($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 use the data attribute when an element directive is used',
inject(function($rootScope, $compile) {
element = $compile('<ng-messages for="col">' +
' <ng-message when="val">Message is set</div>' +
'</ng-messages>')($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');
}));
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('<div ng-messages="col">' +
' <div ng-message="val">Message is set</div>' +
'</div>')($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('<div ng-messages="col">' +
' <div ng-message="blue">This message is blue</div>' +
' <div ng-message="red">This message is red</div>' +
'</div>')($rootScope);
$rootScope.$apply(function() {
$rootScope.col = {};
});
expect(element.children().length).toBe(0);
expect(trim(element.text())).toEqual('');
$rootScope.$apply(function() {
$rootScope.col = {
blue : true,
red : false
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual('This message is blue');
$rootScope.$apply(function() {
$rootScope.col = {
red : prop
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual('This message is red');
$rootScope.$apply(function() {
$rootScope.col = null;
});
expect(element.children().length).toBe(0);
expect(trim(element.text())).toEqual('');
$rootScope.$apply(function() {
$rootScope.col = {
blue : 0,
red : null
};
});
expect(element.children().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('<div ng-messages="col">' +
' <div ng-message="one">Message#one</div>' +
' <div ng-message="two">Message#two</div>' +
' <div ng-message="three">Message#three</div>' +
'</div>')($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('<div ng-messages="col">' +
' <div ng-message="ready">This message is ready</div>' +
'</div>')($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 render animations when the active/inactive classes are added/removed', function() {
module('ngAnimate');
module('ngAnimateMock');
inject(function($rootScope, $compile, $animate) {
element = $compile('<div ng-messages="col">' +
' <div ng-message="ready">This message is ready</div>' +
'</div>')($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('when including templates', function() {
they('should load a remote template using $prop',
{'<div ng-messages ng-messages-include="...">':
'<div ng-messages="data" ng-messages-include="abc.html"></div>',
'<ng-messages include="...">' :
'<ng-messages for="data" include="abc.html"></ng-messages>'},
function(html) {
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', '<div ng-message="a">A</div>' +
'<div ng-message="b">B</div>' +
'<div ng-message="c">C</div>');
element = $compile(html)($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'a': 1,
'b': 2,
'c': 3
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("A");
$rootScope.$apply(function() {
$rootScope.data = {
'c': 3
};
});
expect(element.children().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('<div ng-messages="data" ng-messages-include="tpl"></div>')($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,'<div ng-message="required">You did not enter a value</div>');
element = $compile('<div ng-messages="data" ng-messages-include="my-messages">' +
' <div ng-message="failed">Your value is that of failure</div>' +
'</div>')($rootScope);
$rootScope.data = {
required : true,
failed : true
};
$rootScope.$digest();
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("Your value is that of failure");
$httpBackend.flush();
expect(element.children().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',
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', '<div ng-message="a">A</div>' +
'<div ng-message="b">B</div>' +
'<div ng-message="c">C</div>');
element = $compile('<div ng-messages="data" ng-messages-include="abc.html">' +
' <div ng-message="a">AAA</div>' +
' <div ng-message="c">CCC</div>' +
'</div>')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'a': 1,
'b': 2,
'c': 3
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("AAA");
$rootScope.$apply(function() {
$rootScope.data = {
'b': 2,
'c': 3
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("B");
$rootScope.$apply(function() {
$rootScope.data = {
'c': 3
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("CCC");
}));
it('should retain the order of the remote template\'s messages when overriding within the element',
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('abc.html', '<div ng-message="c">C</div>' +
'<div ng-message="a">A</div>' +
'<div ng-message="b">B</div>');
element = $compile('<div ng-messages="data" ng-messages-include="abc.html">' +
' <div ng-message="a">AAA</div>' +
' <div ng-message="c">CCC</div>' +
'</div>')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'a': 1,
'b': 2,
'c': 3
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("CCC");
$rootScope.$apply(function() {
$rootScope.data = {
'a': 1,
'b': 2,
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("AAA");
$rootScope.$apply(function() {
$rootScope.data = {
'b': 3
};
});
expect(element.children().length).toBe(1);
expect(trim(element.text())).toEqual("B");
}));
});
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('<div ng-messages="data" ' + prop + '>' +
' <div ng-message="one">1</div>' +
' <div ng-message="two">2</div>' +
' <div ng-message="three">3</div>' +
'</div>')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'one': true,
'two': false,
'three': true
};
});
expect(element.children().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', '<div ng-message="x">X</div>' +
'<div ng-message="y">Y</div>' +
'<div ng-message="z">Z</div>');
element = $compile('<div ng-messages="data" ' +
'ng-messages-multiple="true" ' +
'ng-messages-include="xyz.html"></div>')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'x': 'a',
'y': null,
'z': true
};
});
expect(element.children().length).toBe(2);
expect(s(element.text())).toEqual("XZ");
$rootScope.$apply(function() {
$rootScope.data.y = {};
});
expect(element.children().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', '<div ng-message="x">X</div>' +
'<div ng-message="y">Y</div>' +
'<div ng-message="z">Z</div>');
element = $compile('<div ng-messages="data" ' +
'ng-messages-multiple="true" ' +
'ng-messages-include="xyz.html">' +
'<div ng-message="y">YYY</div>' +
'<div ng-message="z">ZZZ</div>' +
'</div>')($rootScope);
$rootScope.$apply(function() {
$rootScope.data = {
'x': 'a',
'y': null,
'z': true
};
});
expect(element.children().length).toBe(2);
expect(s(element.text())).toEqual("XZZZ");
$rootScope.$apply(function() {
$rootScope.data.y = {};
});
expect(element.children().length).toBe(3);
expect(s(element.text())).toEqual("XYYYZZZ");
}));
});
});