| var validator = { |
| |
| test_tooLong: function(ctl, data) { |
| var self = this; |
| test(function() { |
| self.pre_check(ctl, 'tooLong'); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.tooLong, |
| 'The validity.tooLong should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.tooLong, |
| 'The validity.tooLong should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_tooShort: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "tooShort"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.tooShort, |
| 'The validity.tooShort should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.tooShort, |
| 'The validity.tooShort should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_patternMismatch: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "patternMismatch"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.patternMismatch, |
| 'The validity.patternMismatch should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.patternMismatch, |
| 'The validity.patternMismatch should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_valueMissing: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "valueMissing"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.valueMissing, |
| 'The validity.valueMissing should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.valueMissing, |
| 'The validity.valueMissing should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_typeMismatch: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "typeMismatch"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.typeMismatch, |
| 'The validity.typeMismatch should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.typeMismatch, |
| 'The validity.typeMismatch should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_rangeOverflow: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "rangeOverflow"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.rangeOverflow, |
| 'The validity.rangeOverflow should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.rangeOverflow, |
| 'The validity.rangeOverflow should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_rangeUnderflow: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "rangeUnderflow"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.rangeUnderflow, |
| 'The validity.rangeUnderflow should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.rangeUnderflow, |
| 'The validity.rangeUnderflow should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_stepMismatch: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "stepMismatch"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.stepMismatch, |
| 'The validity.stepMismatch should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.stepMismatch, |
| 'The validity.stepMismatch should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_badInput: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "badInput"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.badInput, |
| 'The validity.badInput should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.badInput, |
| 'The validity.badInput should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_customError: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "customError"); |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) { |
| assert_true( |
| ctl.validity.customError, |
| 'The validity.customError attribute should be true' + condStr); |
| // validationMessage returns the empty string if ctl is barred from |
| // constraint validation, which happens if ctl is disabled or readOnly. |
| if (ctl.disabled || ctl.readOnly) { |
| assert_equals( |
| ctl.validationMessage, '', |
| 'The validationMessage attribute must be empty' + condStr); |
| } else { |
| assert_equals( |
| ctl.validationMessage, data.conditions.message, |
| 'The validationMessage attribute should be \'' + |
| data.conditions.message + '\'' + condStr); |
| } |
| } else { |
| assert_false( |
| ctl.validity.customError, |
| 'The validity.customError attribute should be false' + condStr); |
| assert_equals( |
| ctl.validationMessage, '', |
| 'The validationMessage attribute must be empty' + condStr); |
| } |
| }); |
| }, data.name); |
| }, |
| |
| test_isValid: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.iterate_over(ctl, data).forEach(function(val) { |
| const {ctl, expected, condStr} = val; |
| if (expected) |
| assert_true( |
| ctl.validity.valid, |
| 'The validity.valid should be true' + condStr); |
| else |
| assert_false( |
| ctl.validity.valid, |
| 'The validity.valid should be false' + condStr); |
| }); |
| }, data.name); |
| }, |
| |
| test_willValidate: function(ctl, data) { |
| var self = this; |
| test(function () { |
| self.pre_check(ctl, "willValidate"); |
| self.set_conditions(ctl, data.conditions); |
| if (data.ancestor) { |
| var dl = document.createElement("datalist"); |
| dl.appendChild(ctl); |
| } |
| |
| if (data.expected) |
| assert_true(ctl.willValidate, "The willValidate attribute should be true."); |
| else |
| assert_false(ctl.willValidate, "The willValidate attribute should be false."); |
| }, data.name); |
| }, |
| |
| test_checkValidity: function(ctl, data) { |
| var self = this; |
| test(function () { |
| var eventFired = false; |
| self.pre_check(ctl, "checkValidity"); |
| self.set_conditions(ctl, data.conditions); |
| if (data.dirty) |
| self.set_dirty(ctl); |
| |
| on_event(ctl, "invalid", function(e){ |
| assert_equals(e.type, "invalid", "The invalid event should be fired."); |
| eventFired = true; |
| }); |
| |
| if (data.expected) { |
| assert_true(ctl.checkValidity(), "The checkValidity method should be true."); |
| assert_false(eventFired, "The invalid event should not be fired."); |
| } else { |
| assert_false(ctl.checkValidity(), "The checkValidity method should be false."); |
| assert_true(eventFired, "The invalid event should be fired."); |
| } |
| }, data.name); |
| |
| test(function () { |
| var fm = document.createElement("form"); |
| var ctl2 = ctl.cloneNode(true); |
| |
| self.pre_check(ctl, "checkValidity"); |
| self.set_conditions(ctl2, data.conditions); |
| fm.appendChild(ctl2); |
| document.body.appendChild(fm); |
| if (data.dirty) |
| self.set_dirty(ctl2); |
| |
| var result = fm.checkValidity(); |
| document.body.removeChild(fm); |
| |
| if (data.expected) |
| assert_true(result, "The checkValidity method of the element's form owner should return true."); |
| else |
| assert_false(result, "The checkValidity method of the element's form owner should return false."); |
| }, data.name + " (in a form)"); |
| }, |
| |
| test_reportValidity: function(ctl, data) { |
| var self = this; |
| test(function () { |
| var eventFired = false; |
| |
| self.pre_check(ctl, "reportValidity"); |
| self.set_conditions(ctl, data.conditions); |
| if (data.dirty) |
| self.set_dirty(ctl); |
| |
| on_event(ctl, "invalid", function(e){ |
| assert_equals(e.type, "invalid", "The invalid event should be fired."); |
| eventFired = true; |
| }); |
| |
| if (data.expected) { |
| assert_true(ctl.reportValidity(), "The reportValidity method should be true."); |
| assert_false(eventFired, "The invalid event should not be fired."); |
| } else { |
| assert_false(ctl.reportValidity(), "The reportValidity method should be false."); |
| assert_true(eventFired, "The invalid event should be fired."); |
| } |
| }, data.name); |
| |
| test(function () { |
| var fm = document.createElement("form"); |
| var ctl2 = ctl.cloneNode(true); |
| |
| self.pre_check(ctl, "reportValidity"); |
| self.set_conditions(ctl2, data.conditions); |
| fm.appendChild(ctl2); |
| document.body.appendChild(fm); |
| if (data.dirty) |
| self.set_dirty(ctl2); |
| |
| var result = fm.reportValidity(); |
| document.body.removeChild(fm); |
| |
| if (data.expected) |
| assert_true(result, "The reportValidity method of the element's form owner should return true."); |
| else |
| assert_false(result, "The reportValidity method of the element's form owner should return false."); |
| }, data.name + " (in a form)"); |
| }, |
| |
| test_support_type: function(ctl, typ, testName) { |
| test(function () { |
| assert_equals(ctl.type, typ, "The " + typ + " type should be supported."); |
| }, testName); |
| }, |
| |
| set_conditions: function(ctl, obj) { |
| [ |
| "checked", |
| "disabled", |
| "max", |
| "maxlength", |
| "min", |
| "minlength", |
| "multiple", |
| "pattern", |
| "required", |
| "selected", |
| "step", |
| "value" |
| ].forEach(function(item) { |
| ctl.removeAttribute(item); |
| }); |
| for (var attr in obj) { |
| if (attr === "message") |
| ctl.setCustomValidity(obj[attr]); |
| else if (attr === "checked" || obj[attr] || obj[attr] === "") |
| ctl[attr] = obj[attr]; |
| } |
| }, |
| |
| set_dirty: function(ctl) { |
| ctl.focus(); |
| var old_value = ctl.value; |
| ctl.value = "a"; |
| ctl.value = old_value; |
| }, |
| |
| pre_check: function(ctl, item) { |
| switch (item) { |
| case "willValidate": |
| assert_true(item in ctl, "The " + item + " attribute doesn't exist."); |
| break; |
| case "checkValidity": |
| case "reportValidity": |
| assert_true(item in ctl, "The " + item + " method doesn't exist."); |
| break; |
| case "tooLong": |
| case "tooShort": |
| case "patternMismatch": |
| case "typeMismatch": |
| case "stepMismatch": |
| case "rangeOverflow": |
| case "rangeUnderflow": |
| case "valueMissing": |
| case "badInput": |
| case "valid": |
| assert_true("validity" in ctl, "The validity attribute doesn't exist."); |
| assert_true(item in ctl.validity, "The " + item + " attribute doesn't exist."); |
| break; |
| case "customError": |
| assert_true("validity" in ctl, "The validity attribute doesn't exist."); |
| assert_true("setCustomValidity" in ctl, "The validity attribute doesn't exist."); |
| assert_true("validationMessage" in ctl, "The validity attribute doesn't exist."); |
| assert_true(item in ctl.validity, "The " + item + " attribute doesn't exist."); |
| break; |
| } |
| }, |
| |
| iterate_over: function(ctl, data) { |
| // Iterate over normal, disabled, readonly, and both (if applicable). |
| var ctlNormal = ctl.cloneNode(true); |
| this.set_conditions(ctlNormal, data.conditions); |
| if (data.dirty) |
| this.set_dirty(ctlNormal); |
| |
| var ctlDisabled = ctl.cloneNode(true); |
| this.set_conditions(ctlDisabled, data.conditions); |
| if (data.dirty) |
| this.set_dirty(ctlDisabled); |
| ctlDisabled.disabled = true; |
| |
| var expectedImmutable = |
| data.expectedImmutable !== undefined ? data.expectedImmutable : data.expected; |
| |
| var variants = [ |
| {ctl: ctlNormal, expected: data.expected, condStr: '.'}, |
| {ctl: ctlDisabled, expected: expectedImmutable, condStr: ', when control is disabled.'}, |
| ]; |
| |
| if ('readOnly' in ctl) { |
| var ctlReadonly = ctl.cloneNode(true); |
| this.set_conditions(ctlReadonly, data.conditions); |
| if (data.dirty) |
| this.set_dirty(ctlReadonly); |
| ctlReadonly.readOnly = true; |
| |
| var ctlBoth = ctl.cloneNode(true); |
| this.set_conditions(ctlBoth, data.conditions); |
| if (data.dirty) |
| this.set_dirty(ctlBoth); |
| ctlBoth.disabled = true; |
| ctlBoth.readOnly = true; |
| |
| variants.push({ |
| ctl: ctlReadonly, |
| expected: expectedImmutable, |
| condStr: ', when control is readonly.' |
| }); |
| |
| variants.push({ |
| ctl: ctlBoth, |
| expected: expectedImmutable, |
| condStr: ', when control is disabled & readonly.' |
| }); |
| } |
| |
| return variants; |
| }, |
| |
| run_test: function(testee, method) { |
| var testMethod = "test_" + method; |
| if (typeof this[testMethod] !== "function") { |
| return false; |
| } |
| |
| var ele = null, |
| prefix = ""; |
| |
| for (var i = 0; i < testee.length; i++) { |
| if (testee[i].types.length > 0) { |
| for (var typ in testee[i].types) { |
| ele = document.createElement(testee[i].tag); |
| document.body.appendChild(ele); |
| try { |
| ele.type = testee[i].types[typ]; |
| } catch (e) { |
| //Do nothing, avoid the runtime error breaking the test |
| } |
| |
| prefix = "[" + testee[i].tag.toUpperCase() + " in " + testee[i].types[typ].toUpperCase() + " status] "; |
| if (ele.type != testee[i].types[typ]) { |
| this.test_support_type( |
| ele, |
| testee[i].types[typ], |
| prefix + "The " + testee[i].types[typ] + " type must be supported." |
| ); |
| continue; |
| } |
| |
| for (var j = 0; j < testee[i].testData.length; j++) { |
| testee[i].testData[j].name = testee[i].testData[j].name.replace(/\[.*\]\s/g, prefix); |
| this[testMethod](ele, testee[i].testData[j]); |
| } |
| } |
| } else { |
| ele = document.createElement(testee[i].tag); |
| document.body.appendChild(ele); |
| prefix = "[" + testee[i].tag + "] "; |
| |
| if (testElements[i].tag === "select") { |
| ele.add(new Option('test1', '')); // Placeholder |
| ele.add(new Option("test2", 1)); |
| } |
| |
| for (var item in testee[i].testData) { |
| testee[i].testData[item].name = testee[i].testData[item].name.replace("[target]", prefix); |
| this[testMethod](ele, testee[i].testData[item]); |
| } |
| } |
| } |
| } |
| } |