From 6a682b0ac0928f8a426dc7ba0cf82de622c33cda Mon Sep 17 00:00:00 2001 From: huei90 Date: Thu, 3 Jul 2014 15:42:36 +0800 Subject: [PATCH] Add rule.js => angular-validation-rule.js --- CONTRIBUTING.md | 2 +- Gruntfile.js | 6 +++-- README.md | 11 +++++++-- config/karma.conf.angular.1.2.js | 1 + config/karma.conf.angular.1.3.js | 1 + demo/demo.js | 2 +- dist/angular-validation-rule.js | 35 +++++++++++++++++++++++++++++ dist/angular-validation-rule.min.js | 1 + dist/angular-validation.js | 30 ++++--------------------- dist/angular-validation.min.js | 2 +- index.html | 1 + src/provider.js | 30 ++++--------------------- src/rule.js | 35 +++++++++++++++++++++++++++++ test/unit/directivesSpec.js | 3 ++- test/unit/providerSpec.js | 2 +- 15 files changed, 101 insertions(+), 61 deletions(-) create mode 100644 dist/angular-validation-rule.js create mode 100644 dist/angular-validation-rule.min.js create mode 100644 src/rule.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c70c4a1..8ac556a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ grunt dev **Start coding** ``` -open `provider.js`, looking for `var expression` and `var defaultMsg` +open `rule.js`, looking for `var expression` and `var defaultMsg` Adding a new expression and defaultMsg to extend it ``` diff --git a/Gruntfile.js b/Gruntfile.js index 253799a..69ac7c5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -31,14 +31,16 @@ module.exports = function (grunt) { concat: { basic_and_extras: { files: { - 'dist/angular-validation.js': ['src/module.js', 'src/provider.js', 'src/directive.js'] + 'dist/angular-validation.js': ['src/module.js', 'src/provider.js', 'src/directive.js'], + 'dist/angular-validation-rule.js': ['src/rule.js'] } } }, uglify: { my_target: { files: { - 'dist/angular-validation.min.js': ['dist/angular-validation.js'] + 'dist/angular-validation.min.js': ['dist/angular-validation.js'], + 'dist/angular-validation-rule.min.js': ['dist/angular-validation-rule.js'] } } }, diff --git a/README.md b/README.md index 18e3845..a7d6056 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,15 @@ npm install angular-validation Using angular-validation --- -```javascript +```html + + +``` +```js angular.module('yourApp', ['validation']); + +// including your validation rule +angular.module('yourApp', ['validation', 'validation.rule']); ``` Writing your Code @@ -278,7 +285,7 @@ Easily disable success/error message }]); ``` -Built-in validation in angular-validation +Built-in validation in angular-validation-rule === 1. Required diff --git a/config/karma.conf.angular.1.2.js b/config/karma.conf.angular.1.2.js index d575481..68cf43c 100644 --- a/config/karma.conf.angular.1.2.js +++ b/config/karma.conf.angular.1.2.js @@ -10,6 +10,7 @@ module.exports = function(config) { 'test/lib/angular.1.2.16.js', 'test/lib/angular-mocks.1.2.16.js', 'dist/angular-validation.js', + 'dist/angular-validation-rule.js', 'test/unit/*.js' ], diff --git a/config/karma.conf.angular.1.3.js b/config/karma.conf.angular.1.3.js index 459c6a9..0dff5ac 100644 --- a/config/karma.conf.angular.1.3.js +++ b/config/karma.conf.angular.1.3.js @@ -10,6 +10,7 @@ module.exports = function(config) { 'test/lib/angular.1.3.0-beta.5.js', 'test/lib/angular-mocks.1.3.0-beta.5.js', 'dist/angular-validation.js', + 'dist/angular-validation-rule.js', 'test/unit/*.js' ], diff --git a/demo/demo.js b/demo/demo.js index 8f44e7b..a87a1d0 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -1,5 +1,5 @@ (function () { - angular.module('myApp', ['validation']) + angular.module('myApp', ['validation', 'validation.rule']) // ------------------- // config phase diff --git a/dist/angular-validation-rule.js b/dist/angular-validation-rule.js new file mode 100644 index 0000000..78749a6 --- /dev/null +++ b/dist/angular-validation-rule.js @@ -0,0 +1,35 @@ +(function () { + angular.module('validation.rule', ['validation']) + .config(['$validationProvider', function ($validationProvider) { + + var expression = { + required: /^.+$/, + url: /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/, + email: /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/, + number: /^\d+$/ + }; + + var defaultMsg = { + required: { + error: 'This should be Required!!', + success: 'It\'s Required' + }, + url: { + error: 'This should be Url', + success: 'It\'s Url' + }, + email: { + error: 'This should be Email', + success: 'It\'s Email' + }, + number: { + error: 'This should be Number', + success: 'It\'s Number' + } + }; + + $validationProvider.setExpression(expression).setDefaultMsg(defaultMsg); + + }]); + +}).call(this); \ No newline at end of file diff --git a/dist/angular-validation-rule.min.js b/dist/angular-validation-rule.min.js new file mode 100644 index 0000000..f2ce74e --- /dev/null +++ b/dist/angular-validation-rule.min.js @@ -0,0 +1 @@ +(function(){angular.module("validation.rule",["validation"]).config(["$validationProvider",function(a){var b={required:/^.+$/,url:/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/,email:/^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/,number:/^\d+$/},c={required:{error:"This should be Required!!",success:"It's Required"},url:{error:"This should be Url",success:"It's Url"},email:{error:"This should be Email",success:"It's Email"},number:{error:"This should be Number",success:"It's Number"}};a.setExpression(b).setDefaultMsg(c)}])}).call(this); \ No newline at end of file diff --git a/dist/angular-validation.js b/dist/angular-validation.js index b99a997..6fe3124 100644 --- a/dist/angular-validation.js +++ b/dist/angular-validation.js @@ -29,38 +29,16 @@ /** * Define validation type RegExp - * @type {{required: RegExp, url: RegExp, email: RegExp}} + * @type {{}} */ - var expression = { - required: /^.+$/, - url: /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/, - email: /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/, - number: /^\d+$/ - }; + var expression = {}; /** * default error, success message - * @type {{required: {error: string, success: string}, url: {error: string, success: string}, email: {error: string, success: string}, number: {error: string, success: string}}} + * @type {{}} */ - var defaultMsg = { - required: { - error: 'This should be Required!!', - success: 'It\'s Required' - }, - url: { - error: 'This should be Url', - success: 'It\'s Url' - }, - email: { - error: 'This should be Email', - success: 'It\'s Email' - }, - number: { - error: 'This should be Number', - success: 'It\'s Number' - } - }; + var defaultMsg = {}; /** diff --git a/dist/angular-validation.min.js b/dist/angular-validation.min.js index 761e423..f0de43c 100644 --- a/dist/angular-validation.min.js +++ b/dist/angular-validation.min.js @@ -1 +1 @@ -(function(){angular.module("validation",["validation.provider","validation.directive"])}).call(this),function(){angular.module("validation.provider",[]).provider("$validation",function(){var a,b,c,d,e,f=this,g=function(f){a=f,b=a.get("$rootScope"),c=a.get("$http"),d=a.get("$q"),e=a.get("$timeout")},h={required:/^.+$/,url:/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/,email:/^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/,number:/^\d+$/},i={required:{error:"This should be Required!!",success:"It's Required"},url:{error:"This should be Url",success:"It's Url"},email:{error:"This should be Email",success:"It's Email"},number:{error:"This should be Number",success:"It's Number"}};this.setExpression=function(a){return angular.extend(h,a),f},this.getExpression=function(a){return h[a]},this.setDefaultMsg=function(a){return angular.extend(i,a),f},this.getDefaultMsg=function(a){return i[a]},this.setErrorHTML=function(a){return a.constructor===Function?(f.getErrorHTML=a,f):void 0},this.getErrorHTML=function(a){return'

'+a+"

"},this.setSuccessHTML=function(a){return a.constructor===Function?(f.getSuccessHTML=a,f):void 0},this.getSuccessHTML=function(a){return'

'+a+"

"},this.showSuccessMessage=!0,this.showErrorMessage=!0,this.checkValid=function(a){return void 0===a.$valid?!1:a&&a.$valid===!0},this.validate=function(a){var c=0;for(var g in a)a[g].hasOwnProperty("$dirty")&&b.$broadcast(g+"submit-"+a[g].validationId,c++);var h=d.defer();return h.promise.success=function(a){return h.promise.then(function(b){a(b)}),h.promise},h.promise.error=function(a){return h.promise.then(null,function(b){a(b)}),h.promise},e(function(){f.checkValid(a)?h.resolve("success"):h.reject("error")}),h.promise},this.reset=function(a){for(var c in a)a[c].hasOwnProperty("$dirty")&&b.$broadcast(c+"reset-"+a[c].validationId)},this.$get=["$injector",function(a){return g(a),{setErrorHTML:this.setErrorHTML,getErrorHTML:this.getErrorHTML,setSuccessHTML:this.setSuccessHTML,getSuccessHTML:this.getSuccessHTML,setExpression:this.setExpression,getExpression:this.getExpression,setDefaultMsg:this.setDefaultMsg,getDefaultMsg:this.getDefaultMsg,showSuccessMessage:this.showSuccessMessage,showErrorMessage:this.showErrorMessage,checkValid:this.checkValid,validate:this.validate,reset:this.reset}}]})}.call(this),function(){angular.module("validation.directive",["validation.provider"]).directive("validator",["$injector",function(a){var b=a.get("$validation"),c=a.get("$q"),d=a.get("$timeout"),e=function(a,c,d,e,f){return a.next().html(b.showSuccessMessage?b.getSuccessHTML(c||b.getDefaultMsg(d).success):""),f.$setValidity(f.$name,!0),e&&e(),!0},f=function(a,c,d,e,f){return a.next().html(b.showErrorMessage?b.getErrorHTML(c||b.getDefaultMsg(d).error):""),f.$setValidity(f.$name,!1),e&&e(),!1},g=!1,h=function(a,d,g,h,i,j){var k=i+"SuccessMessage",l=i+"ErrorMessage",m=b.getExpression(i).constructor,n={success:function(){return e(d,g[k],i,a.validCallback,h)},error:function(){return f(d,g[l],i,a.invalidCallback,h)}};return m===Function?c.all([b.getExpression(i)(j,a,d,g)]).then(function(a){return a&&a.length>0&&a[0]?n.success():n.error()},function(){return n.error()}):m===RegExp&&b.getExpression(i).test(j)?n.success():n.error()},i=function(){return(65536*(1+Math.random())|0).toString(16).substring(1)},j=function(){return i()+i()+i()+i()};return{restrict:"A",require:"ngModel",scope:{model:"=ngModel",validCallback:"&",invalidCallback:"&"},link:function(a,b,c,e){var f=function(){},i=c.validator.split(","),k=e.validationId=j();b.after(""),e.$setValidity(e.$name,!1),a.$on(e.$name+"reset-"+k,function(){f(),g=!1,e.$setViewValue(""),e.$setPristine(),e.$setValidity(e.$name,!1),e.$render(),b.next().html("")}),i.forEach(function(d){return a.$on(e.$name+"submit-"+k,function(i,j){var k=b[0].value,l=!1;0==j&&(g=!1),l=h(a,b,c,e,d,k),"submit"===c.validMethod&&(f(),f=a.$watch("model",function(f,g){f!==g&&((void 0===f||null===f)&&(f=""),l=h(a,b,c,e,d,f))})),g||l||(g=!0,b[0].focus())}),"blur"===c.validMethod?void b.bind("blur",function(){var f=b[0].value;a.$apply(function(){h(a,b,c,e,d,f)})}):void("submit"!==c.validMethod&&"submit-only"!==c.validMethod&&a.$watch("model",function(f){if(e.$pristine&&e.$viewValue)e.$setViewValue(e.$viewValue);else if(e.$pristine)return void b.next().html("");h(a,b,c,e,d,f)}))}),d(function(){c.$observe("noValidationMessage",function(a){var c=b.next();"true"==a||1==a?c.css("display","none"):("false"==a||0==a)&&c.css("display","block")})})}}}]).directive("validationSubmit",["$injector",function(a){var b=a.get("$validation"),c=a.get("$timeout"),d=a.get("$parse");return{priority:1,terminal:!0,link:function(a,e,f){var g=f.validationSubmit;c(function(){e.on("click",function(c){c.preventDefault(),b.validate(a[g]).success(function(){d(f.ngClick)(a)})})})}}}]).directive("validationReset",["$injector",function(a){var b=a.get("$validation"),c=a.get("$timeout");return{link:function(a,d,e){var f=e.validationReset;c(function(){d.on("click",function(c){c.preventDefault(),b.reset(a[f])})})}}}])}.call(this); \ No newline at end of file +(function(){angular.module("validation",["validation.provider","validation.directive"])}).call(this),function(){angular.module("validation.provider",[]).provider("$validation",function(){var a,b,c,d,e,f=this,g=function(f){a=f,b=a.get("$rootScope"),c=a.get("$http"),d=a.get("$q"),e=a.get("$timeout")},h={},i={};this.setExpression=function(a){return angular.extend(h,a),f},this.getExpression=function(a){return h[a]},this.setDefaultMsg=function(a){return angular.extend(i,a),f},this.getDefaultMsg=function(a){return i[a]},this.setErrorHTML=function(a){return a.constructor===Function?(f.getErrorHTML=a,f):void 0},this.getErrorHTML=function(a){return'

'+a+"

"},this.setSuccessHTML=function(a){return a.constructor===Function?(f.getSuccessHTML=a,f):void 0},this.getSuccessHTML=function(a){return'

'+a+"

"},this.showSuccessMessage=!0,this.showErrorMessage=!0,this.checkValid=function(a){return void 0===a.$valid?!1:a&&a.$valid===!0},this.validate=function(a){var c=0;for(var g in a)a[g].hasOwnProperty("$dirty")&&b.$broadcast(g+"submit-"+a[g].validationId,c++);var h=d.defer();return h.promise.success=function(a){return h.promise.then(function(b){a(b)}),h.promise},h.promise.error=function(a){return h.promise.then(null,function(b){a(b)}),h.promise},e(function(){f.checkValid(a)?h.resolve("success"):h.reject("error")}),h.promise},this.reset=function(a){for(var c in a)a[c].hasOwnProperty("$dirty")&&b.$broadcast(c+"reset-"+a[c].validationId)},this.$get=["$injector",function(a){return g(a),{setErrorHTML:this.setErrorHTML,getErrorHTML:this.getErrorHTML,setSuccessHTML:this.setSuccessHTML,getSuccessHTML:this.getSuccessHTML,setExpression:this.setExpression,getExpression:this.getExpression,setDefaultMsg:this.setDefaultMsg,getDefaultMsg:this.getDefaultMsg,showSuccessMessage:this.showSuccessMessage,showErrorMessage:this.showErrorMessage,checkValid:this.checkValid,validate:this.validate,reset:this.reset}}]})}.call(this),function(){angular.module("validation.directive",["validation.provider"]).directive("validator",["$injector",function(a){var b=a.get("$validation"),c=a.get("$q"),d=a.get("$timeout"),e=function(a,c,d,e,f){return a.next().html(b.showSuccessMessage?b.getSuccessHTML(c||b.getDefaultMsg(d).success):""),f.$setValidity(f.$name,!0),e&&e(),!0},f=function(a,c,d,e,f){return a.next().html(b.showErrorMessage?b.getErrorHTML(c||b.getDefaultMsg(d).error):""),f.$setValidity(f.$name,!1),e&&e(),!1},g=!1,h=function(a,d,g,h,i,j){var k=i+"SuccessMessage",l=i+"ErrorMessage",m=b.getExpression(i).constructor,n={success:function(){return e(d,g[k],i,a.validCallback,h)},error:function(){return f(d,g[l],i,a.invalidCallback,h)}};return m===Function?c.all([b.getExpression(i)(j,a,d,g)]).then(function(a){return a&&a.length>0&&a[0]?n.success():n.error()},function(){return n.error()}):m===RegExp&&b.getExpression(i).test(j)?n.success():n.error()},i=function(){return(65536*(1+Math.random())|0).toString(16).substring(1)},j=function(){return i()+i()+i()+i()};return{restrict:"A",require:"ngModel",scope:{model:"=ngModel",validCallback:"&",invalidCallback:"&"},link:function(a,b,c,e){var f=function(){},i=c.validator.split(","),k=e.validationId=j();b.after(""),e.$setValidity(e.$name,!1),a.$on(e.$name+"reset-"+k,function(){f(),g=!1,e.$setViewValue(""),e.$setPristine(),e.$setValidity(e.$name,!1),e.$render(),b.next().html("")}),i.forEach(function(d){return a.$on(e.$name+"submit-"+k,function(i,j){var k=b[0].value,l=!1;0==j&&(g=!1),l=h(a,b,c,e,d,k),"submit"===c.validMethod&&(f(),f=a.$watch("model",function(f,g){f!==g&&((void 0===f||null===f)&&(f=""),l=h(a,b,c,e,d,f))})),g||l||(g=!0,b[0].focus())}),"blur"===c.validMethod?void b.bind("blur",function(){var f=b[0].value;a.$apply(function(){h(a,b,c,e,d,f)})}):void("submit"!==c.validMethod&&"submit-only"!==c.validMethod&&a.$watch("model",function(f){if(e.$pristine&&e.$viewValue)e.$setViewValue(e.$viewValue);else if(e.$pristine)return void b.next().html("");h(a,b,c,e,d,f)}))}),d(function(){c.$observe("noValidationMessage",function(a){var c=b.next();"true"==a||1==a?c.css("display","none"):("false"==a||0==a)&&c.css("display","block")})})}}}]).directive("validationSubmit",["$injector",function(a){var b=a.get("$validation"),c=a.get("$timeout"),d=a.get("$parse");return{priority:1,terminal:!0,link:function(a,e,f){var g=f.validationSubmit;c(function(){e.on("click",function(c){c.preventDefault(),b.validate(a[g]).success(function(){d(f.ngClick)(a)})})})}}}]).directive("validationReset",["$injector",function(a){var b=a.get("$validation"),c=a.get("$timeout");return{link:function(a,d,e){var f=e.validationReset;c(function(){d.on("click",function(c){c.preventDefault(),b.reset(a[f])})})}}}])}.call(this); \ No newline at end of file diff --git a/index.html b/index.html index 075eb1e..dff9458 100644 --- a/index.html +++ b/index.html @@ -207,6 +207,7 @@

Angular Validation. Fork me on Github + diff --git a/src/provider.js b/src/provider.js index 193833b..62b9d49 100644 --- a/src/provider.js +++ b/src/provider.js @@ -26,38 +26,16 @@ /** * Define validation type RegExp - * @type {{required: RegExp, url: RegExp, email: RegExp}} + * @type {{}} */ - var expression = { - required: /^.+$/, - url: /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/, - email: /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/, - number: /^\d+$/ - }; + var expression = {}; /** * default error, success message - * @type {{required: {error: string, success: string}, url: {error: string, success: string}, email: {error: string, success: string}, number: {error: string, success: string}}} + * @type {{}} */ - var defaultMsg = { - required: { - error: 'This should be Required!!', - success: 'It\'s Required' - }, - url: { - error: 'This should be Url', - success: 'It\'s Url' - }, - email: { - error: 'This should be Email', - success: 'It\'s Email' - }, - number: { - error: 'This should be Number', - success: 'It\'s Number' - } - }; + var defaultMsg = {}; /** diff --git a/src/rule.js b/src/rule.js new file mode 100644 index 0000000..78749a6 --- /dev/null +++ b/src/rule.js @@ -0,0 +1,35 @@ +(function () { + angular.module('validation.rule', ['validation']) + .config(['$validationProvider', function ($validationProvider) { + + var expression = { + required: /^.+$/, + url: /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/, + email: /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/, + number: /^\d+$/ + }; + + var defaultMsg = { + required: { + error: 'This should be Required!!', + success: 'It\'s Required' + }, + url: { + error: 'This should be Url', + success: 'It\'s Url' + }, + email: { + error: 'This should be Email', + success: 'It\'s Email' + }, + number: { + error: 'This should be Number', + success: 'It\'s Number' + } + }; + + $validationProvider.setExpression(expression).setDefaultMsg(defaultMsg); + + }]); + +}).call(this); \ No newline at end of file diff --git a/test/unit/directivesSpec.js b/test/unit/directivesSpec.js index 7f5dc27..16f6619 100644 --- a/test/unit/directivesSpec.js +++ b/test/unit/directivesSpec.js @@ -11,7 +11,8 @@ describe('directives', function () { element; beforeEach(module('validation.directive')); - + beforeEach(module('validation.rule')); + describe('Example of Required', function () { beforeEach(inject(function ($injector) { diff --git a/test/unit/providerSpec.js b/test/unit/providerSpec.js index af32959..2a5255e 100644 --- a/test/unit/providerSpec.js +++ b/test/unit/providerSpec.js @@ -13,7 +13,7 @@ describe('provider', function () { myApp; beforeEach(function () { - myApp = angular.module('myApp', ['validation']) + myApp = angular.module('myApp', ['validation', 'validation.rule']) .config(function ($validationProvider) { validationProvider = $validationProvider; });