From 3b76233d0e59ef7f3f2ceb47486769f43394f890 Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Thu, 13 Oct 2016 19:57:12 +0300 Subject: [PATCH 1/5] refactor(input): avoid duplicating `step`/`ngStep` tests --- test/ng/directive/inputSpec.js | 208 +++++++++++---------------------- 1 file changed, 70 insertions(+), 138 deletions(-) diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 15471354c56f..9973c2411cd3 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -2621,154 +2621,88 @@ describe('input', function() { }); }); - describe('step', function() { - it('should validate', function() { - $rootScope.step = 10; - $rootScope.value = 20; - var inputElm = helper.compileInput(''); - - expect(inputElm.val()).toBe('20'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(20); - expect($rootScope.form.alias.$error.step).toBeFalsy(); - - helper.changeInputValueTo('18'); - expect(inputElm).toBeInvalid(); - expect(inputElm.val()).toBe('18'); - expect($rootScope.value).toBeUndefined(); - expect($rootScope.form.alias.$error.step).toBeTruthy(); - - helper.changeInputValueTo('10'); - expect(inputElm).toBeValid(); - expect(inputElm.val()).toBe('10'); - expect($rootScope.value).toBe(10); - expect($rootScope.form.alias.$error.step).toBeFalsy(); - - $rootScope.$apply('value = 12'); - expect(inputElm).toBeInvalid(); - expect(inputElm.val()).toBe('12'); - expect($rootScope.value).toBe(12); - expect($rootScope.form.alias.$error.step).toBeTruthy(); - }); - - it('should validate even if the step value changes on-the-fly', function() { - $rootScope.step = 10; - var inputElm = helper.compileInput(''); - - helper.changeInputValueTo('10'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - - // Step changes, but value matches - $rootScope.$apply('step = 5'); - expect(inputElm.val()).toBe('10'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - expect($rootScope.form.alias.$error.step).toBeFalsy(); - - // Step changes, value does not match - $rootScope.$apply('step = 6'); - expect(inputElm).toBeInvalid(); - expect($rootScope.value).toBeUndefined(); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeTruthy(); - - // null = valid - $rootScope.$apply('step = null'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeFalsy(); - - // Step val as string - $rootScope.$apply('step = "7"'); - expect(inputElm).toBeInvalid(); - expect($rootScope.value).toBeUndefined(); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeTruthy(); - // unparsable string is ignored - $rootScope.$apply('step = "abc"'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeFalsy(); - }); - }); + forEach({ + step: 'step="{{step}}"', + ngStep: 'ng-step="step"' + }, function(attrHtml, attrName) { + describe(attrName, function() { - describe('ngStep', function() { - it('should validate', function() { - $rootScope.step = 10; - $rootScope.value = 20; - var inputElm = helper.compileInput(''); + it('should validate', function() { + $rootScope.step = 10; + $rootScope.value = 20; + var inputElm = helper.compileInput( + ''); - expect(inputElm.val()).toBe('20'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(20); - expect($rootScope.form.alias.$error.step).toBeFalsy(); + expect(inputElm.val()).toBe('20'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(20); + expect($rootScope.form.alias.$error.step).toBeFalsy(); - helper.changeInputValueTo('18'); - expect(inputElm).toBeInvalid(); - expect(inputElm.val()).toBe('18'); - expect($rootScope.value).toBeUndefined(); - expect($rootScope.form.alias.$error.step).toBeTruthy(); + helper.changeInputValueTo('18'); + expect(inputElm).toBeInvalid(); + expect(inputElm.val()).toBe('18'); + expect($rootScope.value).toBeUndefined(); + expect($rootScope.form.alias.$error.step).toBeTruthy(); - helper.changeInputValueTo('10'); - expect(inputElm).toBeValid(); - expect(inputElm.val()).toBe('10'); - expect($rootScope.value).toBe(10); - expect($rootScope.form.alias.$error.step).toBeFalsy(); + helper.changeInputValueTo('10'); + expect(inputElm).toBeValid(); + expect(inputElm.val()).toBe('10'); + expect($rootScope.value).toBe(10); + expect($rootScope.form.alias.$error.step).toBeFalsy(); - $rootScope.$apply('value = 12'); - expect(inputElm).toBeInvalid(); - expect(inputElm.val()).toBe('12'); - expect($rootScope.value).toBe(12); - expect($rootScope.form.alias.$error.step).toBeTruthy(); - }); + $rootScope.$apply('value = 12'); + expect(inputElm).toBeInvalid(); + expect(inputElm.val()).toBe('12'); + expect($rootScope.value).toBe(12); + expect($rootScope.form.alias.$error.step).toBeTruthy(); + }); - it('should validate even if the step value changes on-the-fly', function() { - $rootScope.step = 10; - var inputElm = helper.compileInput(''); + it('should validate even if the step value changes on-the-fly', function() { + $rootScope.step = 10; + var inputElm = helper.compileInput( + ''); - helper.changeInputValueTo('10'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); + helper.changeInputValueTo('10'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(10); - // Step changes, but value matches - $rootScope.$apply('step = 5'); - expect(inputElm.val()).toBe('10'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - expect($rootScope.form.alias.$error.step).toBeFalsy(); + // Step changes, but value matches + $rootScope.$apply('step = 5'); + expect(inputElm.val()).toBe('10'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(10); + expect($rootScope.form.alias.$error.step).toBeFalsy(); - // Step changes, value does not match - $rootScope.$apply('step = 6'); - expect(inputElm).toBeInvalid(); - expect($rootScope.value).toBeUndefined(); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeTruthy(); + // Step changes, value does not match + $rootScope.$apply('step = 6'); + expect(inputElm).toBeInvalid(); + expect($rootScope.value).toBeUndefined(); + expect(inputElm.val()).toBe('10'); + expect($rootScope.form.alias.$error.step).toBeTruthy(); - // null = valid - $rootScope.$apply('step = null'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeFalsy(); + // null = valid + $rootScope.$apply('step = null'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(10); + expect(inputElm.val()).toBe('10'); + expect($rootScope.form.alias.$error.step).toBeFalsy(); - // Step val as string - $rootScope.$apply('step = "7"'); - expect(inputElm).toBeInvalid(); - expect($rootScope.value).toBeUndefined(); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeTruthy(); + // Step val as string + $rootScope.$apply('step = "7"'); + expect(inputElm).toBeInvalid(); + expect($rootScope.value).toBeUndefined(); + expect(inputElm.val()).toBe('10'); + expect($rootScope.form.alias.$error.step).toBeTruthy(); - // unparsable string is ignored - $rootScope.$apply('step = "abc"'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(10); - expect(inputElm.val()).toBe('10'); - expect($rootScope.form.alias.$error.step).toBeFalsy(); + // unparsable string is ignored + $rootScope.$apply('step = "abc"'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(10); + expect(inputElm.val()).toBe('10'); + expect($rootScope.form.alias.$error.step).toBeFalsy(); + }); }); }); @@ -3001,7 +2935,6 @@ describe('input', function() { }); describe('range', function() { - var scope; var rangeTestEl = angular.element(''); @@ -3048,7 +2981,6 @@ describe('input', function() { expect(scope.age).toBe(50); expect(inputElm).toBeValid(); }); - } else { it('should reset the model if view is invalid', function() { @@ -3438,7 +3370,6 @@ describe('input', function() { expect(scope.value).toBe(40); }); }); - } @@ -3448,6 +3379,7 @@ describe('input', function() { // Browsers that implement range will never allow you to set a value that doesn't match the step value // However, currently only Firefox fully implements the spec when setting the value after the step value changes. // Other browsers fail in various edge cases, which is why they are not tested here. + it('should round the input value to the nearest step on user input', function() { var inputElm = helper.compileInput(''); @@ -3510,8 +3442,8 @@ describe('input', function() { expect(scope.value).toBe(10); expect(scope.form.alias.$error.step).toBeFalsy(); }); - } else { + it('should validate if "range" is not implemented', function() { scope.step = 10; scope.value = 20; From 70393950a6d31cc9cbf36ee82e4a70fb0741b006 Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Thu, 13 Oct 2016 19:59:23 +0300 Subject: [PATCH 2/5] fix(input): fix `step` validation for `input[number]`/`input[range]` Related to 9a8b8aa and #15257. Fixes the issue discussed in https://github.com/angular/angular.js/commit/9a8b8aa#commitcomment-19108436. Fixes #15257 --- src/ng/directive/input.js | 58 +++++++++++- test/ng/directive/inputSpec.js | 160 +++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+), 4 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 7e26ca16f6d1..b1a091fadd0a 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1529,13 +1529,62 @@ function parseNumberAttrVal(val) { return !isNumberNaN(val) ? val : undefined; } +function isNumberInteger(num) { + // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066 + // (minus the assumption that `num` is a number) + + // eslint-disable-next-line no-bitwise + return (num | 0) === num; +} + +function countDecimals(num) { + var numString = num.toString(); + var decimalSymbolIndex = numString.indexOf('.'); + + if (decimalSymbolIndex === -1) { + if (-1 < num && num < 1) { + // It may be in the exponentional notation format (`1e-X`) + var match = /e-(\d+)$/.exec(numString); + + if (match) { + return Number(match[1]); + } + } + + return 0; + } + + return numString.length - decimalSymbolIndex - 1; +} + +function isValidForStep(viewValue, stepBase, step) { + // At this point `stepBase` and `step` are expected to be non-NaN values + // and `viewValue` is expected to be a valid stringified number. + var value = Number(viewValue); + + // Due to limitations is Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or + // `0.5 % 0.1 !== 0`), we need to make sure all numbers are integers before proceeding. + if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) { + var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step)); + var multiplier = Math.pow(10, decimalCount); + + value = value * multiplier; + stepBase = stepBase * multiplier; + step = step * multiplier; + } + + return (value - stepBase) % step === 0; +} + function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { badInputChecker(scope, element, attr, ctrl); numberFormatterParser(ctrl); baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + var minVal; + var maxVal; + if (isDefined(attr.min) || attr.ngMin) { - var minVal; ctrl.$validators.min = function(value) { return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal; }; @@ -1548,7 +1597,6 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { } if (isDefined(attr.max) || attr.ngMax) { - var maxVal; ctrl.$validators.max = function(value) { return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal; }; @@ -1563,7 +1611,8 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { if (isDefined(attr.step) || attr.ngStep) { var stepVal; ctrl.$validators.step = function(modelValue, viewValue) { - return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || viewValue % stepVal === 0; + return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || + isValidForStep(viewValue, minVal || 0, stepVal); }; attr.$observe('step', function(val) { @@ -1633,7 +1682,8 @@ function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) { } : // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would function stepValidator(modelValue, viewValue) { - return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || viewValue % stepVal === 0; + return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || + isValidForStep(viewValue, minVal || 0, stepVal); }; setInitialValueAndObserver('step', stepChange); diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 9973c2411cd3..ee232959ddaf 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -2703,6 +2703,87 @@ describe('input', function() { expect(inputElm.val()).toBe('10'); expect($rootScope.form.alias.$error.step).toBeFalsy(); }); + + it('should use the correct "step base" when `[min]` is specified', function() { + $rootScope.min = 5; + $rootScope.step = 10; + $rootScope.value = 10; + var inputElm = helper.compileInput( + ''); + var ngModel = inputElm.controller('ngModel'); + + expect(inputElm.val()).toBe('10'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('15'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(15); + + $rootScope.$apply('step = 3'); + expect(inputElm.val()).toBe('15'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('8'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(8); + + $rootScope.$apply('min = 10; step = 20; value = 30'); + expect(inputElm.val()).toBe('30'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(30); + + $rootScope.$apply('min = 5'); + expect(inputElm.val()).toBe('30'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + $rootScope.$apply('step = 0.00000001'); + expect(inputElm.val()).toBe('30'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(30); + + // 0.3 - 0.2 === 0.09999999999999998 + $rootScope.$apply('min = 0.2; step = 0.09999999999999998; value = 0.3'); + expect(inputElm.val()).toBe('0.3'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + }); + + it('should correctly validate even in cases where `(x*y % x !== 0)`', function() { + $rootScope.step = 0.1; + var inputElm = helper.compileInput( + ''); + var ngModel = inputElm.controller('ngModel'); + + expect(inputElm.val()).toBe(''); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('0.3'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.3); + + helper.changeInputValueTo('2.9999999999999996'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + // 0.5 % 0.1 === 0.09999999999999998 + helper.changeInputValueTo('0.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.5); + + // 3.5 % 0.1 === 0.09999999999999981 + helper.changeInputValueTo('3.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(3.5); + }); }); }); @@ -3516,6 +3597,85 @@ describe('input', function() { expect(inputElm.val()).toBe('10'); expect(scope.form.alias.$error.step).toBeFalsy(); }); + + it('should use the correct "step base" when `[min]` is specified', function() { + $rootScope.min = 5; + $rootScope.step = 10; + $rootScope.value = 10; + var inputElm = helper.compileInput( + ''); + var ngModel = inputElm.controller('ngModel'); + + expect(inputElm.val()).toBe('10'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('15'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(15); + + $rootScope.$apply('step = 3'); + expect(inputElm.val()).toBe('15'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('8'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(8); + + $rootScope.$apply('min = 10; step = 20; value = 30'); + expect(inputElm.val()).toBe('30'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(30); + + $rootScope.$apply('min = 5'); + expect(inputElm.val()).toBe('30'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + $rootScope.$apply('step = 0.00000001'); + expect(inputElm.val()).toBe('30'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(30); + + // 0.3 - 0.2 === 0.09999999999999998 + $rootScope.$apply('min = 0.2; step = 0.09999999999999998; value = 0.3'); + expect(inputElm.val()).toBe('0.3'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + }); + + it('should correctly validate even in cases where `(x*y % x !== 0)`', function() { + var inputElm = helper.compileInput(''); + var ngModel = inputElm.controller('ngModel'); + + expect(inputElm.val()).toBe(''); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('0.3'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.3); + + helper.changeInputValueTo('2.9999999999999996'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + // 0.5 % 0.1 === 0.09999999999999998 + helper.changeInputValueTo('0.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.5); + + // 3.5 % 0.1 === 0.09999999999999981 + helper.changeInputValueTo('3.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(3.5); + }); } }); }); From 10870c84d52cfa899d3e8d8de98d9ed68383a472 Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Fri, 14 Oct 2016 10:43:58 +0300 Subject: [PATCH 3/5] fixup! fix(input): fix `step` validation for `input[number]`/`input[range]` --- src/ng/directive/input.js | 2 +- test/ng/directive/inputSpec.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index b1a091fadd0a..d01fc9735dd5 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1543,7 +1543,7 @@ function countDecimals(num) { if (decimalSymbolIndex === -1) { if (-1 < num && num < 1) { - // It may be in the exponentional notation format (`1e-X`) + // It may be in the exponential notation format (`1e-X`) var match = /e-(\d+)$/.exec(numString); if (match) { diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index ee232959ddaf..ab3e7817ac44 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -2731,7 +2731,8 @@ describe('input', function() { expect(inputElm).toBeValid(); expect($rootScope.value).toBe(8); - $rootScope.$apply('min = 10; step = 20; value = 30'); + $rootScope.$apply('min = 10; step = 20'); + helper.changeInputValueTo('30'); expect(inputElm.val()).toBe('30'); expect(inputElm).toBeValid(); expect($rootScope.value).toBe(30); @@ -2748,7 +2749,8 @@ describe('input', function() { expect($rootScope.value).toBe(30); // 0.3 - 0.2 === 0.09999999999999998 - $rootScope.$apply('min = 0.2; step = 0.09999999999999998; value = 0.3'); + $rootScope.$apply('min = 0.2; step = (0.3 - 0.2)'); + helper.changeInputValueTo('0.3'); expect(inputElm.val()).toBe('0.3'); expect(inputElm).toBeInvalid(); expect(ngModel.$error.step).toBe(true); From 0ecf8bdf09ca9a41c298fbfaa0473d42568ac355 Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Mon, 17 Oct 2016 15:05:19 +0300 Subject: [PATCH 4/5] fixup! fix(input): fix `step` validation for `input[number]`/`input[range]` --- src/ng/directive/input.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index d01fc9735dd5..4c9cdc360924 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1562,8 +1562,8 @@ function isValidForStep(viewValue, stepBase, step) { // and `viewValue` is expected to be a valid stringified number. var value = Number(viewValue); - // Due to limitations is Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or - // `0.5 % 0.1 !== 0`), we need to make sure all numbers are integers before proceeding. + // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or + // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers. if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) { var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step)); var multiplier = Math.pow(10, decimalCount); From 611b88c1974e048a0743a5b0a9b882be743bf5ee Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Mon, 17 Oct 2016 21:34:22 +0300 Subject: [PATCH 5/5] fixup! fix(input): fix `step` validation for `input[number]`/`input[range]` --- test/ng/directive/inputSpec.js | 116 +++++++++++++++++---------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index ab3e7817ac44..40ceff4ac879 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -2757,35 +2757,37 @@ describe('input', function() { expect($rootScope.value).toBeUndefined(); }); - it('should correctly validate even in cases where `(x*y % x !== 0)`', function() { - $rootScope.step = 0.1; - var inputElm = helper.compileInput( - ''); - var ngModel = inputElm.controller('ngModel'); - - expect(inputElm.val()).toBe(''); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBeUndefined(); - - helper.changeInputValueTo('0.3'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(0.3); - - helper.changeInputValueTo('2.9999999999999996'); - expect(inputElm).toBeInvalid(); - expect(ngModel.$error.step).toBe(true); - expect($rootScope.value).toBeUndefined(); - - // 0.5 % 0.1 === 0.09999999999999998 - helper.changeInputValueTo('0.5'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(0.5); - - // 3.5 % 0.1 === 0.09999999999999981 - helper.changeInputValueTo('3.5'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(3.5); - }); + it('should correctly validate even in cases where the JS floating point arithmetic fails', + function() { + $rootScope.step = 0.1; + var inputElm = helper.compileInput( + ''); + var ngModel = inputElm.controller('ngModel'); + + expect(inputElm.val()).toBe(''); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('0.3'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.3); + + helper.changeInputValueTo('2.9999999999999996'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + // 0.5 % 0.1 === 0.09999999999999998 + helper.changeInputValueTo('0.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.5); + + // 3.5 % 0.1 === 0.09999999999999981 + helper.changeInputValueTo('3.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(3.5); + } + ); }); }); @@ -3651,33 +3653,35 @@ describe('input', function() { expect($rootScope.value).toBeUndefined(); }); - it('should correctly validate even in cases where `(x*y % x !== 0)`', function() { - var inputElm = helper.compileInput(''); - var ngModel = inputElm.controller('ngModel'); - - expect(inputElm.val()).toBe(''); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBeUndefined(); - - helper.changeInputValueTo('0.3'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(0.3); - - helper.changeInputValueTo('2.9999999999999996'); - expect(inputElm).toBeInvalid(); - expect(ngModel.$error.step).toBe(true); - expect($rootScope.value).toBeUndefined(); - - // 0.5 % 0.1 === 0.09999999999999998 - helper.changeInputValueTo('0.5'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(0.5); - - // 3.5 % 0.1 === 0.09999999999999981 - helper.changeInputValueTo('3.5'); - expect(inputElm).toBeValid(); - expect($rootScope.value).toBe(3.5); - }); + it('should correctly validate even in cases where the JS floating point arithmetic fails', + function() { + var inputElm = helper.compileInput(''); + var ngModel = inputElm.controller('ngModel'); + + expect(inputElm.val()).toBe(''); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBeUndefined(); + + helper.changeInputValueTo('0.3'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.3); + + helper.changeInputValueTo('2.9999999999999996'); + expect(inputElm).toBeInvalid(); + expect(ngModel.$error.step).toBe(true); + expect($rootScope.value).toBeUndefined(); + + // 0.5 % 0.1 === 0.09999999999999998 + helper.changeInputValueTo('0.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(0.5); + + // 3.5 % 0.1 === 0.09999999999999981 + helper.changeInputValueTo('3.5'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(3.5); + } + ); } }); });