Browse Source

#426: Add test suite for the zipCode validator

nghuuphuoc 11 years ago
parent
commit
54127c1322

+ 1 - 1
dist/css/bootstrapValidator.min.css

@@ -2,7 +2,7 @@
  * BootstrapValidator (http://bootstrapvalidator.com)
  * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
  *
- * @version     v0.5.0-dev, built on 2014-07-01 11:21:31 AM
+ * @version     v0.5.0-dev, built on 2014-07-02 4:05:46 PM
  * @author      https://twitter.com/nghuuphuoc
  * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
  * @license     MIT

+ 38 - 34
dist/js/bootstrapValidator.js

@@ -2,7 +2,7 @@
  * BootstrapValidator (http://bootstrapvalidator.com)
  * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
  *
- * @version     v0.5.0-dev, built on 2014-07-01 11:21:31 AM
+ * @version     v0.5.0-dev, built on 2014-07-02 4:05:46 PM
  * @author      https://twitter.com/nghuuphuoc
  * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
  * @license     MIT
@@ -363,7 +363,7 @@
                     return options.message;
                 case (!!$.fn.bootstrapValidator.i18n[validatorName]):
                     return ('function' === typeof $.fn.bootstrapValidator.i18n[validatorName].getMessage)
-                            ? $.fn.bootstrapValidator.i18n[validatorName].getMessage(options)
+                            ? $.fn.bootstrapValidator.i18n[validatorName].getMessage(options, this)
                             : $.fn.bootstrapValidator.i18n[validatorName]['default'];
                 case (!!this.options.fields[field].message):
                     return this.options.fields[field].message;
@@ -788,27 +788,6 @@
         },
         
         /**
-         * Update the option of a specific validator
-         * 
-         * @param {String|jQuery} field The field name or field element
-         * @param {String} validator The validator name
-         * @param {String} option The option name
-         * @param {String} value The value to set
-         * @returns {BootstrapValidator}
-         */
-        updateOption: function(field, validator, option, value) {
-            if ('object' === typeof field) {
-                field = field.attr('data-bv-field');
-            }
-            if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
-                this.options.fields[field].validators[validator][option] = value;
-                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
-            }
-
-            return this;
-        },
-
-        /**
          * Update all validating results of field
          *
          * @param {String|jQuery} field The field name or field element
@@ -1159,6 +1138,27 @@
         },
 
         /**
+         * Update the option of a specific validator
+         *
+         * @param {String|jQuery} field The field name or field element
+         * @param {String} validator The validator name
+         * @param {String} option The option name
+         * @param {String} value The value to set
+         * @returns {BootstrapValidator}
+         */
+        updateOption: function(field, validator, option, value) {
+            if ('object' === typeof field) {
+                field = field.attr('data-bv-field');
+            }
+            if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
+                this.options.fields[field].validators[validator][option] = value;
+                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
+            }
+
+            return this;
+        },
+
+        /**
          * Add a new field
          *
          * @param {String|jQuery} field The field name or field element
@@ -1405,6 +1405,9 @@
                     }
 
                     for (validator in this.options.fields[field].validators) {
+                        if ($field.data('bv.dfs.' + validator)) {
+                            $field.data('bv.dfs.' + validator).reject();
+                        }
                         $field.removeData('bv.result.' + validator).removeData('bv.dfs.' + validator);
                     }
                 }
@@ -1539,10 +1542,10 @@
     };
 
     // Available validators
-    $.fn.bootstrapValidator.validators = {};
+    $.fn.bootstrapValidator.validators  = {};
 
     // i18n
-    $.fn.bootstrapValidator.i18n       = {};
+    $.fn.bootstrapValidator.i18n        = {};
 
     $.fn.bootstrapValidator.Constructor = BootstrapValidator;
 
@@ -1561,6 +1564,9 @@
             if ('function' === typeof functionName) {
                 return functionName.apply(this, args);
             } else if ('string' === typeof functionName) {
+                if ('()' === functionName.substring(functionName.length - 2)) {
+                    functionName = functionName.substring(0, functionName.length - 2);
+                }
                 var ns      = functionName.split('.'),
                     func    = ns.pop(),
                     context = window;
@@ -6104,7 +6110,6 @@
 ;(function($) {
     $.fn.bootstrapValidator.i18n.zipCode = $.extend($.fn.bootstrapValidator.i18n.zipCode || {}, {
         'default': 'Please enter a valid zip code',
-        countryNotSupported: 'The country code %s is not supported',
         country: 'Please enter a valid %s',
         countries: {
             'CA': 'Canadian postal code',
@@ -6118,12 +6123,8 @@
         },
 
         getMessage: function(options) {
-            var country = (options.country || 'US').toUpperCase();
-            if ($.inArray(country, $.fn.bootstrapValidator.validators.zipCode.COUNTRIES) === -1) {
-                return $.fn.bootstrapValidator.helpers.format(this.countryNotSupported, country);
-            }
-
-            if (this.countries[country]) {
+            var country = options.country;
+            if ('string' === typeof country && this.countries[country]) {
                 return $.fn.bootstrapValidator.helpers.format(this.country, this.countries[country]);
             }
 
@@ -6151,7 +6152,7 @@
          * The country can be defined by:
          * - An ISO 3166 country code
          * Currently it supports the following countries:
-         *      - US (United State)
+         *      - US (United States)
          *      - CA (Canada)
          *      - DK (Denmark)
          *      - GB (United Kingdom)
@@ -6201,11 +6202,14 @@
                     break;
             }
 
+            if (!country) {
+                return false;
+            }
+
             country = country.toUpperCase();
             if ($.inArray(country, this.COUNTRIES) === -1) {
                 return false;
             }
-
             switch (country) {
                 case 'CA': return /^(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}\s?[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}$/i.test(value);
                 case 'DK': return /^(DK(-|\s)?)?\d{4}$/i.test(value);

File diff suppressed because it is too large
+ 4 - 4
dist/js/bootstrapValidator.min.js


+ 30 - 24
src/js/bootstrapValidator.js

@@ -362,7 +362,7 @@
                     return options.message;
                 case (!!$.fn.bootstrapValidator.i18n[validatorName]):
                     return ('function' === typeof $.fn.bootstrapValidator.i18n[validatorName].getMessage)
-                            ? $.fn.bootstrapValidator.i18n[validatorName].getMessage(options)
+                            ? $.fn.bootstrapValidator.i18n[validatorName].getMessage(options, this)
                             : $.fn.bootstrapValidator.i18n[validatorName]['default'];
                 case (!!this.options.fields[field].message):
                     return this.options.fields[field].message;
@@ -787,27 +787,6 @@
         },
         
         /**
-         * Update the option of a specific validator
-         * 
-         * @param {String|jQuery} field The field name or field element
-         * @param {String} validator The validator name
-         * @param {String} option The option name
-         * @param {String} value The value to set
-         * @returns {BootstrapValidator}
-         */
-        updateOption: function(field, validator, option, value) {
-            if ('object' === typeof field) {
-                field = field.attr('data-bv-field');
-            }
-            if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
-                this.options.fields[field].validators[validator][option] = value;
-                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
-            }
-
-            return this;
-        },
-
-        /**
          * Update all validating results of field
          *
          * @param {String|jQuery} field The field name or field element
@@ -1158,6 +1137,27 @@
         },
 
         /**
+         * Update the option of a specific validator
+         *
+         * @param {String|jQuery} field The field name or field element
+         * @param {String} validator The validator name
+         * @param {String} option The option name
+         * @param {String} value The value to set
+         * @returns {BootstrapValidator}
+         */
+        updateOption: function(field, validator, option, value) {
+            if ('object' === typeof field) {
+                field = field.attr('data-bv-field');
+            }
+            if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
+                this.options.fields[field].validators[validator][option] = value;
+                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
+            }
+
+            return this;
+        },
+
+        /**
          * Add a new field
          *
          * @param {String|jQuery} field The field name or field element
@@ -1404,6 +1404,9 @@
                     }
 
                     for (validator in this.options.fields[field].validators) {
+                        if ($field.data('bv.dfs.' + validator)) {
+                            $field.data('bv.dfs.' + validator).reject();
+                        }
                         $field.removeData('bv.result.' + validator).removeData('bv.dfs.' + validator);
                     }
                 }
@@ -1538,10 +1541,10 @@
     };
 
     // Available validators
-    $.fn.bootstrapValidator.validators = {};
+    $.fn.bootstrapValidator.validators  = {};
 
     // i18n
-    $.fn.bootstrapValidator.i18n       = {};
+    $.fn.bootstrapValidator.i18n        = {};
 
     $.fn.bootstrapValidator.Constructor = BootstrapValidator;
 
@@ -1560,6 +1563,9 @@
             if ('function' === typeof functionName) {
                 return functionName.apply(this, args);
             } else if ('string' === typeof functionName) {
+                if ('()' === functionName.substring(functionName.length - 2)) {
+                    functionName = functionName.substring(0, functionName.length - 2);
+                }
                 var ns      = functionName.split('.'),
                     func    = ns.pop(),
                     context = window;

+ 7 - 9
src/js/validator/zipCode.js

@@ -1,7 +1,6 @@
 (function($) {
     $.fn.bootstrapValidator.i18n.zipCode = $.extend($.fn.bootstrapValidator.i18n.zipCode || {}, {
         'default': 'Please enter a valid zip code',
-        countryNotSupported: 'The country code %s is not supported',
         country: 'Please enter a valid %s',
         countries: {
             'CA': 'Canadian postal code',
@@ -15,12 +14,8 @@
         },
 
         getMessage: function(options) {
-            var country = (options.country || 'US').toUpperCase();
-            if ($.inArray(country, $.fn.bootstrapValidator.validators.zipCode.COUNTRIES) === -1) {
-                return $.fn.bootstrapValidator.helpers.format(this.countryNotSupported, country);
-            }
-
-            if (this.countries[country]) {
+            var country = options.country;
+            if ('string' === typeof country && this.countries[country]) {
                 return $.fn.bootstrapValidator.helpers.format(this.country, this.countries[country]);
             }
 
@@ -48,7 +43,7 @@
          * The country can be defined by:
          * - An ISO 3166 country code
          * Currently it supports the following countries:
-         *      - US (United State)
+         *      - US (United States)
          *      - CA (Canada)
          *      - DK (Denmark)
          *      - GB (United Kingdom)
@@ -98,11 +93,14 @@
                     break;
             }
 
+            if (!country) {
+                return false;
+            }
+
             country = country.toUpperCase();
             if ($.inArray(country, this.COUNTRIES) === -1) {
                 return false;
             }
-
             switch (country) {
                 case 'CA': return /^(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}\s?[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}$/i.test(value);
                 case 'DK': return /^(DK(-|\s)?)?\d{4}$/i.test(value);

+ 3 - 0
test/index.html

@@ -17,6 +17,9 @@
     <script type="text/javascript" src="../dist/js/bootstrapValidator.js"></script>
 
     <!-- Specs -->
+    <script type="text/javascript">
+    var TestSuite = {};
+    </script>
     <script type="text/javascript" src="spec.js"></script>
 </head>
 <body>

+ 205 - 13
test/spec.js

@@ -361,25 +361,25 @@ describe('enable validators', function() {
     });
 });
 
-var My = {
-    NameSpace: {
+TestSuite = $.extend({}, TestSuite, {
+    Event: {
         onEmailValid: function(e, data) {
-            $('#msg').html('My.NameSpace.onEmailValid() called, ' + data.field + ' is valid');
+            $('#msg').html('TestSuite.Event.onEmailValid() called, ' + data.field + ' is valid');
         },
 
         onEmailInvalid: function(e, data) {
-            $('#msg').html('My.NameSpace.onEmailInvalid() called, ' + data.field + ' is invalid');
+            $('#msg').html('TestSuite.Event.onEmailInvalid() called, ' + data.field + ' is invalid');
         },
 
         onFormValid: function(e) {
-            $('#msg').html('My.NameSpace.onFormValid() called, form ' + $(e.target).attr('id') + ' is valid');
+            $('#msg').html('TestSuite.Event.onFormValid() called, form ' + $(e.target).attr('id') + ' is valid');
         },
 
         onFormInvalid: function(e) {
-            $('#msg').html('My.NameSpace.onFormInvalid() called, form ' + $(e.target).attr('id') + ' is invalid');
+            $('#msg').html('TestSuite.Event.onFormInvalid() called, form ' + $(e.target).attr('id') + ' is invalid');
         }
     }
-};
+});
 
 // ---
 // Form events
@@ -430,7 +430,7 @@ describe('event form attribute callback global', function() {
 describe('event form attribute callback namespace', function() {
     beforeEach(function() {
         $([
-            '<form class="form-horizontal" id="eventForm" data-bv-onsuccess="My.NameSpace.onFormValid" data-bv-onerror="My.NameSpace.onFormInvalid" >',
+            '<form class="form-horizontal" id="eventForm" data-bv-onsuccess="TestSuite.Event.onFormValid" data-bv-onerror="TestSuite.Event.onFormInvalid" >',
                 '<div id="msg"></div>',
                 '<div class="form-group">',
                     '<input type="text" name="email" required data-bv-emailaddress />',
@@ -451,13 +451,13 @@ describe('event form attribute callback namespace', function() {
     it('call data-bv-onsuccess', function() {
         this.$email.val('email@domain.com');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onFormValid() called, form eventForm is valid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onFormValid() called, form eventForm is valid');
     });
 
     it('call data-bv-onerror', function() {
         this.$email.val('email@domain');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onFormInvalid() called, form eventForm is invalid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onFormInvalid() called, form eventForm is invalid');
     });
 });
 
@@ -595,7 +595,7 @@ describe('event field attribute callback namespace', function() {
             '<form class="form-horizontal" id="eventForm">',
                 '<div id="msg"></div>',
                 '<div class="form-group">',
-                    '<input type="text" name="email" data-bv-emailaddress data-bv-onsuccess="My.NameSpace.onEmailValid" data-bv-onerror="My.NameSpace.onEmailInvalid" />',
+                    '<input type="text" name="email" data-bv-emailaddress data-bv-onsuccess="TestSuite.Event.onEmailValid" data-bv-onerror="TestSuite.Event.onEmailInvalid" />',
                 '</div>',
             '</form>'
         ].join('\n')).appendTo('body');
@@ -613,13 +613,13 @@ describe('event field attribute callback namespace', function() {
     it('call data-bv-onsuccess', function() {
         this.$email.val('email@domain.com');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onEmailValid() called, email is valid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onEmailValid() called, email is valid');
     });
 
     it('call data-bv-onerror', function() {
         this.$email.val('email@domain');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onEmailInvalid() called, email is invalid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onEmailInvalid() called, email is invalid');
     });
 });
 
@@ -3371,3 +3371,195 @@ describe('vat', function() {
         }
     });
 });
+
+function getCountryCode(value, validator, $field) {
+    $('#msg').html('getCountryCode() called');
+    return validator.getFieldElements('country').val();
+};
+
+TestSuite = $.extend({}, TestSuite, {
+    ZipCode: {
+        getCountryCode: function(value, validator, $field) {
+            $('#msg').html('TestSuite.ZipCode.getCountryCode() called');
+            return validator.getFieldElements('country').val();
+        }
+    }
+});
+
+describe('zipCode', function() {
+    beforeEach(function() {
+        $([
+            '<form class="form-horizontal" id="zipCodeForm">',
+                '<div id="msg"></div>',
+                '<div class="form-group">',
+                    '<label class="col-md-3 control-label">Country:</label>',
+                    '<div class="col-md-2">',
+                        '<select class="form-control" name="country">',
+                            '<option value="">Select a country</option>',
+                            '<option value="US">United States</option>',
+                            '<option value="CA">Canada</option>',
+                            '<option value="DK">Denmark</option>',
+                            '<option value="IT">Italy</option>',
+                            '<option value="NL">Netherlands</option>',
+                            '<option value="SE">Sweden</option>',
+                            '<option value="GB">United Kingdom</option>',
+                        '</select>',
+                    '</div>',
+                '</div>',
+                '<div class="form-group">',
+                    '<label class="col-md-3 control-label">Zipcode</label>',
+                    '<div class="col-md-2">',
+                        '<input type="text" class="form-control" name="zc" data-bv-zipcode data-bv-zipcode-country="US" />',
+                    '</div>',
+                '</div>',
+            '</form>'
+        ].join('\n')).appendTo('body');
+
+        $('#zipCodeForm').bootstrapValidator();
+
+        /**
+         * @type {BootstrapValidator}
+         */
+        this.bv       = $('#zipCodeForm').data('bootstrapValidator');
+
+        this.$country = this.bv.getFieldElements('country');
+        this.$zipCode = this.bv.getFieldElements('zc');
+    });
+
+    afterEach(function() {
+        $('#zipCodeForm').bootstrapValidator('destroy').remove();
+    });
+
+    it('country code US', function() {
+        this.$zipCode.val('12345');
+        this.bv.validate();
+        expect(this.bv.isValid()).toBeTruthy();
+
+        this.bv.resetForm();
+        this.$zipCode.val('123');
+        this.bv.validate();
+        expect(this.bv.isValid()).toEqual(false);
+    });
+
+    it('country code updateOption()', function() {
+        // Check IT postal code
+        this.bv.updateOption('zc', 'zipCode', 'country', 'IT');
+        this.$zipCode.val('1234');
+        this.bv.validate();
+        expect(this.bv.isValid()).toEqual(false);
+
+        this.bv.resetForm();
+        this.$zipCode.val('IT-12345');
+        this.bv.validate();
+        expect(this.bv.isValid()).toBeTruthy();
+
+        // Check United Kingdom postal code
+        this.bv.updateOption('zc', 'zipCode', 'country', 'GB');
+        var validUkSamples = ['EC1A 1BB', 'W1A 1HQ', 'M1 1AA', 'B33 8TH', 'CR2 6XH', 'DN55 1PT', 'AI-2640', 'ASCN 1ZZ', 'GIR 0AA'];
+
+        for (var i in validUkSamples) {
+            this.bv.resetForm();
+            this.$zipCode.val(validUkSamples[i]);
+            this.bv.validate();
+            expect(this.bv.isValid()).toBeTruthy();
+        }
+    });
+
+    it('country code other field declarative', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'country');
+
+        // Need to destroy the plugin instance ...
+        $('#zipCodeForm').bootstrapValidator('destroy');
+
+        // ... and re-create it
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('IT');
+
+        this.bv.resetForm();
+        this.$zipCode.val('1234');
+        this.bv.validate();
+        expect(this.bv.isValid()).toEqual(false);
+
+        this.bv.resetForm();
+        this.$zipCode.val('I-12345');
+        this.bv.validate();
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+
+    it('country code callback declarative function', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'getCountryCode');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('NL');
+        this.$zipCode.val('0123');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toEqual(false);
+    });
+
+    it('country code callback declarative function()', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'getCountryCode()');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('NL');
+        this.$zipCode.val('1234 ab');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+
+    it('country code callback declarative A.B.C', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'TestSuite.ZipCode.getCountryCode');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('DK');
+        this.$zipCode.val('DK 123');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('TestSuite.ZipCode.getCountryCode() called');
+        expect(this.bv.isValid()).toEqual(false);
+    });
+
+    it('country code callback declarative A.B.C()', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'TestSuite.ZipCode.getCountryCode()');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('DK');
+        this.$zipCode.val('DK-1234');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('TestSuite.ZipCode.getCountryCode() called');
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+
+    it('country code callback programmatically', function() {
+        this.$zipCode.removeAttr('data-bv-zipcode-country');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm')
+                        .bootstrapValidator({
+                            fields: {
+                                zc: {
+                                    validators: {
+                                        zipCode: {
+                                            country: function(value, validator, $field) {
+                                                return getCountryCode(value, validator, $field);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        })
+                        .data('bootstrapValidator');
+        this.$country.val('SE');
+
+        this.bv.resetForm();
+        this.$zipCode.val('S-567 8');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toEqual(false);
+
+        this.bv.resetForm();
+        this.$zipCode.val('S-12345');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+});

+ 13 - 13
test/spec/event.js

@@ -1,22 +1,22 @@
-var My = {
-    NameSpace: {
+TestSuite = $.extend({}, TestSuite, {
+    Event: {
         onEmailValid: function(e, data) {
-            $('#msg').html('My.NameSpace.onEmailValid() called, ' + data.field + ' is valid');
+            $('#msg').html('TestSuite.Event.onEmailValid() called, ' + data.field + ' is valid');
         },
 
         onEmailInvalid: function(e, data) {
-            $('#msg').html('My.NameSpace.onEmailInvalid() called, ' + data.field + ' is invalid');
+            $('#msg').html('TestSuite.Event.onEmailInvalid() called, ' + data.field + ' is invalid');
         },
 
         onFormValid: function(e) {
-            $('#msg').html('My.NameSpace.onFormValid() called, form ' + $(e.target).attr('id') + ' is valid');
+            $('#msg').html('TestSuite.Event.onFormValid() called, form ' + $(e.target).attr('id') + ' is valid');
         },
 
         onFormInvalid: function(e) {
-            $('#msg').html('My.NameSpace.onFormInvalid() called, form ' + $(e.target).attr('id') + ' is invalid');
+            $('#msg').html('TestSuite.Event.onFormInvalid() called, form ' + $(e.target).attr('id') + ' is invalid');
         }
     }
-};
+});
 
 // ---
 // Form events
@@ -67,7 +67,7 @@ describe('event form attribute callback global', function() {
 describe('event form attribute callback namespace', function() {
     beforeEach(function() {
         $([
-            '<form class="form-horizontal" id="eventForm" data-bv-onsuccess="My.NameSpace.onFormValid" data-bv-onerror="My.NameSpace.onFormInvalid" >',
+            '<form class="form-horizontal" id="eventForm" data-bv-onsuccess="TestSuite.Event.onFormValid" data-bv-onerror="TestSuite.Event.onFormInvalid" >',
                 '<div id="msg"></div>',
                 '<div class="form-group">',
                     '<input type="text" name="email" required data-bv-emailaddress />',
@@ -88,13 +88,13 @@ describe('event form attribute callback namespace', function() {
     it('call data-bv-onsuccess', function() {
         this.$email.val('email@domain.com');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onFormValid() called, form eventForm is valid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onFormValid() called, form eventForm is valid');
     });
 
     it('call data-bv-onerror', function() {
         this.$email.val('email@domain');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onFormInvalid() called, form eventForm is invalid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onFormInvalid() called, form eventForm is invalid');
     });
 });
 
@@ -232,7 +232,7 @@ describe('event field attribute callback namespace', function() {
             '<form class="form-horizontal" id="eventForm">',
                 '<div id="msg"></div>',
                 '<div class="form-group">',
-                    '<input type="text" name="email" data-bv-emailaddress data-bv-onsuccess="My.NameSpace.onEmailValid" data-bv-onerror="My.NameSpace.onEmailInvalid" />',
+                    '<input type="text" name="email" data-bv-emailaddress data-bv-onsuccess="TestSuite.Event.onEmailValid" data-bv-onerror="TestSuite.Event.onEmailInvalid" />',
                 '</div>',
             '</form>'
         ].join('\n')).appendTo('body');
@@ -250,13 +250,13 @@ describe('event field attribute callback namespace', function() {
     it('call data-bv-onsuccess', function() {
         this.$email.val('email@domain.com');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onEmailValid() called, email is valid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onEmailValid() called, email is valid');
     });
 
     it('call data-bv-onerror', function() {
         this.$email.val('email@domain');
         this.bv.validate();
-        expect($('#msg').html()).toEqual('My.NameSpace.onEmailInvalid() called, email is invalid');
+        expect($('#msg').html()).toEqual('TestSuite.Event.onEmailInvalid() called, email is invalid');
     });
 });
 

+ 191 - 0
test/spec/validator/zipCode.js

@@ -0,0 +1,191 @@
+function getCountryCode(value, validator, $field) {
+    $('#msg').html('getCountryCode() called');
+    return validator.getFieldElements('country').val();
+};
+
+TestSuite = $.extend({}, TestSuite, {
+    ZipCode: {
+        getCountryCode: function(value, validator, $field) {
+            $('#msg').html('TestSuite.ZipCode.getCountryCode() called');
+            return validator.getFieldElements('country').val();
+        }
+    }
+});
+
+describe('zipCode', function() {
+    beforeEach(function() {
+        $([
+            '<form class="form-horizontal" id="zipCodeForm">',
+                '<div id="msg"></div>',
+                '<div class="form-group">',
+                    '<label class="col-md-3 control-label">Country:</label>',
+                    '<div class="col-md-2">',
+                        '<select class="form-control" name="country">',
+                            '<option value="">Select a country</option>',
+                            '<option value="US">United States</option>',
+                            '<option value="CA">Canada</option>',
+                            '<option value="DK">Denmark</option>',
+                            '<option value="IT">Italy</option>',
+                            '<option value="NL">Netherlands</option>',
+                            '<option value="SE">Sweden</option>',
+                            '<option value="GB">United Kingdom</option>',
+                        '</select>',
+                    '</div>',
+                '</div>',
+                '<div class="form-group">',
+                    '<label class="col-md-3 control-label">Zipcode</label>',
+                    '<div class="col-md-2">',
+                        '<input type="text" class="form-control" name="zc" data-bv-zipcode data-bv-zipcode-country="US" />',
+                    '</div>',
+                '</div>',
+            '</form>'
+        ].join('\n')).appendTo('body');
+
+        $('#zipCodeForm').bootstrapValidator();
+
+        /**
+         * @type {BootstrapValidator}
+         */
+        this.bv       = $('#zipCodeForm').data('bootstrapValidator');
+
+        this.$country = this.bv.getFieldElements('country');
+        this.$zipCode = this.bv.getFieldElements('zc');
+    });
+
+    afterEach(function() {
+        $('#zipCodeForm').bootstrapValidator('destroy').remove();
+    });
+
+    it('country code US', function() {
+        this.$zipCode.val('12345');
+        this.bv.validate();
+        expect(this.bv.isValid()).toBeTruthy();
+
+        this.bv.resetForm();
+        this.$zipCode.val('123');
+        this.bv.validate();
+        expect(this.bv.isValid()).toEqual(false);
+    });
+
+    it('country code updateOption()', function() {
+        // Check IT postal code
+        this.bv.updateOption('zc', 'zipCode', 'country', 'IT');
+        this.$zipCode.val('1234');
+        this.bv.validate();
+        expect(this.bv.isValid()).toEqual(false);
+
+        this.bv.resetForm();
+        this.$zipCode.val('IT-12345');
+        this.bv.validate();
+        expect(this.bv.isValid()).toBeTruthy();
+
+        // Check United Kingdom postal code
+        this.bv.updateOption('zc', 'zipCode', 'country', 'GB');
+        var validUkSamples = ['EC1A 1BB', 'W1A 1HQ', 'M1 1AA', 'B33 8TH', 'CR2 6XH', 'DN55 1PT', 'AI-2640', 'ASCN 1ZZ', 'GIR 0AA'];
+
+        for (var i in validUkSamples) {
+            this.bv.resetForm();
+            this.$zipCode.val(validUkSamples[i]);
+            this.bv.validate();
+            expect(this.bv.isValid()).toBeTruthy();
+        }
+    });
+
+    it('country code other field declarative', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'country');
+
+        // Need to destroy the plugin instance ...
+        $('#zipCodeForm').bootstrapValidator('destroy');
+
+        // ... and re-create it
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('IT');
+
+        this.bv.resetForm();
+        this.$zipCode.val('1234');
+        this.bv.validate();
+        expect(this.bv.isValid()).toEqual(false);
+
+        this.bv.resetForm();
+        this.$zipCode.val('I-12345');
+        this.bv.validate();
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+
+    it('country code callback declarative function', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'getCountryCode');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('NL');
+        this.$zipCode.val('0123');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toEqual(false);
+    });
+
+    it('country code callback declarative function()', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'getCountryCode()');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('NL');
+        this.$zipCode.val('1234 ab');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+
+    it('country code callback declarative A.B.C', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'TestSuite.ZipCode.getCountryCode');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('DK');
+        this.$zipCode.val('DK 123');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('TestSuite.ZipCode.getCountryCode() called');
+        expect(this.bv.isValid()).toEqual(false);
+    });
+
+    it('country code callback declarative A.B.C()', function() {
+        this.$zipCode.attr('data-bv-zipcode-country', 'TestSuite.ZipCode.getCountryCode()');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm').bootstrapValidator().data('bootstrapValidator');
+        this.$country.val('DK');
+        this.$zipCode.val('DK-1234');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('TestSuite.ZipCode.getCountryCode() called');
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+
+    it('country code callback programmatically', function() {
+        this.$zipCode.removeAttr('data-bv-zipcode-country');
+        $('#zipCodeForm').bootstrapValidator('destroy');
+        this.bv = $('#zipCodeForm')
+                        .bootstrapValidator({
+                            fields: {
+                                zc: {
+                                    validators: {
+                                        zipCode: {
+                                            country: function(value, validator, $field) {
+                                                return getCountryCode(value, validator, $field);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        })
+                        .data('bootstrapValidator');
+        this.$country.val('SE');
+
+        this.bv.resetForm();
+        this.$zipCode.val('S-567 8');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toEqual(false);
+
+        this.bv.resetForm();
+        this.$zipCode.val('S-12345');
+        this.bv.validate();
+        expect($('#msg').html()).toEqual('getCountryCode() called');
+        expect(this.bv.isValid()).toBeTruthy();
+    });
+});