UNPKG

hyperform

Version:

Capture form validation back from the browser

411 lines (323 loc) 12 kB
function regressions_make_hform(_doc, settings) { _doc = _doc || document; settings = settings || {}; var form = _doc.createElement('form'); form.innerHTML = '<input name="test" value="button_span">'+ '<button><span>submit</span></button>'; var hform = _doc.defaultView.hyperform(form, settings); _doc.body.appendChild(form); return hform; } function destroy_hform(hform) { if (hform.form && hform.form.parentNode) { hform.form.parentNode.removeChild(hform.form); } hform.destroy(); } function once(element, event, handler) { var func = function(evt) { element.removeEventListener(event, func); handler(evt); }; element.addEventListener(event, func); } describe('Issue 7', function() { it('should publish validation methods on HTMLFormElements', function() { var hform = regressions_make_hform(); var form = hform.form; if (! ('reportValidity' in form)) { throw Error('no reportValidity method found'); } destroy_hform(hform); }); }); describe('Issue 11', function() { it('should fire a cancelable submit event', function(done) { // revalidate:never was part of the original issue report var hform = regressions_make_hform(document, { revalidate: 'never' }); var form = hform.form; form.addEventListener('submit', function(evt) { if (! evt.submittedVia || evt.submittedVia.nodeName !== 'BUTTON') { throw Error('not a Hyperform submit event'); } evt.preventDefault(); destroy_hform(hform); done(); }); form.querySelector('button').click(); }); }); describe('Issue 13', function() { it('should add name=value of submit button', function(done) { /* we're taking a deviation here by creating the form in an iframe, so * we can submit the form and check that the button's name=value is * really there. */ var iframe = document.createElement('iframe'); iframe.src = 'blank.html'; document.body.appendChild(iframe); once(iframe.contentWindow, 'load', function() { var hform = regressions_make_hform(iframe.contentDocument); var form = hform.form; form.method = 'get'; form.addEventListener('submit', function(evt) { if (! evt.submittedVia || evt.submittedVia.nodeName !== 'BUTTON') { throw Error('not a Hyperform submit event'); } }); var button = form.querySelector('button'); button.name = 'test'; button.value = 'value'; form.parentNode.removeChild(form); iframe.contentDocument.body.appendChild(form); form.action = '#'; setTimeout(function(){ once(iframe, 'load', function() { if (iframe.contentWindow.location.search.search(/test=value/) === -1) { throw Error('test value not found'); } iframe.parentNode.removeChild(iframe); done(); }); button.click(); }, 100); }); }); }); describe('Issue 34', function() { it('should catch submit when clicking on span nested in button', function(done) { var hform = regressions_make_hform(); var form = hform.form; form.addEventListener('submit', function(evt) { evt.preventDefault(); if (! evt.submittedVia || evt.submittedVia.nodeName !== 'BUTTON') { throw Error('not a Hyperform submit event'); } destroy_hform(hform); done(); }); form.querySelector('button span').click(); }); }); describe('Issue 35', function() { it('should work in IE <= 10 when called on non-window', function() { // see https://github.com/hyperform/hyperform/issues/35#issuecomment-264213879 hyperform(document).destroy(); }); }); describe('Issue 41', function() { /* IE has no document.currentScript, and apparently it can't be polyfilled * in IE 11 anyway. */ if (navigator.userAgent.search('Trident') === -1) { it('should autoload when requested', function(done) { var iframe = document.createElement('iframe'); iframe.src = 'blank.html'; document.body.appendChild(iframe); once(iframe.contentWindow, 'load', function() { var el = iframe.contentDocument.createElement('script'); el.src = '../../dist/hyperform.js'; el.setAttribute('data-hf-autoload', ''); el.addEventListener('load', function() { if (! iframe.contentWindow.HTMLInputElement.prototype.checkValidity.__hyperform) { throw Error('no original checkValidity method detected'); } iframe.parentNode.removeChild(iframe); done(); }); iframe.contentDocument.body.appendChild(el); }); }); } it('should not autoload when not requested', function(done) { var iframe = document.createElement('iframe'); iframe.src = 'blank.html'; document.body.appendChild(iframe); once(iframe.contentWindow, 'load', function() { var el = iframe.contentDocument.createElement('script'); el.src = '../../dist/hyperform.js'; iframe.contentDocument.body.appendChild(el); el.addEventListener('load', function() { if ('_original_checkValidity' in iframe.contentWindow.HTMLFormElement) { throw Error('overwritten checkValidity method detected'); } iframe.parentNode.removeChild(iframe); done(); }); }); }); }); describe('Issue 45', function() { it('should use the minlength value in the "tooShort" warning string', function() { var hform = regressions_make_hform(); var form = hform.form; var input = form.getElementsByTagName('input')[0]; input.setAttribute('minlength', '3'); input.setAttribute('maxlength', '5'); input.value = 'ab'; input.checkValidity(); if (input.validationMessage.search('5') > -1) { throw Error('validation message uses maxlength value: '+ input.validationMessage); } if (input.validationMessage.search('3') === -1 && input.validationMessage.search('2') === -1) { throw Error('validation message does not reference values: '+ input.validationMessage); } destroy_hform(hform); }); }); describe('Issue 49', function() { it('should detect an invalid date when called on non-window', function() { var form = document.createElement('form'); var input = document.createElement('input'); input.name = 'test'; input.type = 'date'; form.appendChild(input); document.body.appendChild(form); var hform = hyperform(form); values = ['abc', '01.01.2000', '2000-01', '2000-13-32']; for (var i = 0; i < values.length; i++) { input.value = values[i]; if (input.value && ! input.validity.badInput) { throw Error(values[i]+' should not be a valid date'); } } hform.destroy(); document.body.removeChild(form); }); /* TODO we should not only test setting input.value but actually entering * values. However, that's behind the input's shadow DOM where we cannot * access fields. The test above is trivially true, but we need to make * sure, that manually entered wrong values result in a badInput. */ }); describe('Issue 69', function() { it('should check, if a required <select> option is not in fact disabled', function() { var form = document.createElement('form'); var select = document.createElement('select'); select.innerHTML = '<option>another</option><option selected disabled>select another</option>'; select.required = true; form.appendChild(select); document.body.appendChild(form); var hform = hyperform(form); if (! select.validity.valueMissing) { throw Error('select has no submittable option selected'); } hform.destroy(); document.body.removeChild(form); }); }); describe('Issue 78', function() { it('should not run validation when tabbing into an element', function() { var hform = regressions_make_hform(document, { revalidate: 'oninput' }); var validated = false; hyperform.addValidator(hform.form.elements[0], function() { validated = true; }); hform.form.elements[0].focus(); var e = document.createEvent('HTMLEvents'); e.keyCode = 9; e.initEvent('keyup', true, true); hform.form.elements[0].dispatchEvent(e); if (validated) { throw Error('should not have validated on tab'); } var e = document.createEvent('HTMLEvents'); e.keyCode = 65; e.initEvent('keyup', true, true); hform.form.elements[0].dispatchEvent(e); if (! validated) { throw Error('should have validated on other keyCode'); } hform.destroy(); document.body.removeChild(hform.form); }); }); describe('Issue 85', function() { it('should fail validation, when the placeholder option is selected', function() { var form = document.createElement('form'); var select = document.createElement('select'); select.innerHTML = '<option value="">select another</option><option>another</option><option value="">really empty!</option>'; select.required = true; form.appendChild(select); document.body.appendChild(form); var hform = hyperform(form); if (! select.validity.valueMissing) { throw Error('select has no submittable option selected'); } select.options[2].selected = true; if (select.validity.valueMissing) { throw Error('an empty option that is not the placeholder option should be permissible.'); } select.options[0].selected = true; if (! select.validity.valueMissing) { throw Error('the placeholder option is not permissible.'); } destroy_hform(hform); }); }); describe('Issue 86', function() { it('should work on arbitrary elements as root', function(done) { var div = document.createElement('div'); function mkform() { var form = document.createElement('form'); var input = document.createElement('input'); input.setAttribute('name', 'foo'); input.setAttribute('required', 'required'); form.appendChild(input); div.appendChild(form); return form; } function check(form, label) { var input = form.getElementsByTagName('input')[0]; input.className.replace('hf-validated', ''); input.reportValidity(); if (input.className.search('hf-validated') === -1) { throw Error(label+' form not validated.'); } } var first_form = mkform(); document.body.appendChild(div); var hform = hyperform(div); check(first_form, 'existing'); var second_form = mkform(); /* mutation observers work asynchronously. We need to delay the test * therefore. */ window.requestAnimationFrame(function() { check(second_form, 'added'); div.removeChild(second_form); window.requestAnimationFrame(function() { div.appendChild(second_form); window.requestAnimationFrame(function() { check(second_form, 're-attached'); hform.destroy(); document.body.removeChild(div); done(); }); }); }); }); }); describe('Issue 87', function() { it('should not validate elements of a form@novalidate', function() { var hform = regressions_make_hform(); var form = hform.form; form.setAttribute('novalidate', ''); var input = form.getElementsByTagName('input')[0]; input.setAttribute('minlength', '3'); input.value = 'ab'; if (input.validity.valid) { throw Error('elements inside a form@novalidate should be validated, if explicitly requested'); } input.addEventListener('invalid', function(event) { throw Error('elements inside a form@novalidate should not be validated on submit'); }); form.addEventListener('submit', function(event) { event.preventDefault(); }); form.elements[0].click(); form.elements[0].focus(); form.elements[0].blur(); form.elements[1].click(); destroy_hform(hform); }); });