Repository: baianat/vee-validate (js)

Issue:
Infinite Update Loop for Unexpected Validation Rule Parameter
**Versions**

- vee-validate: 2.1.7
- vue: 2.6.6

**Describe the bug**
When using between validation rule with unexpected parameter (e.g.: `NaN`) and accessing `this.errors` VeeValidate gets the Vue app in an infinite loop and freezes the browser.

Generally I wouldn't pass `NaN` directly, but for more complex scenarios where the lower or upper bounds for a between rule come from a computed property and there is a bug when calculating this value then the parameter might be `NaN`. This happened to me as the lower bound was determined using `Math.max` and I didn't expand the array, i.e.: `Math.max([1, 2, 3])` returns `NaN` while `Math.max(...[1, 2, 3])` returns `3`. This can be easy to miss.

**To reproduce**
Steps to reproduce the behavior:
1. Define a form with an input with between rule (use object notation and pass `NaN` as the first parameter)
2. Register a method for handling the submit of the form and access `this.errors`
3. Submit the form
4. The browser freezes

**Expected behavior**
If a validation rule receives unexpected parameters it should end the validation promise in an error state so that I can chain a `catch` and log the error.

**Demo link**
https://jsfiddle.net/tjuzcmdh/2/ (check the console window)
The VeeValidate version used in the sample above is 2.1.6, I've tested 2.1.7 as well and the same problem happens with the latest version as well.

**Desktop:**
 - OS: Windows 10
 - Browser Chrome
 - Version 72.0.3626.109

Pull request description:
fix: added NaN check for directive render loops closes #1873
closes #1873

Patch:
diff --git a/src/utils/index.js b/src/utils/index.js
index 10b4fc0c..a90106b9 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -17,6 +17,15 @@ export const isDateInput = (el: HTMLInputElement) => {
  */
 export const getDataAttribute = (el: HTMLElement, name: string) => el.getAttribute(`data-vv-${name}`);
 
+export const isNaN = (value: any) => {
+  if ('isNaN' in Number) {
+    return Number.isNaN(value);
+  }
+
+  // eslint-disable-next-line
+  return value === value;
+};
+
 /**
  * Checks if the values are either null or undefined.
  */
@@ -76,6 +85,10 @@ export const isEqual = (lhs: any, rhs: any): boolean => {
     });
   }
 
+  if (isNaN(lhs) && isNaN(rhs)) {
+    return true;
+  }
+
   return lhs === rhs;
 };
 


Test patch:
diff --git a/tests/unit/utils.js b/tests/unit/utils.js
index 50306751..2d79d7b4 100644
--- a/tests/unit/utils.js
+++ b/tests/unit/utils.js
@@ -372,6 +372,8 @@ test('compares two values', () => {
   expect(utils.isEqual([1, 2, 3], [1, 2, 3])).toBe(true);
   expect(utils.isEqual([1, 2, 3], [1, 2])).toBe(false);
   expect(utils.isEqual([1, 2, 3], [1, 2, '3'])).toBe(false);
+
+  expect(utils.isEqual(NaN, NaN)).toBe(true);
 });
 
 test('formats file sizes', () => {