From 91b6c5f7ffaa19f967547ae3916641fed9e0f04c Mon Sep 17 00:00:00 2001
From: Misko Hevery
Date: Sun, 7 Nov 2010 13:04:48 -0800
Subject: Added documentation for validators.
BACKWARD INCOMPATIBLE: removed ssn validators, since it is unlikely that most people will need it and if they do, they can added it thorough RegExp
---
docs/validator.template | 5 ++
src/filters.js | 4 +-
src/scenario/dsl.js | 29 +------
src/validators.js | 217 +++++++++++++++++++++++++++++++++++++++++++++--
src/widgets.js | 129 ++++++++++++++++++++++++++++
test/ValidatorsTest.js | 6 --
test/scenario/dslSpec.js | 2 +-
7 files changed, 350 insertions(+), 42 deletions(-)
diff --git a/docs/validator.template b/docs/validator.template
index 517a2fa0..2d5d4bc9 100644
--- a/docs/validator.template
+++ b/docs/validator.template
@@ -9,6 +9,11 @@
<input type="text" ng:validate="{{shortName}}{{#paramRest}}{{^default}}:{{name}}{{/default}}{{#default}}[:{{name}}]{{/default}}{{/paramRest}}"/>
+
In JavaScript
+
+angular.validator.{{shortName}}({{paramFirst.name}}{{#paramRest}}{{^default}}, {{name}}{{/default}}{{#default}}[, {{name}}]{{/default}}{{/paramRest}} );
+
+
Parameters
{{#param}}
diff --git a/src/filters.js b/src/filters.js
index 206da240..14d0dff8 100644
--- a/src/filters.js
+++ b/src/filters.js
@@ -343,7 +343,7 @@ snippet</p>
});
it('should update', function(){
- textarea('snippet').enter('new text');
+ input('snippet').enter('new text');
expect(using('#html-filter').binding('snippet | html')).toBe('new text');
expect(using('#escaped-html').binding('snippet')).toBe("new <b>text</b>");
expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")).toBe('new text');
@@ -415,7 +415,7 @@ and one more: ftp://127.0.0.1/.
});
it('should update', function(){
- textarea('snippet').enter('new http://link.');
+ input('snippet').enter('new http://link.');
expect(using('#linky-filter').binding('snippet | linky')).
toBe('new http://link.');
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
diff --git a/src/scenario/dsl.js b/src/scenario/dsl.js
index f37ab71d..99bc63a9 100644
--- a/src/scenario/dsl.js
+++ b/src/scenario/dsl.js
@@ -191,7 +191,7 @@ angular.scenario.dsl('input', function() {
chain.enter = function(value) {
return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) {
- var input = $document.elements('input[name="$1"]', this.name);
+ var input = $document.elements(':input[name="$1"]', this.name);
input.val(value);
input.trigger('change');
done();
@@ -200,7 +200,7 @@ angular.scenario.dsl('input', function() {
chain.check = function() {
return this.addFutureAction("checkbox '" + this.name + "' toggle", function($window, $document, done) {
- var input = $document.elements('input:checkbox[name="$1"]', this.name);
+ var input = $document.elements(':checkbox[name="$1"]', this.name);
input.trigger('click');
done();
});
@@ -209,7 +209,7 @@ angular.scenario.dsl('input', function() {
chain.select = function(value) {
return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function($window, $document, done) {
var input = $document.
- elements('input:radio[name$="@$1"][value="$2"]', this.name, value);
+ elements(':radio[name$="@$1"][value="$2"]', this.name, value);
input.trigger('click');
done();
});
@@ -222,29 +222,6 @@ angular.scenario.dsl('input', function() {
});
-/**
- * Usage:
- * textarea(name).enter(value) enters value in the text area with specified name
- */
-angular.scenario.dsl('textarea', function() {
- var chain = {};
-
- chain.enter = function(value) {
- return this.addFutureAction("textarea '" + this.name + "' enter '" + value + "'", function($window, $document, done) {
- var textarea = $document.elements('textarea[name="$1"]', this.name);
- textarea.val(value);
- textarea.trigger('change');
- done();
- });
- };
-
- return function(name) {
- this.name = name;
- return chain;
- };
-});
-
-
/**
* Usage:
* repeater('#products table', 'Product List').count() number of rows
diff --git a/src/validators.js b/src/validators.js
index 2d8b5354..9715be59 100644
--- a/src/validators.js
+++ b/src/validators.js
@@ -1,6 +1,31 @@
extend(angularValidator, {
'noop': function() { return _null; },
+ /**
+ * @ngdoc validator
+ * @name angular.validator.regexp
+ * @description
+ * Use regexp validator to restrict the input to any Regular Expression.
+ *
+ * @param {string} value value to validate
+ * @param {regexp} expression regular expression.
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter valid SSN:
+ *
+ *
+ * @scenario
+ * it('should invalidate non ssn', function(){
+ * var textBox = element('.example :input');
+ * expect(textBox.attr('className')).not().toMatch(/ng-validation-error/);
+ * expect(textBox.val()).toEqual('123-45-6789');
+ *
+ * input('ssn').enter('123-45-67890');
+ * expect(textBox.attr('className')).toMatch(/ng-validation-error/);
+ * });
+ *
+ */
'regexp': function(value, regexp, msg) {
if (!value.match(regexp)) {
return msg ||
@@ -10,6 +35,43 @@ extend(angularValidator, {
}
},
+ /**
+ * @ngdoc validator
+ * @name angular.validator.number
+ * @description
+ * Use number validator to restrict the input to numbers with an
+ * optional range. (See integer for whole numbers validator).
+ *
+ * @param {string} value value to validate
+ * @param {int=} [min=MIN_INT] minimum value.
+ * @param {int=} [max=MAX_INT] maximum value.
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter number:
+ * Enter number greater than 10:
+ * Enter number between 100 and 200:
+ *
+ * @scenario
+ * it('should invalidate number', function(){
+ * var n1 = element('.example :input[name=n1]');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('n1').enter('1.x');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ *
+ * var n2 = element('.example :input[name=n2]');
+ * expect(n2.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('n2').enter('9');
+ * expect(n2.attr('className')).toMatch(/ng-validation-error/);
+ *
+ * var n3 = element('.example :input[name=n3]');
+ * expect(n3.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('n3').enter('201');
+ * expect(n3.attr('className')).toMatch(/ng-validation-error/);
+ *
+ * });
+ *
+ */
'number': function(value, min, max) {
var num = 1 * value;
if (num == value) {
@@ -25,6 +87,42 @@ extend(angularValidator, {
}
},
+ /**
+ * @ngdoc validator
+ * @name angular.validator.integer
+ * @description
+ * Use number validator to restrict the input to integers with an
+ * optional range. (See integer for whole numbers validator).
+ *
+ * @param {string} value value to validate
+ * @param {int=} [min=MIN_INT] minimum value.
+ * @param {int=} [max=MAX_INT] maximum value.
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter integer:
+ * Enter integer equal or greater than 10:
+ * Enter integer between 100 and 200 (inclusive):
+ *
+ * @scenario
+ * it('should invalidate integer', function(){
+ * var n1 = element('.example :input[name=n1]');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('n1').enter('1.1');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ *
+ * var n2 = element('.example :input[name=n2]');
+ * expect(n2.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('n2').enter('10.1');
+ * expect(n2.attr('className')).toMatch(/ng-validation-error/);
+ *
+ * var n3 = element('.example :input[name=n3]');
+ * expect(n3.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('n3').enter('100.1');
+ * expect(n3.attr('className')).toMatch(/ng-validation-error/);
+ *
+ * });
+ */
'integer': function(value, min, max) {
var numberError = angularValidator['number'](value, min, max);
if (numberError) return numberError;
@@ -34,6 +132,29 @@ extend(angularValidator, {
return _null;
},
+ /**
+ * @ngdoc validator
+ * @name angular.validator.date
+ * @description
+ * Use date validator to restrict the user input to a valid date
+ * in format in format MM/DD/YYYY.
+ *
+ * @param {string} value value to validate
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter valid date:
+ *
+ *
+ * @scenario
+ * it('should invalidate date', function(){
+ * var n1 = element('.example :input');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('text').enter('123/123/123');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ * });
+ *
+ */
'date': function(value) {
var fields = /^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/.exec(value);
var date = fields ? new Date(fields[3], fields[1]-1, fields[2]) : 0;
@@ -44,13 +165,28 @@ extend(angularValidator, {
_null : "Value is not a date. (Expecting format: 12/31/2009).";
},
- 'ssn': function(value) {
- if (value.match(/^\d\d\d-\d\d-\d\d\d\d$/)) {
- return _null;
- }
- return "SSN needs to be in 999-99-9999 format.";
- },
-
+ /**
+ * @ngdoc validator
+ * @name angular.validator.email
+ * @description
+ * Use email validator if you wist to restrict the user input to a valid email.
+ *
+ * @param {string} value value to validate
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter valid email:
+ *
+ *
+ * @scenario
+ * it('should invalidate email', function(){
+ * var n1 = element('.example :input');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('text').enter('a@b.c');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ * });
+ *
+ */
'email': function(value) {
if (value.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)) {
return _null;
@@ -58,6 +194,28 @@ extend(angularValidator, {
return "Email needs to be in username@host.com format.";
},
+ /**
+ * @ngdoc validator
+ * @name angular.validator.phone
+ * @description
+ * Use phone validator to restrict the input phone numbers.
+ *
+ * @param {string} value value to validate
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter valid phone number:
+ *
+ *
+ * @scenario
+ * it('should invalidate phone', function(){
+ * var n1 = element('.example :input');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('text').enter('+12345678');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ * });
+ *
+ */
'phone': function(value) {
if (value.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)) {
return _null;
@@ -68,6 +226,28 @@ extend(angularValidator, {
return "Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly.";
},
+ /**
+ * @ngdoc validator
+ * @name angular.validator.url
+ * @description
+ * Use phone validator to restrict the input URLs.
+ *
+ * @param {string} value value to validate
+ * @css ng-validation-error
+ *
+ * @example
+ * Enter valid phone number:
+ *
+ *
+ * @scenario
+ * it('should invalidate url', function(){
+ * var n1 = element('.example :input');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('text').enter('abc://server/path');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ * });
+ *
+ */
'url': function(value) {
if (value.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/)) {
return _null;
@@ -75,6 +255,29 @@ extend(angularValidator, {
return "URL needs to be in http://server[:port]/path format.";
},
+ /**
+ * @ngdoc validator
+ * @name angular.validator.json
+ * @description
+ * Use json validator if you wish to restrict the user input to a valid JSON.
+ *
+ * @param {string} value value to validate
+ * @css ng-validation-error
+ *
+ * @example
+ *
+ *
+ * @scenario
+ * it('should invalidate json', function(){
+ * var n1 = element('.example :input');
+ * expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
+ * input('json').enter('{name}');
+ * expect(n1.attr('className')).toMatch(/ng-validation-error/);
+ * });
+ *
+ */
'json': function(value) {
try {
fromJson(value);
diff --git a/src/widgets.js b/src/widgets.js
index 4845e694..43a16c8c 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -1,5 +1,134 @@
/**
+ * @ngdoc widget
+ * @name angular.widget.HTML
*
+ * @description
+ * The most common widgets you will use will be in the from of the
+ * standard HTML set. These widgets are bound using the name attribute
+ * to an expression. In addition they can have `ng:validate`, `ng:required`,
+ * `ng:format`, `ng:change` attribute to further control their behavior.
+ *
+ * @usageContent
+ * see example below for usage
+ *
+ *
+ *
+ *
+ *
+ * @example
+
+
+ * @scenario
+ * it('should exercise text', function(){
+ * input('input1').enter('Carlos');
+ * expect(binding('input1')).toEqual('"Carlos"');
+ * });
+ * it('should exercise textarea', function(){
+ * input('input2').enter('Carlos');
+ * expect(binding('input2')).toEqual('"Carlos"');
+ * });
+ * it('should exercise radio', function(){
+ * expect(binding('input3')).toEqual('null');
+ * input('input3').select('A');
+ * expect(binding('input3')).toEqual('"A"');
+ * input('input3').select('B');
+ * expect(binding('input3')).toEqual('"B"');
+ * });
+ * it('should exercise checkbox', function(){
+ * expect(binding('input4')).toEqual('false');
+ * input('input4').check();
+ * expect(binding('input4')).toEqual('true');
+ * });
+ * it('should exercise pulldown', function(){
+ * expect(binding('input5')).toEqual('"c"');
+ * select('input5').option('d');
+ * expect(binding('input5')).toEqual('"d"');
+ * });
+ * it('should exercise multiselect', function(){
+ * expect(binding('input6')).toEqual('[]');
+ * select('input6').options('e');
+ * expect(binding('input6')).toEqual('["e"]');
+ * select('input6').options('e', 'f');
+ * expect(binding('input6')).toEqual('["e","f"]');
+ * });
*/
function modelAccessor(scope, element) {
diff --git a/test/ValidatorsTest.js b/test/ValidatorsTest.js
index 463e05de..cc77b6da 100644
--- a/test/ValidatorsTest.js
+++ b/test/ValidatorsTest.js
@@ -69,12 +69,6 @@ ValidatorTest.prototype.testPhone = function() {
assertEquals(null, angular.validator.phone("+421 0905 933 297"));
};
-ValidatorTest.prototype.testSSN = function() {
- var error = "SSN needs to be in 999-99-9999 format.";
- assertEquals(angular.validator.ssn("ab"), error);
- assertEquals(angular.validator.ssn("123-45-6789"), null);
-};
-
ValidatorTest.prototype.testURL = function() {
var error = "URL needs to be in http://server[:port]/path format.";
assertEquals(angular.validator.url("ab"), error);
diff --git a/test/scenario/dslSpec.js b/test/scenario/dslSpec.js
index f9833e8b..e33cd056 100644
--- a/test/scenario/dslSpec.js
+++ b/test/scenario/dslSpec.js
@@ -509,7 +509,7 @@ describe("angular.scenario.dsl", function() {
it('should change value in textarea', function() {
doc.append('');
- var chain = $root.dsl.textarea('test.textarea');
+ var chain = $root.dsl.input('test.textarea');
chain.enter('foo');
expect(_jQuery('textarea[name="test.textarea"]').val()).toEqual('foo');
});
--
cgit v1.2.3